diff --git a/DEVELOPMENT b/DEVELOPMENT deleted file mode 100644 index e69de29b..00000000 diff --git a/index.js b/index.js index 951b2196..8cf8d1c3 100644 --- a/index.js +++ b/index.js @@ -1,70 +1,80 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -/* eslint-disable rulesdir/no-commonjs */ +var _fs = _interopRequireDefault(require('fs')); + +var _path = _interopRequireDefault(require('path')); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _FeatureLoader; + +function _load_FeatureLoader() { + return _FeatureLoader = _interopRequireDefault(require('nuclide-commons-atom/FeatureLoader')); +} + +var _displayNuclideWarning; + +function _load_displayNuclideWarning() { + return _displayNuclideWarning = _interopRequireDefault(require('./display-nuclide-warning')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -import fs from 'fs'; // eslint-disable-next-line rulesdir/prefer-nuclide-uri -import path from 'path'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import FeatureLoader from 'nuclide-commons-atom/FeatureLoader'; -import displayNuclideWarning from './display-nuclide-warning'; +const featureDir = _path.default.join(__dirname, 'modules/atom-ide-ui/pkg'); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -const featureDir = path.join(__dirname, 'modules/atom-ide-ui/pkg'); -const features = fs - .readdirSync(featureDir) - .map(item => { - const dirname = path.join(featureDir, item); - try { - const pkgJson = fs.readFileSync( - path.join(dirname, 'package.json'), - 'utf8', - ); - return { - path: dirname, - pkg: JSON.parse(pkgJson), - }; - } catch (err) { - if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { - throw err; - } +/* eslint-disable rulesdir/no-commonjs */ + +const features = _fs.default.readdirSync(featureDir).map(item => { + const dirname = _path.default.join(featureDir, item); + try { + const pkgJson = _fs.default.readFileSync(_path.default.join(dirname, 'package.json'), 'utf8'); + return { + path: dirname, + pkg: JSON.parse(pkgJson) + }; + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; } - }) - .filter(Boolean); + } +}).filter(Boolean); /** * Use a unified package loader to load all the feature packages. * See the following post for more context: * https://nuclide.io/blog/2016/01/13/Nuclide-v0.111.0-The-Unified-Package/ */ -let disposables: ?UniversalDisposable; -const featureLoader = new FeatureLoader({ +let disposables; +const featureLoader = new (_FeatureLoader || _load_FeatureLoader()).default({ path: __dirname, config: {}, - features, + features }); featureLoader.load(); module.exports = { config: featureLoader.getConfig(), activate() { - disposables = new UniversalDisposable( - require('nuclide-commons-ui'), - atom.packages.onDidActivatePackage(pkg => { - if (pkg.name === 'nuclide') { - displayNuclideWarning(); - } - }), - ); + disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(require('nuclide-commons-ui'), atom.packages.onDidActivatePackage(pkg => { + if (pkg.name === 'nuclide') { + (0, (_displayNuclideWarning || _load_displayNuclideWarning()).default)(); + } + })); featureLoader.activate(); }, deactivate() { @@ -76,5 +86,5 @@ module.exports = { }, serialize() { featureLoader.serialize(); - }, -}; + } +}; \ No newline at end of file diff --git a/modules/atom-ide-ui/index.js b/modules/atom-ide-ui/index.js index 033345ae..a726efc4 100644 --- a/modules/atom-ide-ui/index.js +++ b/modules/atom-ide-ui/index.js @@ -1,112 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -export type { - BusySignalOptions, - BusySignalService, -} from './pkg/atom-ide-busy-signal/lib/types'; - -export type { - CodeAction, - CodeActionProvider, -} from './pkg/atom-ide-code-actions/lib/types'; - -export type { - CodeFormatProvider, - RangeCodeFormatProvider, - FileCodeFormatProvider, - OnTypeCodeFormatProvider, - OnSaveCodeFormatProvider, -} from './pkg/atom-ide-code-format/lib/types'; - -export type { - CodeHighlightProvider, -} from './pkg/atom-ide-code-highlight/lib/types'; - -export type { - Datatip, - DatatipProvider, - DatatipService, - MarkedString, - ModifierDatatipProvider, - ModifierKey, -} from './pkg/atom-ide-datatip/lib/types'; - -export type { - Definition, - DefinitionProvider, - DefinitionPreviewProvider, - DefinitionQueryResult, -} from './pkg/atom-ide-definitions/lib/types'; - -export type { - CallbackDiagnosticProvider, - DiagnosticFix, - DiagnosticInvalidationCallback, - DiagnosticInvalidationMessage, - DiagnosticMessage, - DiagnosticMessages, - DiagnosticMessageKind, - DiagnosticMessageType, - DiagnosticProvider, - DiagnosticProviderUpdate, - DiagnosticTrace, - DiagnosticUpdateCallback, - IndieLinterDelegate, - LinterMessage, - LinterMessageV1, - LinterMessageV2, - LinterProvider, - LinterTrace, - ObservableDiagnosticProvider, - RegisterIndieLinter, -} from './pkg/atom-ide-diagnostics/lib/types'; - -export type { - FindReferencesProvider, - FindReferencesReturn, - Reference, -} from './pkg/atom-ide-find-references/lib/types'; - -export type { - Outline, - OutlineProvider, - OutlineTree, - ResultsStreamProvider, -} from './pkg/atom-ide-outline-view/lib/types'; - -export type { - Signature, - SignatureHelp, - SignatureHelpProvider, - SignatureParameter, -} from './pkg/atom-ide-signature-help/lib/types'; - -export type { - HyperclickProvider, - HyperclickSuggestion, -} from './pkg/hyperclick/lib/types'; - -export type { - ConsoleService, - ConsoleApi, - Level as ConsoleLevel, - Message as ConsoleMessage, - SourceInfo as ConsoleSourceInfo, - OutputProviderStatus, -} from './pkg/atom-ide-console/lib/types'; - -// Deprecated console types. Exported only for legacy users. -export type { - OutputService, - RegisterExecutorFunction, -} from './pkg/atom-ide-console/lib/types'; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusyMessageInstance.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusyMessageInstance.js index cec5474a..edf2de1e 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusyMessageInstance.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusyMessageInstance.js @@ -1,41 +1,29 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {BusyMessage} from './types'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.BusyMessageInstance = undefined; -import invariant from 'assert'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; +var _UniversalDisposable; -export class BusyMessageInstance { - // These things are set at construction-time: - _publishCallback: () => void; - _creationOrder: number; - _waitingFor: 'computer' | 'user'; - _onDidClick: ?() => void; - _disposables: UniversalDisposable; - _titleElement: HTMLElement = document.createElement('span'); +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +class BusyMessageInstance { // These things might be modified afterwards: - _currentTitle: ?string = null; - _isVisibleForDebounce: boolean = true; - _isVisibleForFile: boolean = true; - _revealTooltip: boolean = false; - - constructor( - publishCallback: () => void, - creationOrder: number, - waitingFor: 'computer' | 'user', - onDidClick: ?() => void, - disposables: UniversalDisposable, - ) { + + // These things are set at construction-time: + constructor(publishCallback, creationOrder, waitingFor, onDidClick, disposables) { + this._titleElement = document.createElement('span'); + this._currentTitle = null; + this._isVisibleForDebounce = true; + this._isVisibleForFile = true; + this._revealTooltip = false; + this._publishCallback = publishCallback; this._creationOrder = creationOrder; this._waitingFor = waitingFor; @@ -43,12 +31,15 @@ export class BusyMessageInstance { this._disposables = disposables; } - get waitingFor(): 'computer' | 'user' { + get waitingFor() { return this._waitingFor; } - setTitle(val: string): void { - invariant(!this._disposables.disposed); + setTitle(val) { + if (!!this._disposables.disposed) { + throw new Error('Invariant violation: "!this._disposables.disposed"'); + } + if (this._currentTitle === val) { return; } @@ -69,49 +60,66 @@ export class BusyMessageInstance { } } - getTitleElement(): ?HTMLElement { + getTitleElement() { return this._titleElement; } - setIsVisibleForDebounce(val: boolean): void { - invariant(!this._disposables.disposed); + setIsVisibleForDebounce(val) { + if (!!this._disposables.disposed) { + throw new Error('Invariant violation: "!this._disposables.disposed"'); + } + this._isVisibleForDebounce = val; this._publishCallback(); } - setIsVisibleForFile(val: boolean): void { - invariant(!this._disposables.disposed); + setIsVisibleForFile(val) { + if (!!this._disposables.disposed) { + throw new Error('Invariant violation: "!this._disposables.disposed"'); + } + this._isVisibleForFile = val; this._publishCallback(); } - isVisible(): boolean { - invariant(!this._disposables.disposed); - return ( - this._isVisibleForFile && - this._isVisibleForDebounce && - this._currentTitle != null - ); + isVisible() { + if (!!this._disposables.disposed) { + throw new Error('Invariant violation: "!this._disposables.disposed"'); + } + + return this._isVisibleForFile && this._isVisibleForDebounce && this._currentTitle != null; } - setRevealTooltip(val: boolean): void { + setRevealTooltip(val) { this._revealTooltip = val; } - shouldRevealTooltip(): boolean { + shouldRevealTooltip() { return this._revealTooltip; } - compare(that: BusyMessageInstance): number { + compare(that) { return this._creationOrder - that._creationOrder; } - dispose(): void { + dispose() { this._disposables.dispose(); this._currentTitle = null; this._publishCallback(); } } -// This is how we declare that a type fulfills an interface in Flow: -(((null: any): BusyMessageInstance): BusyMessage); +exports.BusyMessageInstance = BusyMessageInstance; // This is how we declare that a type fulfills an interface in Flow: +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +null; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusySignalSingleton.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusySignalSingleton.js index a736a344..f3baef31 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusySignalSingleton.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/BusySignalSingleton.js @@ -1,3 +1,13 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,23 +16,19 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {BusySignalOptions, BusyMessage} from './types'; -import type {MessageStore} from './MessageStore'; - -export default class BusySignalSingleton { - _messageStore: MessageStore; +class BusySignalSingleton { - constructor(messageStore: MessageStore) { + constructor(messageStore) { this._messageStore = messageStore; } dispose() {} - reportBusy(title: string, options?: BusySignalOptions): BusyMessage { + reportBusy(title, options) { return this._messageStore.add(title, options || {}); } @@ -33,16 +39,17 @@ export default class BusySignalSingleton { * Used to indicate that some work is ongoing while the given asynchronous * function executes. */ - async reportBusyWhile( - title: string, - f: () => Promise, - options?: BusySignalOptions, - ): Promise { - const busySignal = this.reportBusy(title, options); - try { - return await f(); - } finally { - busySignal.dispose(); - } + reportBusyWhile(title, f, options) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + const busySignal = _this.reportBusy(title, options); + try { + return yield f(); + } finally { + busySignal.dispose(); + } + })(); } } +exports.default = BusySignalSingleton; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/MessageStore.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/MessageStore.js index 7a54f563..12c4966c 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/MessageStore.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/MessageStore.js @@ -1,3 +1,36 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.MessageStore = undefined; + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _BusyMessageInstance; + +function _load_BusyMessageInstance() { + return _BusyMessageInstance = require('./BusyMessageInstance'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// The "busy debounce delay" is for busy messages that were created with the +// 'debounce' option set to true. The icon and tooltip message won't appear +// until this many milliseconds have elapsed; if the busy message gets disposed +// before this time, then the user won't see anything. /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,100 +39,87 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {BusyMessage, BusySignalOptions} from './types'; - -import invariant from 'assert'; -import {Observable, BehaviorSubject} from 'rxjs'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {arrayEqual} from 'nuclide-commons/collection'; -import {BusyMessageInstance} from './BusyMessageInstance'; - -// The "busy debounce delay" is for busy messages that were created with the -// 'debounce' option set to true. The icon and tooltip message won't appear -// until this many milliseconds have elapsed; if the busy message gets disposed -// before this time, then the user won't see anything. const BUSY_DEBOUNCE_DELAY = 300; -export class MessageStore { - _counter: number = 0; - _messages: Set = new Set(); - _currentVisibleMessages: Array = []; - _messageStream: BehaviorSubject< - Array, - > = new BehaviorSubject([]); +class MessageStore { + constructor() { + this._counter = 0; + this._messages = new Set(); + this._currentVisibleMessages = []; + this._messageStream = new _rxjsBundlesRxMinJs.BehaviorSubject([]); + } - getMessageStream(): Observable> { + getMessageStream() { return this._messageStream; } - dispose(): void { + dispose() { const messagesToDispose = [...this._messages]; for (const message of messagesToDispose) { message.dispose(); } - invariant(this._messages.size === 0); + + if (!(this._messages.size === 0)) { + throw new Error('Invariant violation: "this._messages.size === 0"'); + } + this._messageStream.complete(); } - _publish(): void { - const visibleMessages = [...this._messages] - .filter(m => m.isVisible()) - .sort((m1, m2) => m1.compare(m2)); + _publish() { + const visibleMessages = [...this._messages].filter(m => m.isVisible()).sort((m1, m2) => m1.compare(m2)); // We only send out on messageStream when the list of visible // BusyMessageInstance object identities has changed, e.g. when ones // are made visible or invisible or new ones are created. We don't send // out just on title change. - if (!arrayEqual(this._currentVisibleMessages, visibleMessages)) { + if (!(0, (_collection || _load_collection()).arrayEqual)(this._currentVisibleMessages, visibleMessages)) { this._messageStream.next(visibleMessages); this._currentVisibleMessages = visibleMessages; } } - add(title: string, options: BusySignalOptions): BusyMessage { + add(title, options) { this._counter++; const creationOrder = this._counter; - const waitingFor = - options != null && options.waitingFor != null - ? options.waitingFor - : 'computer'; + const waitingFor = options != null && options.waitingFor != null ? options.waitingFor : 'computer'; const onDidClick = options == null ? null : options.onDidClick; - const messageDisposables = new UniversalDisposable(); - - const message = new BusyMessageInstance( - this._publish.bind(this), - creationOrder, - waitingFor, - onDidClick, - messageDisposables, - ); + const messageDisposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(); + + const message = new (_BusyMessageInstance || _load_BusyMessageInstance()).BusyMessageInstance(this._publish.bind(this), creationOrder, waitingFor, onDidClick, messageDisposables); this._messages.add(message); messageDisposables.add(() => this._messages.delete(message)); // debounce defaults 'true' for busy-signal, and 'false' for action-required - const debounceRaw: ?boolean = options == null ? null : options.debounce; - const debounce: boolean = - debounceRaw == null ? waitingFor === 'computer' : debounceRaw; + const debounceRaw = options == null ? null : options.debounce; + const debounce = debounceRaw == null ? waitingFor === 'computer' : debounceRaw; if (debounce) { message.setIsVisibleForDebounce(false); // After the debounce time, we'll check whether the messageId is still // around (i.e. hasn't yet been disposed), and if so we'll display it. - let timeoutId = ((0: any): TimeoutID); + let timeoutId = 0; const teardown = () => clearTimeout(timeoutId); timeoutId = setTimeout(() => { - invariant(!messageDisposables.disposed); - invariant(this._messages.has(message)); + if (!!messageDisposables.disposed) { + throw new Error('Invariant violation: "!messageDisposables.disposed"'); + } + + if (!this._messages.has(message)) { + throw new Error('Invariant violation: "this._messages.has(message)"'); + } // If the message was disposed, then it should have already called // clearTimeout, so this timeout handler shouldn't have been invoked. // And also the message should have been removed from this._messages. // So both tests above should necessary fail. // If the messageStore was disposed, then every message in it should // already have been disposed, as per above. + + messageDisposables.remove(teardown); message.setIsVisibleForDebounce(true); }, BUSY_DEBOUNCE_DELAY); @@ -110,10 +130,7 @@ export class MessageStore { message.setIsVisibleForFile(false); const file = options.onlyForFile; const teardown = atom.workspace.observeActivePaneItem(item => { - const activePane = - item != null && typeof item.getPath === 'function' - ? String(item.getPath()) - : null; + const activePane = item != null && typeof item.getPath === 'function' ? String(item.getPath()) : null; const newVisible = activePane === file; message.setIsVisibleForFile(newVisible); }); @@ -133,3 +150,4 @@ export class MessageStore { return message; } } +exports.MessageStore = MessageStore; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/StatusBarTile.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/StatusBarTile.js index 5c5aafc5..4ab78c61 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/StatusBarTile.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/StatusBarTile.js @@ -1,3 +1,43 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _Icon; + +function _load_Icon() { + return _Icon = require('nuclide-commons-ui/Icon'); +} + +var _BusyMessageInstance; + +function _load_BusyMessageInstance() { + return _BusyMessageInstance = require('./BusyMessageInstance'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// We want to be the furthest left on the right side of the status bar so as not to leave a +// conspicuous gap (or cause jitter) when nothing is busy. /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,70 +46,47 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {Observable} from 'rxjs'; - -import invariant from 'assert'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {arrayCompact} from 'nuclide-commons/collection'; -import {Icon} from 'nuclide-commons-ui/Icon'; -import {BusyMessageInstance} from './BusyMessageInstance'; - -// We want to be the furthest left on the right side of the status bar so as not to leave a -// conspicuous gap (or cause jitter) when nothing is busy. const STATUS_BAR_PRIORITY = 1000; -type Props = { - waitingForComputer: boolean, - waitingForUser: boolean, - onDidClick: ?() => void, -}; - -function StatusBarTileComponent(props: Props) { +function StatusBarTileComponent(props) { let element; if (props.waitingForUser) { - element = ; + element = _react.createElement((_Icon || _load_Icon()).Icon, { className: 'busy-signal-status-bar', icon: 'unverified' }); } else if (props.waitingForComputer) { - element =
; + element = _react.createElement('div', { className: 'busy-signal-status-bar loading-spinner-tiny' }); } else { element = null; } if (props.onDidClick != null) { - element = {element}; + element = _react.createElement( + 'a', + { onClick: props.onDidClick }, + element + ); } return element; } -export default class StatusBarTile { - _item: HTMLElement; - _tile: atom$StatusBarTile; - _tooltip: ?IDisposable; - _disposables: UniversalDisposable; - _messages: Array = []; - _isMouseOverItem: boolean = false; - _isMouseOverTooltip: number = 0; - _leaveTimeoutId: ?TimeoutID; - - constructor( - statusBar: atom$StatusBar, - messageStream: Observable>, - ) { +class StatusBarTile { + + constructor(statusBar, messageStream) { + this._messages = []; + this._isMouseOverItem = false; + this._isMouseOverTooltip = 0; + this._item = document.createElement('div'); this._tile = this._createTile(statusBar); - this._disposables = new UniversalDisposable( - messageStream.subscribe(messages => this._handleMessages(messages)), - ); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(messageStream.subscribe(messages => this._handleMessages(messages))); } - dispose(): void { - ReactDOM.unmountComponentAtNode(this._item); + dispose() { + _reactDom.default.unmountComponentAtNode(this._item); this._tile.destroy(); if (this._tooltip != null) { this._tooltip.dispose(); @@ -77,7 +94,7 @@ export default class StatusBarTile { this._disposables.dispose(); } - _createTile(statusBar: atom$StatusBar): atom$StatusBarTile { + _createTile(statusBar) { const item = this._item; item.className = 'inline-block'; item.addEventListener('mouseenter', () => { @@ -91,29 +108,24 @@ export default class StatusBarTile { }); const tile = statusBar.addRightTile({ item, - priority: STATUS_BAR_PRIORITY, + priority: STATUS_BAR_PRIORITY }); return tile; } - _handleMessages(messages: Array): void { + _handleMessages(messages) { this._messages = messages; - const onDidClicks = arrayCompact(messages.map(m => m._onDidClick)); + const onDidClicks = (0, (_collection || _load_collection()).arrayCompact)(messages.map(m => m._onDidClick)); - const props: Props = { + const props = { waitingForComputer: messages.some(m => m.waitingFor === 'computer'), waitingForUser: messages.some(m => m.waitingFor === 'user'), - onDidClick: - onDidClicks.length > 0 - ? () => onDidClicks.forEach(callback => callback()) - : null, + onDidClick: onDidClicks.length > 0 ? () => onDidClicks.forEach(callback => callback()) : null }; - ReactDOM.render(, this._item); + _reactDom.default.render(_react.createElement(StatusBarTileComponent, props), this._item); - const revealTooltip = messages.some(message => - message.shouldRevealTooltip(), - ); + const revealTooltip = messages.some(message => message.shouldRevealTooltip()); if (this._tooltip != null) { // If the user already had the tooltip up, then we'll either // refresh it or hide it. No matter what, we'll have to unmount it. @@ -121,10 +133,7 @@ export default class StatusBarTile { // There are two reasons to refresh the tooltip (bringing it back): // 1) the mouse was previously over the tile or the tooltip // 2) one of the messages is marked with 'reveal tooltip' - if ( - messages.length > 0 && - (revealTooltip || this._isMouseOverItem || this._isMouseOverTooltip) - ) { + if (messages.length > 0 && (revealTooltip || this._isMouseOverItem || this._isMouseOverTooltip)) { this._ensureTooltip(); } else { this._isMouseOverItem = false; @@ -134,7 +143,7 @@ export default class StatusBarTile { } } - _disposeTooltip(): void { + _disposeTooltip() { if (this._tooltip != null) { this._tooltip.dispose(); this._tooltip = null; @@ -142,7 +151,7 @@ export default class StatusBarTile { } } - _ensureTooltip(): void { + _ensureTooltip() { if (this._tooltip != null) { return; } @@ -152,14 +161,18 @@ export default class StatusBarTile { body.appendChild(document.createElement('br')); } const titleElement = message.getTitleElement(); - invariant(titleElement != null); + + if (!(titleElement != null)) { + throw new Error('Invariant violation: "titleElement != null"'); + } + body.appendChild(titleElement); } this._tooltip = atom.tooltips.add(this._item, { item: body, delay: 0, - trigger: 'manual', + trigger: 'manual' }); const tooltipAtomObjects = atom.tooltips.tooltips.get(this._item); if (tooltipAtomObjects != null) { @@ -177,12 +190,8 @@ export default class StatusBarTile { } } - _startLeaveTimeoutIfNecessary(): void { - if ( - !this._isMouseOverItem && - this._isMouseOverTooltip === 0 && - this._leaveTimeoutId == null - ) { + _startLeaveTimeoutIfNecessary() { + if (!this._isMouseOverItem && this._isMouseOverTooltip === 0 && this._leaveTimeoutId == null) { this._leaveTimeoutId = setTimeout(() => { this._disposeTooltip(); // Currently visible messages should no longer reveal the tooltip again. @@ -191,10 +200,11 @@ export default class StatusBarTile { } } - _stopLeaveTimeout(): void { + _stopLeaveTimeout() { if (this._leaveTimeoutId != null) { clearTimeout(this._leaveTimeoutId); this._leaveTimeoutId = null; } } } +exports.default = StatusBarTile; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/main.js index 0dadbe3e..effc9d5c 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/main.js @@ -1,3 +1,37 @@ +'use strict'; + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _BusySignalSingleton; + +function _load_BusySignalSingleton() { + return _BusySignalSingleton = _interopRequireDefault(require('./BusySignalSingleton')); +} + +var _MessageStore; + +function _load_MessageStore() { + return _MessageStore = require('./MessageStore'); +} + +var _StatusBarTile; + +function _load_StatusBarTile() { + return _StatusBarTile = _interopRequireDefault(require('./StatusBarTile')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,45 +40,32 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {BusySignalService} from './types'; - -import createPackage from 'nuclide-commons-atom/createPackage'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import BusySignalSingleton from './BusySignalSingleton'; -import {MessageStore} from './MessageStore'; -import StatusBarTile from './StatusBarTile'; - class Activation { - _disposables: UniversalDisposable; - _service: BusySignalService; - _messageStore: MessageStore; constructor() { - this._messageStore = new MessageStore(); - this._service = new BusySignalSingleton(this._messageStore); - this._disposables = new UniversalDisposable(this._messageStore); + this._messageStore = new (_MessageStore || _load_MessageStore()).MessageStore(); + this._service = new (_BusySignalSingleton || _load_BusySignalSingleton()).default(this._messageStore); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(this._messageStore); } dispose() { this._disposables.dispose(); } - consumeStatusBar(statusBar: atom$StatusBar): IDisposable { + consumeStatusBar(statusBar) { // Avoid retaining StatusBarTile by wrapping it. - const disposable = new UniversalDisposable( - new StatusBarTile(statusBar, this._messageStore.getMessageStream()), - ); + const disposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(new (_StatusBarTile || _load_StatusBarTile()).default(statusBar, this._messageStore.getMessageStream())); this._disposables.add(disposable); return disposable; } - provideBusySignal(): BusySignalService { + provideBusySignal() { return this._service; } } -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/types.js index 38a0a1cd..a726efc4 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/lib/types.js @@ -1,57 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; - -export type BusySignalOptions = {| - // Can say that a busy signal will only appear when a given file is open. - // Default = null, meaning the busy signal applies to all files. - onlyForFile?: NuclideUri, - // Is user waiting for computer to finish a task? (traditional busy spinner) - // or is the computer waiting for user to finish a task? (action required) - // Default = spinner. - waitingFor?: 'computer' | 'user', - // Debounce it? default = true for busy-signal, and false for action-required. - debounce?: boolean, - // If onClick is set, then the tooltip will be clickable. Default = null. - onDidClick?: () => void, - // If set to true, the busy signal tooltip will be immediately revealed - // when it first becomes visible (without explicit mouse interaction). - revealTooltip?: boolean, -|}; - -export type BusySignalService = { - // Activates the busy signal with the given title and returns the promise - // from the provided callback. - // The busy signal automatically deactivates when the returned promise - // either resolves or rejects. - reportBusyWhile( - title: string, - f: () => Promise, - options?: BusySignalOptions, - ): Promise, - - // Activates the busy signal. Set the title in the returned BusySignal - // object (you can update the title multiple times) and dispose it when done. - reportBusy(title: string, options?: BusySignalOptions): BusyMessage, - - // This is a no-op. When someone consumes the busy service, they get back a - // reference to the single shared instance, so disposing of it would be wrong. - dispose(): void, -}; - -export type BusyMessage = { - // You can set/update the title. - setTitle(title: string): void, - // Dispose of the signal when done to make it go away. - dispose(): void, -}; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/spec/BusySignalInstance-spec.js b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/spec/BusySignalInstance-spec.js index ca086019..7d1bdd71 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-busy-signal/spec/BusySignalInstance-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-busy-signal/spec/BusySignalInstance-spec.js @@ -1,3 +1,27 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('nuclide-commons/fsPromise')); +} + +var _MessageStore; + +function _load_MessageStore() { + return _MessageStore = require('../lib/MessageStore'); +} + +var _BusySignalSingleton; + +function _load_BusySignalSingleton() { + return _BusySignalSingleton = _interopRequireDefault(require('../lib/BusySignalSingleton')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,65 +30,41 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {BusySignalOptions} from '../lib/types'; - -import fsPromise from 'nuclide-commons/fsPromise'; -import {MessageStore} from '../lib/MessageStore'; -import BusySignalSingleton from '../lib/BusySignalSingleton'; - describe('BusySignalSingleton', () => { - let messageStore: MessageStore; - let singleton: BusySignalSingleton; - let messages: Array>; - const options: BusySignalOptions = {debounce: false}; + let messageStore; + let singleton; + let messages; + const options = { debounce: false }; beforeEach(() => { - messageStore = new MessageStore(); - singleton = new BusySignalSingleton(messageStore); + messageStore = new (_MessageStore || _load_MessageStore()).MessageStore(); + singleton = new (_BusySignalSingleton || _load_BusySignalSingleton()).default(messageStore); messages = []; - messageStore - .getMessageStream() - .skip(1) - .subscribe(elements => { - const strings = [...elements].map(element => { - const titleElement = element.getTitleElement(); - const child = - titleElement != null && titleElement.childNodes.length >= 1 - ? titleElement.childNodes[0] - : {}; - return child.data != null && typeof child.data === 'string' - ? child.data - : ''; - }); - messages.push(strings); + messageStore.getMessageStream().skip(1).subscribe(elements => { + const strings = [...elements].map(element => { + const titleElement = element.getTitleElement(); + const child = titleElement != null && titleElement.childNodes.length >= 1 ? titleElement.childNodes[0] : {}; + return child.data != null && typeof child.data === 'string' ? child.data : ''; }); + messages.push(strings); + }); }); it('should record messages before and after a call', () => { expect(messages.length).toBe(0); singleton.reportBusyWhile('foo', () => Promise.resolve(5), options); expect(messages.length).toBe(1); - waitsFor( - () => messages.length === 2, - 'It should publish a second message', - 100, - ); + waitsFor(() => messages.length === 2, 'It should publish a second message', 100); }); it("should send the 'done' message even if the promise rejects", () => { - singleton - .reportBusyWhile('foo', () => Promise.reject(new Error()), options) - .catch(() => {}); + singleton.reportBusyWhile('foo', () => Promise.reject(new Error()), options).catch(() => {}); expect(messages.length).toBe(1); - waitsFor( - () => messages.length === 2, - 'It should publish a second message', - 100, - ); + waitsFor(() => messages.length === 2, 'It should publish a second message', 100); }); it('should properly display duplicate messages', () => { @@ -86,18 +86,18 @@ describe('BusySignalSingleton', () => { }); describe('when onlyForFile is provided', () => { - let editor1: atom$TextEditor = (null: any); - let editor2: atom$TextEditor = (null: any); - let editor3: atom$TextEditor = (null: any); + let editor1 = null; + let editor2 = null; + let editor3 = null; let file2; beforeEach(() => { - waitsForPromise(async () => { - editor1 = await atom.workspace.open(await fsPromise.tempfile()); - file2 = await fsPromise.tempfile(); - editor2 = await atom.workspace.open(file2); - editor3 = await atom.workspace.open(); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + editor1 = yield atom.workspace.open((yield (_fsPromise || _load_fsPromise()).default.tempfile())); + file2 = yield (_fsPromise || _load_fsPromise()).default.tempfile(); + editor2 = yield atom.workspace.open(file2); + editor3 = yield atom.workspace.open(); + })); }); afterEach(() => { @@ -107,10 +107,9 @@ describe('BusySignalSingleton', () => { it('should only display for the proper text editor', () => { atom.workspace.getActivePane().activateItem(editor1); - const disposable = singleton.reportBusy('foo', { - onlyForFile: file2, - ...options, - }); + const disposable = singleton.reportBusy('foo', Object.assign({ + onlyForFile: file2 + }, options)); expect(messages).toEqual([]); atom.workspace.getActivePane().activateItem(editor2); @@ -132,21 +131,18 @@ describe('BusySignalSingleton', () => { }); it('correctly sets revealTooltip when provided', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { function getCurrentMessages() { - return messageStore - .getMessageStream() - .take(1) - .toPromise(); + return messageStore.getMessageStream().take(1).toPromise(); } singleton.reportBusy('foo', { debounce: false, - revealTooltip: true, + revealTooltip: true }); - const curMessages = await getCurrentMessages(); + const curMessages = yield getCurrentMessages(); expect(curMessages.length).toBe(1); expect(curMessages[0].shouldRevealTooltip()).toBe(true); - }); + })); }); -}); +}); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/CodeActionManager.js b/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/CodeActionManager.js index 0bfc072d..1a6945fe 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/CodeActionManager.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/CodeActionManager.js @@ -1,206 +1,201 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import {observeActiveEditorsDebounced} from 'nuclide-commons-atom/debounced'; -import ProviderRegistry from 'nuclide-commons-atom/ProviderRegistry'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {arrayCompact, arrayFlatten} from 'nuclide-commons/collection'; -import {Observable} from 'rxjs'; -import {getLogger} from 'log4js'; - -import type { - RegisterIndieLinter, - IndieLinterDelegate, - LinterMessageV2, -} from '../../../index'; -import type { - DiagnosticMessage, - DiagnosticUpdater, -} from '../../atom-ide-diagnostics/lib/types'; -import type {CodeAction, CodeActionProvider, CodeActionFetcher} from './types'; - -const TIP_DELAY_MS = 500; - -async function actionsToMessage( - location: {file: string, position: atom$RangeLike}, - actions: Array, -): Promise { - const titles = await Promise.all(actions.map(r => r.getTitle())); - const solutions = titles.map((title, i) => ({ - title, - position: location.position, - apply: actions[i].apply.bind(actions[i]), - })); - return { - location, - solutions, - excerpt: 'Select an action', - severity: 'info', - kind: 'action', +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.CodeActionManager = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +let actionsToMessage = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (location, actions) { + const titles = yield Promise.all(actions.map(function (r) { + return r.getTitle(); + })); + const solutions = titles.map(function (title, i) { + return { + title, + position: location.position, + apply: actions[i].apply.bind(actions[i]) + }; + }); + return { + location, + solutions, + excerpt: 'Select an action', + severity: 'info', + kind: 'action' + }; + }); + + return function actionsToMessage(_x, _x2) { + return _ref.apply(this, arguments); }; +})(); + +var _debounced; + +function _load_debounced() { + return _debounced = require('nuclide-commons-atom/debounced'); +} + +var _ProviderRegistry; + +function _load_ProviderRegistry() { + return _ProviderRegistry = _interopRequireDefault(require('nuclide-commons-atom/ProviderRegistry')); +} + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); } -export class CodeActionManager { - _providerRegistry: ProviderRegistry; - _disposables: UniversalDisposable; - _linterDelegate: ?IndieLinterDelegate; - _diagnosticUpdater: ?DiagnosticUpdater; +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const TIP_DELAY_MS = 500; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class CodeActionManager { constructor() { - this._providerRegistry = new ProviderRegistry(); - this._disposables = new UniversalDisposable(this._selectionSubscriber()); + this._providerRegistry = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(this._selectionSubscriber()); } dispose() { this._disposables.dispose(); } - addProvider(provider: CodeActionProvider): IDisposable { + addProvider(provider) { const disposable = this._providerRegistry.addProvider(provider); this._disposables.add(disposable); return disposable; } - consumeDiagnosticUpdates(diagnosticUpdater: DiagnosticUpdater): IDisposable { + consumeDiagnosticUpdates(diagnosticUpdater) { this._diagnosticUpdater = diagnosticUpdater; - return new UniversalDisposable(() => { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { this._diagnosticUpdater = null; }); } - consumeIndie(register: RegisterIndieLinter): IDisposable { + consumeIndie(register) { const linterDelegate = register({ name: 'Code Actions', - supportedMessageKinds: ['action'], + supportedMessageKinds: ['action'] }); this._disposables.add(linterDelegate); this._linterDelegate = linterDelegate; - return new UniversalDisposable(() => { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { this._disposables.remove(linterDelegate); this._linterDelegate = null; }); } - async _genAllCodeActions( - editor: atom$TextEditor, - range: atom$Range, - diagnostics: Array, - ): Promise> { - const codeActionRequests = []; - for (const provider of this._providerRegistry.getAllProvidersForEditor( - editor, - )) { - codeActionRequests.push( - provider.getCodeActions(editor, range, diagnostics), - ); - } - return arrayFlatten(arrayCompact(await Promise.all(codeActionRequests))); + _genAllCodeActions(editor, range, diagnostics) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + const codeActionRequests = []; + for (const provider of _this._providerRegistry.getAllProvidersForEditor(editor)) { + codeActionRequests.push(provider.getCodeActions(editor, range, diagnostics)); + } + return (0, (_collection || _load_collection()).arrayFlatten)((0, (_collection || _load_collection()).arrayCompact)((yield Promise.all(codeActionRequests)))); + })(); } - createCodeActionFetcher(): CodeActionFetcher { + createCodeActionFetcher() { return { getCodeActionForDiagnostic: (diagnostic, editor) => { if (diagnostic.range) { - const {range} = diagnostic; + const { range } = diagnostic; return this._genAllCodeActions(editor, range, [diagnostic]); } return Promise.resolve([]); - }, + } }; } // Listen to buffer range selection changes and trigger code action providers // when ranges change. - _selectionSubscriber(): rxjs$Subscription { + _selectionSubscriber() { // Patterned after highlightEditors of CodeHighlightManager. - return observeActiveEditorsDebounced(0) - .switchMap( - // Get selections for the active editor. - editor => { - if (editor == null) { - return Observable.empty(); - } - const destroyEvents = observableFromSubscribeFunction( - editor.onDidDestroy.bind(editor), - ); - const selections = observableFromSubscribeFunction( - editor.onDidChangeSelectionRange.bind(editor), - ) - .switchMap( - event => - // Remove 0-character selections since it's just cursor movement. - event.newBufferRange.isEmpty() - ? Observable.of(null) - : Observable.of(event.newBufferRange) - .delay(TIP_DELAY_MS) // Delay the emission of the range. - .startWith(null), // null the range immediately when selection changes. - ) - .distinctUntilChanged() - .takeUntil(destroyEvents); - return selections.map( - range => (range == null ? null : {editor, range}), - ); - }, - ) - .switchMap( - // Get a message for the provided selection. - (selection: ?{editor: atom$TextEditor, range: atom$Range}) => { - if (selection == null) { - return Observable.of(null); - } - const {editor, range} = selection; - const file = editor.getBuffer().getPath(); - if (file == null) { - return Observable.empty(); - } - const diagnostics = - this._diagnosticUpdater == null - ? [] - : this._diagnosticUpdater - .getFileMessageUpdates(file) - .messages.filter( - message => - message.range && message.range.intersectsWith(range), - ); - return Observable.fromPromise( - this._genAllCodeActions(editor, range, diagnostics), - ).switchMap(actions => { - // Only produce a message if we have actions to display. - if (actions.length > 0) { - return actionsToMessage({file, position: range}, actions); - } else { - return Observable.empty(); - } - }); - }, - ) - .distinctUntilChanged() - .catch((e, caught) => { - getLogger('code-actions').error( - 'Error getting code actions on selection', - e, - ); - return caught; - }) - .subscribe(message => { - if (this._linterDelegate == null) { - return; - } - if (message == null) { - this._linterDelegate.clearMessages(); + return (0, (_debounced || _load_debounced()).observeActiveEditorsDebounced)(0).switchMap( + // Get selections for the active editor. + editor => { + if (editor == null) { + return _rxjsBundlesRxMinJs.Observable.empty(); + } + const destroyEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidDestroy.bind(editor)); + const selections = (0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidChangeSelectionRange.bind(editor)).switchMap(event => + // Remove 0-character selections since it's just cursor movement. + event.newBufferRange.isEmpty() ? _rxjsBundlesRxMinJs.Observable.of(null) : _rxjsBundlesRxMinJs.Observable.of(event.newBufferRange).delay(TIP_DELAY_MS) // Delay the emission of the range. + .startWith(null) // null the range immediately when selection changes. + ).distinctUntilChanged().takeUntil(destroyEvents); + return selections.map(range => range == null ? null : { editor, range }); + }).switchMap( + // Get a message for the provided selection. + selection => { + if (selection == null) { + return _rxjsBundlesRxMinJs.Observable.of(null); + } + const { editor, range } = selection; + const file = editor.getBuffer().getPath(); + if (file == null) { + return _rxjsBundlesRxMinJs.Observable.empty(); + } + const diagnostics = this._diagnosticUpdater == null ? [] : this._diagnosticUpdater.getFileMessageUpdates(file).messages.filter(message => message.range && message.range.intersectsWith(range)); + return _rxjsBundlesRxMinJs.Observable.fromPromise(this._genAllCodeActions(editor, range, diagnostics)).switchMap(actions => { + // Only produce a message if we have actions to display. + if (actions.length > 0) { + return actionsToMessage({ file, position: range }, actions); } else { - this._linterDelegate.setAllMessages([message]); + return _rxjsBundlesRxMinJs.Observable.empty(); } }); + }).distinctUntilChanged().catch((e, caught) => { + (0, (_log4js || _load_log4js()).getLogger)('code-actions').error('Error getting code actions on selection', e); + return caught; + }).subscribe(message => { + if (this._linterDelegate == null) { + return; + } + if (message == null) { + this._linterDelegate.clearMessages(); + } else { + this._linterDelegate.setAllMessages([message]); + } + }); } } +exports.CodeActionManager = CodeActionManager; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/main.js index cc068c15..4ed863e7 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/main.js @@ -1,3 +1,19 @@ +'use strict'; + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _CodeActionManager; + +function _load_CodeActionManager() { + return _CodeActionManager = require('./CodeActionManager'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,43 +22,35 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import createPackage from 'nuclide-commons-atom/createPackage'; -import {CodeActionManager} from './CodeActionManager'; - -import type {RegisterIndieLinter} from '../../../index'; -import type {CodeActionProvider, CodeActionFetcher} from './types'; -import type {DiagnosticUpdater} from '../../atom-ide-diagnostics/lib/types'; - class Activation { - _codeActionManager: CodeActionManager; constructor() { - this._codeActionManager = new CodeActionManager(); + this._codeActionManager = new (_CodeActionManager || _load_CodeActionManager()).CodeActionManager(); } dispose() { this._codeActionManager.dispose(); } - consumeCodeActionProvider(provider: CodeActionProvider) { + consumeCodeActionProvider(provider) { return this._codeActionManager.addProvider(provider); } - consumeDiagnosticUpdates(diagnosticUpdater: DiagnosticUpdater) { + consumeDiagnosticUpdates(diagnosticUpdater) { return this._codeActionManager.consumeDiagnosticUpdates(diagnosticUpdater); } - provideCodeActionFetcher(): CodeActionFetcher { + provideCodeActionFetcher() { return this._codeActionManager.createCodeActionFetcher(); } - consumeIndie(register: RegisterIndieLinter) { + consumeIndie(register) { return this._codeActionManager.consumeIndie(register); } } -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/types.js index 003f5366..a726efc4 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-actions/lib/types.js @@ -1,42 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {DiagnosticMessage} from '../../../pkg/atom-ide-diagnostics/lib/types'; - -export interface CodeAction { - apply(): Promise; - getTitle(): Promise; - dispose(): void; -} - -export type CodeActionProvider = { - +grammarScopes?: Array, - priority: number, - getCodeActions( - editor: atom$TextEditor, - range: atom$Range, - diagnostics: Array, - ): Promise>, -}; - -/** - * atom-ide-code-actions provides a CodeActionFetcher which offers an API to - * request CodeActions from all CodeAction providers. For now, CodeActionFetcher - * can only fetch CodeActions for a Diagnostic. In the future, this API can be - * extended to provide a stream of CodeActions based on the cursor position. - */ -export type CodeActionFetcher = { - getCodeActionForDiagnostic: ( - diagnostic: DiagnosticMessage, - editor: atom$TextEditor, - ) => Promise>, -}; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-actions/spec/CodeActionManager-spec.js b/modules/atom-ide-ui/pkg/atom-ide-code-actions/spec/CodeActionManager-spec.js index 825aaf85..64367a85 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-actions/spec/CodeActionManager-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-actions/spec/CodeActionManager-spec.js @@ -1,19 +1,22 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import os from 'os'; -import nuclideUri from 'nuclide-commons/nuclideUri'; +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); -import {CodeActionManager} from '../lib/CodeActionManager'; +var _os = _interopRequireDefault(require('os')); + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _CodeActionManager; + +function _load_CodeActionManager() { + return _CodeActionManager = require('../lib/CodeActionManager'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('CodeActionManager', () => { let manager; @@ -22,39 +25,39 @@ describe('CodeActionManager', () => { let editor; beforeEach(() => { jasmine.useMockClock(); - waitsForPromise(async () => { - editor = await atom.workspace.open( - nuclideUri.join(os.tmpdir(), 'test.txt'), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + editor = yield atom.workspace.open((_nuclideUri || _load_nuclideUri()).default.join(_os.default.tmpdir(), 'test.txt')); editor.setText('abc\ndef\nghi'); - manager = new CodeActionManager(); + manager = new (_CodeActionManager || _load_CodeActionManager()).CodeActionManager(); provider = { priority: 1, grammarScopes: ['text.plain.null-grammar'], - async getCodeActions(_e, _r, _d) { - return []; - }, + getCodeActions(_e, _r, _d) { + return (0, _asyncToGenerator.default)(function* () { + return []; + })(); + } }; delegate = { - clearMessages: () => {}, - setAllMessages: _messages => {}, + clearMessages: function () {}, + setAllMessages: function (_messages) {} }; - manager._linterDelegate = (delegate: any); + manager._linterDelegate = delegate; manager.addProvider(provider); - }); + })); }); it('finds code actions on highlight change and updates linter', () => { - const actions = [ - { - apply() {}, - async getTitle() { + const actions = [{ + apply() {}, + getTitle() { + return (0, _asyncToGenerator.default)(function* () { return 'Mock action'; - }, - dispose() {}, + })(); }, - ]; + dispose() {} + }]; const spyActions = spyOn(provider, 'getCodeActions').andReturn(actions); const spyLinter = spyOn(delegate, 'setAllMessages'); @@ -64,18 +67,22 @@ describe('CodeActionManager', () => { advanceClock(501); }); - waitsFor( - () => spyLinter.wasCalled, - 'should have called setAllMessages', - 750, - ); + waitsFor(() => spyLinter.wasCalled, 'should have called setAllMessages', 750); runs(() => { expect(spyActions).toHaveBeenCalled(); expect(spyLinter).toHaveBeenCalled(); - expect( - (spyLinter.mostRecentCall.args: any)[0][0].solutions.length, - ).toEqual(1); + expect(spyLinter.mostRecentCall.args[0][0].solutions.length).toEqual(1); }); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/CodeFormatManager.js b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/CodeFormatManager.js index f6c92237..03f719db 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/CodeFormatManager.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/CodeFormatManager.js @@ -1,66 +1,90 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {BusySignalService} from '../../atom-ide-busy-signal/lib/types'; -import type { - RangeCodeFormatProvider, - FileCodeFormatProvider, - OnTypeCodeFormatProvider, - OnSaveCodeFormatProvider, -} from './types'; - -import {Range} from 'atom'; -import {Observable, Subject} from 'rxjs'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import nuclideUri from 'nuclide-commons/nuclideUri'; -import {completingSwitchMap, microtask} from 'nuclide-commons/observable'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import ProviderRegistry from 'nuclide-commons-atom/ProviderRegistry'; -import { - observeEditorDestroy, - observeTextEditors, -} from 'nuclide-commons-atom/text-editor'; -import {applyTextEditsToBuffer} from 'nuclide-commons-atom/text-edit'; -import {getFormatOnSave, getFormatOnType} from './config'; -import {getLogger} from 'log4js'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -// Save events are critical, so don't allow providers to block them. -const SAVE_TIMEOUT = 2500; +var _atom = require('atom'); -type FormatEvent = - | { - type: 'command' | 'save' | 'new-save', - editor: atom$TextEditor, - } - | { - type: 'type', - editor: atom$TextEditor, - edit: atom$AggregatedTextEditEvent, - }; - -export default class CodeFormatManager { - _subscriptions: UniversalDisposable; - _rangeProviders: ProviderRegistry; - _fileProviders: ProviderRegistry; - _onTypeProviders: ProviderRegistry; - _onSaveProviders: ProviderRegistry; - _busySignalService: ?BusySignalService; +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _ProviderRegistry; + +function _load_ProviderRegistry() { + return _ProviderRegistry = _interopRequireDefault(require('nuclide-commons-atom/ProviderRegistry')); +} + +var _textEditor; + +function _load_textEditor() { + return _textEditor = require('nuclide-commons-atom/text-editor'); +} + +var _textEdit; + +function _load_textEdit() { + return _textEdit = require('nuclide-commons-atom/text-edit'); +} + +var _config; + +function _load_config() { + return _config = require('./config'); +} + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// Save events are critical, so don't allow providers to block them. +const SAVE_TIMEOUT = 2500; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class CodeFormatManager { constructor() { - this._subscriptions = new UniversalDisposable(this._subscribeToEvents()); - this._rangeProviders = new ProviderRegistry(); - this._fileProviders = new ProviderRegistry(); - this._onTypeProviders = new ProviderRegistry(); - this._onSaveProviders = new ProviderRegistry(); + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(this._subscribeToEvents()); + this._rangeProviders = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + this._fileProviders = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + this._onTypeProviders = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + this._onSaveProviders = new (_ProviderRegistry || _load_ProviderRegistry()).default(); } /** @@ -69,69 +93,44 @@ export default class CodeFormatManager { * By handling all events in a central location, we ensure that no buffer * runs into race conditions with simultaneous formatters. */ - _subscribeToEvents(): rxjs$Subscription { + _subscribeToEvents() { // Events from the explicit Atom command. - const commandEvents = observableFromSubscribeFunction(callback => - atom.commands.add( - 'atom-text-editor', - 'code-format:format-code', - callback, - ), - ).switchMap(() => { + const commandEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)(callback => atom.commands.add('atom-text-editor', 'code-format:format-code', callback)).switchMap(() => { const editor = atom.workspace.getActiveTextEditor(); if (!editor) { - return Observable.empty(); + return _rxjsBundlesRxMinJs.Observable.empty(); } - return Observable.of({type: 'command', editor}); + return _rxjsBundlesRxMinJs.Observable.of({ type: 'command', editor }); }); // Events from editor actions (saving, typing). - const editorEvents = observableFromSubscribeFunction( - observeTextEditors, - ).mergeMap(editor => this._getEditorEventStream(editor)); - - return ( - Observable.merge(commandEvents, editorEvents) - // Group events by buffer to prevent simultaneous formatting operations. - .groupBy( - event => event.editor.getBuffer(), - event => event, - grouped => - observableFromSubscribeFunction(callback => - grouped.key.onDidDestroy(callback), - ), - ) - .mergeMap(events => - // Make sure we halt everything when the editor gets destroyed. - events.let(completingSwitchMap(event => this._handleEvent(event))), - ) - .subscribe() - ); + const editorEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)((_textEditor || _load_textEditor()).observeTextEditors).mergeMap(editor => this._getEditorEventStream(editor)); + + return _rxjsBundlesRxMinJs.Observable.merge(commandEvents, editorEvents) + // Group events by buffer to prevent simultaneous formatting operations. + .groupBy(event => event.editor.getBuffer(), event => event, grouped => (0, (_event || _load_event()).observableFromSubscribeFunction)(callback => grouped.key.onDidDestroy(callback))).mergeMap(events => + // Make sure we halt everything when the editor gets destroyed. + events.let((0, (_observable || _load_observable()).completingSwitchMap)(event => this._handleEvent(event)))).subscribe(); } /** * Returns a stream of all typing and saving operations from the editor. */ - _getEditorEventStream(editor: atom$TextEditor): Observable { - const changeEvents = observableFromSubscribeFunction(callback => - editor.getBuffer().onDidChangeText(callback), - ); + _getEditorEventStream(editor) { + const changeEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)(callback => editor.getBuffer().onDidChangeText(callback)); - const saveEvents = Observable.create(observer => { + const saveEvents = _rxjsBundlesRxMinJs.Observable.create(observer => { const realSave = editor.save; - const newSaves = new Subject(); + const newSaves = new _rxjsBundlesRxMinJs.Subject(); // HACK: intercept the real TextEditor.save and handle it ourselves. // Atom has no way of injecting content into the buffer asynchronously // before a save operation. // If we try to format after the save, and then save again, // it's a poor user experience (and also races the text buffer's reload). - const editor_ = (editor: any); + const editor_ = editor; editor_.save = () => { newSaves.next('new-save'); - return this._safeFormatCodeOnSave(editor) - .takeUntil(newSaves) - .toPromise() - .then(() => realSave.call(editor)); + return this._safeFormatCodeOnSave(editor).takeUntil(newSaves).toPromise().then(() => realSave.call(editor)); }; const subscription = newSaves.subscribe(observer); return () => { @@ -144,83 +143,59 @@ export default class CodeFormatManager { // We need to capture when editors are about to be destroyed in order to // interrupt any pending formatting operations. (Otherwise, we may end up // attempting to save a destroyed editor!) - const willDestroyEvents = observableFromSubscribeFunction(cb => - atom.workspace.onWillDestroyPaneItem(cb), - ).filter(event => event.item === editor); - - return Observable.merge( - changeEvents.map(edit => ({type: 'type', editor, edit})), - saveEvents.map(type => ({type, editor})), - ).takeUntil( - Observable.merge(observeEditorDestroy(editor), willDestroyEvents), - ); + const willDestroyEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)(cb => atom.workspace.onWillDestroyPaneItem(cb)).filter(event => event.item === editor); + + return _rxjsBundlesRxMinJs.Observable.merge(changeEvents.map(edit => ({ type: 'type', editor, edit })), saveEvents.map(type => ({ type, editor }))).takeUntil(_rxjsBundlesRxMinJs.Observable.merge((0, (_textEditor || _load_textEditor()).observeEditorDestroy)(editor), willDestroyEvents)); } - _handleEvent(event: FormatEvent): Observable { - const {editor} = event; + _handleEvent(event) { + const { editor } = event; switch (event.type) { case 'command': - return this._formatCodeInTextEditor(editor) - .map(result => { - if (!result) { - throw new Error('No code formatting providers found!'); - } - }) - .catch(err => { - atom.notifications.addError( - `Failed to format code: ${err.message}`, - { - detail: err.detail, - }, - ); - return Observable.empty(); + return this._formatCodeInTextEditor(editor).map(result => { + if (!result) { + throw new Error('No code formatting providers found!'); + } + }).catch(err => { + atom.notifications.addError(`Failed to format code: ${err.message}`, { + detail: err.detail }); + return _rxjsBundlesRxMinJs.Observable.empty(); + }); case 'type': - return this._formatCodeOnTypeInTextEditor(editor, event.edit).catch( - err => { - getLogger('code-format').warn( - 'Failed to format code on type:', - err, - ); - return Observable.empty(); - }, - ); + return this._formatCodeOnTypeInTextEditor(editor, event.edit).catch(err => { + (0, (_log4js || _load_log4js()).getLogger)('code-format').warn('Failed to format code on type:', err); + return _rxjsBundlesRxMinJs.Observable.empty(); + }); case 'save': - return ( - this._safeFormatCodeOnSave(editor) - // Fire-and-forget the original save function. - // This is actually async for remote files, but we don't use the result. - // NOTE: finally is important, as saves should still fire on unsubscribe. - .finally(() => editor.getBuffer().save()) - ); + return this._safeFormatCodeOnSave(editor) + // Fire-and-forget the original save function. + // This is actually async for remote files, but we don't use the result. + // NOTE: finally is important, as saves should still fire on unsubscribe. + .finally(() => editor.getBuffer().save()); case 'new-save': - return Observable.empty(); + return _rxjsBundlesRxMinJs.Observable.empty(); default: - return Observable.throw(`unknown event type ${event.type}`); + return _rxjsBundlesRxMinJs.Observable.throw(`unknown event type ${event.type}`); } } // Checks whether contents are same in the buffer post-format, throwing if // anything has changed. - _checkContentsAreSame(before: string, after: string): void { + _checkContentsAreSame(before, after) { if (before !== after) { - throw new Error( - 'The file contents were changed before formatting was complete.', - ); + throw new Error('The file contents were changed before formatting was complete.'); } } // Formats code in the editor specified, returning whether or not a // code formatter completed successfully. - _formatCodeInTextEditor( - editor: atom$TextEditor, - range?: atom$Range, - ): Observable { - return Observable.defer(() => { + _formatCodeInTextEditor(editor, range) { + return _rxjsBundlesRxMinJs.Observable.defer(() => { const buffer = editor.getBuffer(); const selectionRange = range || editor.getSelectedBufferRange(); - const {start: selectionStart, end: selectionEnd} = selectionRange; - let formatRange: atom$Range; + const { start: selectionStart, end: selectionEnd } = selectionRange; + let formatRange; if (selectionRange.isEmpty()) { // If no selection is done, then, the whole file is wanted to be formatted. formatRange = buffer.getRange(); @@ -232,47 +207,29 @@ export default class CodeFormatManager { // or (2) at the first column of the line AFTER their selection. In both cases // we snap the formatRange to end at the first column of the line after their // selection.) - formatRange = new Range( - [selectionStart.row, 0], - selectionEnd.column === 0 ? selectionEnd : [selectionEnd.row + 1, 0], - ); + formatRange = new _atom.Range([selectionStart.row, 0], selectionEnd.column === 0 ? selectionEnd : [selectionEnd.row + 1, 0]); } const rangeProvider = this._rangeProviders.getProviderForEditor(editor); const fileProvider = this._fileProviders.getProviderForEditor(editor); const contents = editor.getText(); - if ( - rangeProvider != null && - // When formatting the entire file, prefer file-based providers. - (!formatRange.isEqual(buffer.getRange()) || fileProvider == null) - ) { - return Observable.defer(() => - this._reportBusy( - editor, - rangeProvider.formatCode(editor, formatRange), - ), - ).map(edits => { + if (rangeProvider != null && ( + // When formatting the entire file, prefer file-based providers. + !formatRange.isEqual(buffer.getRange()) || fileProvider == null)) { + return _rxjsBundlesRxMinJs.Observable.defer(() => this._reportBusy(editor, rangeProvider.formatCode(editor, formatRange))).map(edits => { // Throws if contents have changed since the time of triggering format code. this._checkContentsAreSame(contents, editor.getText()); - if (!applyTextEditsToBuffer(editor.getBuffer(), edits)) { + if (!(0, (_textEdit || _load_textEdit()).applyTextEditsToBuffer)(editor.getBuffer(), edits)) { throw new Error('Could not apply edits to text buffer.'); } return true; }); } else if (fileProvider != null) { - return Observable.defer(() => - this._reportBusy( - editor, - fileProvider.formatEntireFile(editor, formatRange), - ), - ).map(({newCursor, formatted}) => { + return _rxjsBundlesRxMinJs.Observable.defer(() => this._reportBusy(editor, fileProvider.formatEntireFile(editor, formatRange))).map(({ newCursor, formatted }) => { // Throws if contents have changed since the time of triggering format code. this._checkContentsAreSame(contents, editor.getText()); buffer.setTextViaDiff(formatted); - const newPosition = - newCursor != null - ? buffer.positionForCharacterIndex(newCursor) - : editor.getCursorBufferPosition(); + const newPosition = newCursor != null ? buffer.positionForCharacterIndex(newCursor) : editor.getCursorBufferPosition(); // We call setCursorBufferPosition even when there is no newCursor, // because it unselects the text selection. @@ -280,24 +237,21 @@ export default class CodeFormatManager { return true; }); } else { - return Observable.of(false); + return _rxjsBundlesRxMinJs.Observable.of(false); } }); } - _formatCodeOnTypeInTextEditor( - editor: atom$TextEditor, - aggregatedEvent: atom$AggregatedTextEditEvent, - ): Observable { - return Observable.defer(() => { + _formatCodeOnTypeInTextEditor(editor, aggregatedEvent) { + return _rxjsBundlesRxMinJs.Observable.defer(() => { // Don't try to format changes with multiple cursors. if (aggregatedEvent.changes.length !== 1) { - return Observable.empty(); + return _rxjsBundlesRxMinJs.Observable.empty(); } const event = aggregatedEvent.changes[0]; // This also ensures the non-emptiness of event.newText for below. - if (!shouldFormatOnType(event) || !getFormatOnType()) { - return Observable.empty(); + if (!shouldFormatOnType(event) || !(0, (_config || _load_config()).getFormatOnType)()) { + return _rxjsBundlesRxMinJs.Observable.empty(); } // In the case of bracket-matching, we use the last character because that's // the character that will usually cause a reformat (i.e. `}` instead of `{`). @@ -305,7 +259,7 @@ export default class CodeFormatManager { const provider = this._onTypeProviders.getProviderForEditor(editor); if (provider == null) { - return Observable.empty(); + return _rxjsBundlesRxMinJs.Observable.empty(); } const contents = editor.getText(); @@ -322,94 +276,70 @@ export default class CodeFormatManager { // We want to wait until the cursor has actually moved before we issue a // format request, so that we format at the right position (and potentially // also let any other event handlers have their go). - return microtask - .switchMap(() => - provider.formatAtPosition( - editor, - editor.getCursorBufferPosition().translate([0, -1]), - character, - ), - ) - .map(edits => { - if (edits.length === 0) { - return; - } - this._checkContentsAreSame(contents, editor.getText()); - // Note that this modification is not in a transaction, so it applies as a - // separate editing event than the character typing. This means that you - // can undo just the formatting by attempting to undo once, and then undo - // your actual code by undoing again. - if (!applyTextEditsToBuffer(editor.getBuffer(), edits)) { - throw new Error('Could not apply edits to text buffer.'); - } - }); + return (_observable || _load_observable()).microtask.switchMap(() => provider.formatAtPosition(editor, editor.getCursorBufferPosition().translate([0, -1]), character)).map(edits => { + if (edits.length === 0) { + return; + } + this._checkContentsAreSame(contents, editor.getText()); + // Note that this modification is not in a transaction, so it applies as a + // separate editing event than the character typing. This means that you + // can undo just the formatting by attempting to undo once, and then undo + // your actual code by undoing again. + if (!(0, (_textEdit || _load_textEdit()).applyTextEditsToBuffer)(editor.getBuffer(), edits)) { + throw new Error('Could not apply edits to text buffer.'); + } + }); }); } - _safeFormatCodeOnSave(editor: atom$TextEditor): Observable { - return this._formatCodeOnSaveInTextEditor(editor) - .timeout(SAVE_TIMEOUT) - .catch(err => { - getLogger('code-format').warn('Failed to format code on save:', err); - return Observable.empty(); - }); + _safeFormatCodeOnSave(editor) { + return this._formatCodeOnSaveInTextEditor(editor).timeout(SAVE_TIMEOUT).catch(err => { + (0, (_log4js || _load_log4js()).getLogger)('code-format').warn('Failed to format code on save:', err); + return _rxjsBundlesRxMinJs.Observable.empty(); + }); } - _formatCodeOnSaveInTextEditor(editor: atom$TextEditor): Observable { + _formatCodeOnSaveInTextEditor(editor) { const saveProvider = this._onSaveProviders.getProviderForEditor(editor); if (saveProvider != null) { - return Observable.defer(() => - this._reportBusy(editor, saveProvider.formatOnSave(editor), false), - ).map(edits => { - applyTextEditsToBuffer(editor.getBuffer(), edits); + return _rxjsBundlesRxMinJs.Observable.defer(() => this._reportBusy(editor, saveProvider.formatOnSave(editor), false)).map(edits => { + (0, (_textEdit || _load_textEdit()).applyTextEditsToBuffer)(editor.getBuffer(), edits); }); - } else if (getFormatOnSave()) { - return this._formatCodeInTextEditor( - editor, - editor.getBuffer().getRange(), - ).ignoreElements(); + } else if ((0, (_config || _load_config()).getFormatOnSave)()) { + return this._formatCodeInTextEditor(editor, editor.getBuffer().getRange()).ignoreElements(); } - return Observable.empty(); + return _rxjsBundlesRxMinJs.Observable.empty(); } - _reportBusy( - editor: atom$TextEditor, - promise: Promise, - revealTooltip?: boolean = true, - ): Promise { + _reportBusy(editor, promise, revealTooltip = true) { const busySignalService = this._busySignalService; if (busySignalService != null) { const path = editor.getPath(); - const displayPath = - path != null ? nuclideUri.basename(path) : ''; - return busySignalService.reportBusyWhile( - `Formatting code in ${displayPath}`, - () => promise, - {revealTooltip}, - ); + const displayPath = path != null ? (_nuclideUri || _load_nuclideUri()).default.basename(path) : ''; + return busySignalService.reportBusyWhile(`Formatting code in ${displayPath}`, () => promise, { revealTooltip }); } return promise; } - addRangeProvider(provider: RangeCodeFormatProvider): IDisposable { + addRangeProvider(provider) { return this._rangeProviders.addProvider(provider); } - addFileProvider(provider: FileCodeFormatProvider): IDisposable { + addFileProvider(provider) { return this._fileProviders.addProvider(provider); } - addOnTypeProvider(provider: OnTypeCodeFormatProvider): IDisposable { + addOnTypeProvider(provider) { return this._onTypeProviders.addProvider(provider); } - addOnSaveProvider(provider: OnSaveCodeFormatProvider): IDisposable { + addOnSaveProvider(provider) { return this._onSaveProviders.addProvider(provider); } - consumeBusySignal(busySignalService: BusySignalService): IDisposable { + consumeBusySignal(busySignalService) { this._busySignalService = busySignalService; - return new UniversalDisposable(() => { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { this._busySignalService = null; }); } @@ -419,7 +349,8 @@ export default class CodeFormatManager { } } -function shouldFormatOnType(event: atom$TextEditEvent): boolean { +exports.default = CodeFormatManager; +function shouldFormatOnType(event) { // There's not a direct way to figure out what caused this edit event. There // are three cases that we want to pay attention to: // @@ -453,12 +384,10 @@ function shouldFormatOnType(event: atom$TextEditEvent): boolean { * inserting an extra bracket, so we just assume that any pair of brackets that * bracket-matcher recognizes was a pair matched by the package. */ -function isBracketPair(typedText: string): boolean { +function isBracketPair(typedText) { if (atom.packages.getActivePackage('bracket-matcher') == null) { return false; } - const validBracketPairs: Array = (atom.config.get( - 'bracket-matcher.autocompleteCharacters', - ): any); + const validBracketPairs = atom.config.get('bracket-matcher.autocompleteCharacters'); return validBracketPairs.indexOf(typedText) !== -1; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/config.js b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/config.js index 8c50f9e4..c6ff1528 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/config.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/config.js @@ -1,27 +1,34 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import featureConfig from 'nuclide-commons-atom/feature-config'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getFormatOnSave = getFormatOnSave; +exports.getFormatOnType = getFormatOnType; -export function getFormatOnSave(): boolean { - const formatOnSave = (featureConfig.get( - 'atom-ide-code-format.formatOnSave', - ): any); - return formatOnSave == null ? false : formatOnSave; -} +var _featureConfig; -export function getFormatOnType(): boolean { - return featureConfig.getWithDefaults( - 'atom-ide-code-format.formatOnType', - false, - ); +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function getFormatOnSave() { + const formatOnSave = (_featureConfig || _load_featureConfig()).default.get('atom-ide-code-format.formatOnSave'); + return formatOnSave == null ? false : formatOnSave; +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function getFormatOnType() { + return (_featureConfig || _load_featureConfig()).default.getWithDefaults('atom-ide-code-format.formatOnType', false); +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/main.js index 946f6d7b..04f6c87f 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/main.js @@ -1,3 +1,19 @@ +'use strict'; + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _CodeFormatManager; + +function _load_CodeFormatManager() { + return _CodeFormatManager = _interopRequireDefault(require('./CodeFormatManager')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,38 +22,20 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {BusySignalService} from '../../atom-ide-busy-signal/lib/types'; -import type { - CodeFormatProvider, - RangeCodeFormatProvider, - FileCodeFormatProvider, - OnTypeCodeFormatProvider, - OnSaveCodeFormatProvider, -} from './types'; - -import createPackage from 'nuclide-commons-atom/createPackage'; -import CodeFormatManager from './CodeFormatManager'; - class Activation { - codeFormatManager: CodeFormatManager; constructor() { - this.codeFormatManager = new CodeFormatManager(); + this.codeFormatManager = new (_CodeFormatManager || _load_CodeFormatManager()).default(); } - consumeLegacyProvider(provider: CodeFormatProvider): IDisposable { + consumeLegacyProvider(provider) { // Legacy providers used `selector` / `inclusionPriority`. - provider.grammarScopes = - provider.grammarScopes || - (provider.selector != null ? provider.selector.split(', ') : null); - provider.priority = - provider.priority != null - ? provider.priority - : provider.inclusionPriority != null ? provider.inclusionPriority : 0; + provider.grammarScopes = provider.grammarScopes || (provider.selector != null ? provider.selector.split(', ') : null); + provider.priority = provider.priority != null ? provider.priority : provider.inclusionPriority != null ? provider.inclusionPriority : 0; if (provider.formatCode) { return this.consumeRangeProvider(provider); } else if (provider.formatEntireFile) { @@ -50,23 +48,23 @@ class Activation { throw new Error('Invalid code format provider'); } - consumeRangeProvider(provider: RangeCodeFormatProvider): IDisposable { + consumeRangeProvider(provider) { return this.codeFormatManager.addRangeProvider(provider); } - consumeFileProvider(provider: FileCodeFormatProvider): IDisposable { + consumeFileProvider(provider) { return this.codeFormatManager.addFileProvider(provider); } - consumeOnTypeProvider(provider: OnTypeCodeFormatProvider): IDisposable { + consumeOnTypeProvider(provider) { return this.codeFormatManager.addOnTypeProvider(provider); } - consumeOnSaveProvider(provider: OnSaveCodeFormatProvider): IDisposable { + consumeOnSaveProvider(provider) { return this.codeFormatManager.addOnSaveProvider(provider); } - consumeBusySignal(busySignalService: BusySignalService): IDisposable { + consumeBusySignal(busySignalService) { return this.codeFormatManager.consumeBusySignal(busySignalService); } @@ -75,4 +73,4 @@ class Activation { } } -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/types.js index 971a82d6..a726efc4 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-format/lib/types.js @@ -1,96 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {TextEdit} from 'nuclide-commons-atom/text-edit'; - -/** - * A brief overview of the different code formatting providers: - * - * == Range formatters == - * These accept a range to format and return a list of edits to apply. - * These will always be preferred over file formatters when a range is selected. - * - * == File formatters == - * These always return the result of formatting the entire file. - * To compensate, they can return a custom cursor position to avoid disruption. - * These will be preferred over range formatters for whole-file formatting. - * - * == onType formatters == - * These are run after every typing event in a selected editor. - * - * == onSave formatters == - * These are run whenever a selected editor is saved. - * If the global format-on-save option is enabled, then file/range formatters - * will be triggered on save (even if no save formatters are provided). - * Obviously, save formatters are preferred in this case. - */ - -/** - * Formats the range specified, and returns a list of text edits to apply. - * Text edits must be non-overlapping and preferably in reverse-sorted order. - */ -export type RangeCodeFormatProvider = {| - formatCode: ( - editor: atom$TextEditor, - range: atom$Range, - ) => Promise>, - priority: number, - grammarScopes: Array, -|}; - -/** - * Formats the range specified, but returns the entire file (along with the new cursor position). - * Useful for less-flexible providers like clang-format. - */ -export type FileCodeFormatProvider = {| - formatEntireFile: ( - editor: atom$TextEditor, - range: atom$Range, - ) => Promise<{ - newCursor?: number, - formatted: string, - }>, - priority: number, - grammarScopes: Array, -|}; - -/** - * Formats around the given position, and returns a list of text edits to - * apply, similar to `formatCode`. The provider determines the exact - * range to format based on what's at that position. - * - * This will automatically triggered after every typing event. - */ -export type OnTypeCodeFormatProvider = {| - formatAtPosition: ( - editor: atom$TextEditor, - position: atom$Point, - triggerCharacter: string, - ) => Promise>, - priority: number, - grammarScopes: Array, -|}; - -/** - * Formats files after save events. - */ -export type OnSaveCodeFormatProvider = {| - formatOnSave: (editor: atom$TextEditor) => Promise>, - priority: number, - grammarScopes: Array, -|}; - -export type CodeFormatProvider = - | RangeCodeFormatProvider - | FileCodeFormatProvider - | OnTypeCodeFormatProvider - | OnSaveCodeFormatProvider; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-format/spec/CodeFormatManager-spec.js b/modules/atom-ide-ui/pkg/atom-ide-code-format/spec/CodeFormatManager-spec.js index 51faa61e..b9507c33 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-format/spec/CodeFormatManager-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-format/spec/CodeFormatManager-spec.js @@ -1,3 +1,31 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _atom = require('atom'); + +var _temp; + +function _load_temp() { + return _temp = _interopRequireDefault(require('temp')); +} + +var _config; + +function _load_config() { + return _config = _interopRequireWildcard(require('../lib/config')); +} + +var _CodeFormatManager; + +function _load_CodeFormatManager() { + return _CodeFormatManager = _interopRequireDefault(require('../lib/CodeFormatManager')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,83 +34,76 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import {Range} from 'atom'; -import temp from 'temp'; -import * as config from '../lib/config'; -import CodeFormatManager from '../lib/CodeFormatManager'; - describe('CodeFormatManager', () => { let textEditor; beforeEach(() => { - waitsForPromise(async () => { - temp.track(); - const file = temp.openSync(); - textEditor = await atom.workspace.open(file.path); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + (_temp || _load_temp()).default.track(); + const file = (_temp || _load_temp()).default.openSync(); + textEditor = yield atom.workspace.open(file.path); + })); }); it('formats an editor on request', () => { - waitsForPromise(async () => { - const manager = new CodeFormatManager(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const manager = new (_CodeFormatManager || _load_CodeFormatManager()).default(); manager.addRangeProvider({ grammarScopes: ['text.plain.null-grammar'], priority: 1, - formatCode: () => - Promise.resolve([ - { - oldRange: new Range([0, 0], [0, 3]), - oldText: 'abc', - newText: 'def', - }, - ]), + formatCode: function () { + return Promise.resolve([{ + oldRange: new _atom.Range([0, 0], [0, 3]), + oldText: 'abc', + newText: 'def' + }]); + } }); textEditor.setText('abc'); - atom.commands.dispatch( - atom.views.getView(textEditor), - 'code-format:format-code', - ); - waitsFor(() => textEditor.getText() === 'def'); - }); + atom.commands.dispatch(atom.views.getView(textEditor), 'code-format:format-code'); + waitsFor(function () { + return textEditor.getText() === 'def'; + }); + })); }); it('format an editor using formatEntireFile', () => { - waitsForPromise(async () => { - const manager = new CodeFormatManager(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const manager = new (_CodeFormatManager || _load_CodeFormatManager()).default(); manager.addFileProvider({ grammarScopes: ['text.plain.null-grammar'], priority: 1, - formatEntireFile: () => Promise.resolve({formatted: 'ghi'}), + formatEntireFile: function () { + return Promise.resolve({ formatted: 'ghi' }); + } }); textEditor.setText('abc'); - atom.commands.dispatch( - atom.views.getView(textEditor), - 'code-format:format-code', - ); - waitsFor(() => textEditor.getText() === 'ghi'); - }); + atom.commands.dispatch(atom.views.getView(textEditor), 'code-format:format-code'); + waitsFor(function () { + return textEditor.getText() === 'ghi'; + }); + })); }); it('formats an editor on type', () => { - waitsForPromise(async () => { - spyOn(config, 'getFormatOnType').andReturn(true); - const manager = new CodeFormatManager(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + spyOn(_config || _load_config(), 'getFormatOnType').andReturn(true); + const manager = new (_CodeFormatManager || _load_CodeFormatManager()).default(); const provider = { grammarScopes: ['text.plain.null-grammar'], priority: 1, - formatAtPosition: () => - Promise.resolve([ - { - oldRange: new Range([0, 0], [0, 3]), - oldText: 'abc', - newText: 'def', - }, - ]), + formatAtPosition: function () { + return Promise.resolve([{ + oldRange: new _atom.Range([0, 0], [0, 3]), + oldText: 'abc', + newText: 'def' + }]); + } }; const spy = spyOn(provider, 'formatAtPosition').andCallThrough(); manager.addOnTypeProvider(provider); @@ -92,46 +113,49 @@ describe('CodeFormatManager', () => { textEditor.insertText('b'); textEditor.insertText('c'); - waitsFor(() => textEditor.getText() === 'def'); - runs(() => { + waitsFor(function () { + return textEditor.getText() === 'def'; + }); + runs(function () { // Debouncing should ensure only one format call. expect(spy.callCount).toBe(1); }); - }); + })); }); it('formats an editor on save', () => { - waitsForPromise(async () => { - spyOn(config, 'getFormatOnSave').andReturn(true); - const manager = new CodeFormatManager(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + spyOn(_config || _load_config(), 'getFormatOnSave').andReturn(true); + const manager = new (_CodeFormatManager || _load_CodeFormatManager()).default(); manager.addOnSaveProvider({ grammarScopes: ['text.plain.null-grammar'], priority: 1, - formatOnSave: () => - Promise.resolve([ - { - oldRange: new Range([0, 0], [0, 3]), - oldText: 'abc', - newText: 'def', - }, - ]), + formatOnSave: function () { + return Promise.resolve([{ + oldRange: new _atom.Range([0, 0], [0, 3]), + oldText: 'abc', + newText: 'def' + }]); + } }); textEditor.setText('abc'); - await textEditor.save(); + yield textEditor.save(); expect(textEditor.getText()).toBe('def'); - }); + })); }); it('should still save on timeout', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { jasmine.Clock.useMock(); - spyOn(config, 'getFormatOnSave').andReturn(true); - const manager = new CodeFormatManager(); + spyOn(_config || _load_config(), 'getFormatOnSave').andReturn(true); + const manager = new (_CodeFormatManager || _load_CodeFormatManager()).default(); manager.addRangeProvider({ grammarScopes: ['text.plain.null-grammar'], priority: 1, - formatCode: () => new Promise(() => {}), + formatCode: function () { + return new Promise(function () {}); + } }); const spy = spyOn(textEditor.getBuffer(), 'save').andCallThrough(); @@ -139,20 +163,28 @@ describe('CodeFormatManager', () => { const savePromise = Promise.resolve(textEditor.save()); // The first save should be pushed through after the 2nd. - waitsFor(() => spy.callCount === 1); + waitsFor(function () { + return spy.callCount === 1; + }); - runs(() => { + runs(function () { jasmine.Clock.tick(3000); }); // Hitting the timeout will force the 2nd save through. - waitsFor(() => spy.callCount === 2); + waitsFor(function () { + return spy.callCount === 2; + }); // The real save should still go through. - waitsForPromise(() => savePromise); + waitsForPromise(function () { + return savePromise; + }); // Sanity check. - runs(() => expect(spy.callCount).toBe(2)); - }); + runs(function () { + return expect(spy.callCount).toBe(2); + }); + })); }); -}); +}); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/CodeHighlightManager.js b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/CodeHighlightManager.js index cb79ee91..920b4583 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/CodeHighlightManager.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/CodeHighlightManager.js @@ -1,3 +1,51 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _ProviderRegistry; + +function _load_ProviderRegistry() { + return _ProviderRegistry = _interopRequireDefault(require('nuclide-commons-atom/ProviderRegistry')); +} + +var _debounced; + +function _load_debounced() { + return _debounced = require('nuclide-commons-atom/debounced'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,135 +54,100 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {CodeHighlightProvider} from './types'; - -import {getLogger} from 'log4js'; -import {Observable} from 'rxjs'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import {fastDebounce, toggle} from 'nuclide-commons/observable'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import ProviderRegistry from 'nuclide-commons-atom/ProviderRegistry'; -import {observeActiveEditorsDebounced} from 'nuclide-commons-atom/debounced'; - const CURSOR_DELAY_MS = 250; // Apply a much higher debounce to text changes to avoid disrupting the typing experience. const CHANGE_TOGGLE_MS = 2500; -export default class CodeHighlightManager { - _subscriptions: UniversalDisposable; - _providers: ProviderRegistry; - _markers: Array; +class CodeHighlightManager { constructor() { - this._providers = new ProviderRegistry(); + this._providers = new (_ProviderRegistry || _load_ProviderRegistry()).default(); this._markers = []; - this._subscriptions = new UniversalDisposable(this._highlightEditors()); + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(this._highlightEditors()); } - _highlightEditors(): rxjs$Subscription { - return observeActiveEditorsDebounced(0) - .do(() => this._destroyMarkers()) - .switchMap(editor => { - if (editor == null) { - return Observable.empty(); - } - const cursorPositions = observableFromSubscribeFunction( - editor.onDidChangeCursorPosition.bind(editor), - ) - .filter( - // If we're moving around inside highlighted ranges, that's fine. - event => - !this._isPositionInHighlightedRanges( - editor, - event.newBufferPosition, - ), - ) - .do(() => this._destroyMarkers()) // Immediately clear previous markers. - .let(fastDebounce(CURSOR_DELAY_MS)) - .startWith((null: any)) // Immediately kick off a highlight event. - .map(() => editor.getCursorBufferPosition()); - - // Changing text triggers a CHANGE_TOGGLE_MS period in which cursor changes are ignored. - // We'll model this as one stream that emits 'false' and another that debounces 'true's. - const changeEvents = observableFromSubscribeFunction( - editor.onDidChange.bind(editor), - ) - .do(() => this._destroyMarkers()) - .share(); - - const changeToggles = Observable.merge( - Observable.of(true), - changeEvents.mapTo(false), - changeEvents.let(fastDebounce(CHANGE_TOGGLE_MS)).mapTo(true), - ); - - const destroyEvents = observableFromSubscribeFunction( - editor.onDidDestroy.bind(editor), - ); - - return cursorPositions - .let(toggle(changeToggles)) - .switchMap(async position => { - return { - editor, - ranges: await this._getHighlightedRanges(editor, position), - }; - }) - .takeUntil(destroyEvents); - }) - .subscribe(({editor, ranges}) => { - if (ranges != null) { - this._highlightRanges(editor, ranges); - } - }); + _highlightEditors() { + var _this = this; + + return (0, (_debounced || _load_debounced()).observeActiveEditorsDebounced)(0).do(() => this._destroyMarkers()).switchMap(editor => { + if (editor == null) { + return _rxjsBundlesRxMinJs.Observable.empty(); + } + const cursorPositions = (0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidChangeCursorPosition.bind(editor)).filter( + // If we're moving around inside highlighted ranges, that's fine. + event => !this._isPositionInHighlightedRanges(editor, event.newBufferPosition)).do(() => this._destroyMarkers()) // Immediately clear previous markers. + .let((0, (_observable || _load_observable()).fastDebounce)(CURSOR_DELAY_MS)).startWith(null) // Immediately kick off a highlight event. + .map(() => editor.getCursorBufferPosition()); + + // Changing text triggers a CHANGE_TOGGLE_MS period in which cursor changes are ignored. + // We'll model this as one stream that emits 'false' and another that debounces 'true's. + const changeEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidChange.bind(editor)).do(() => this._destroyMarkers()).share(); + + const changeToggles = _rxjsBundlesRxMinJs.Observable.merge(_rxjsBundlesRxMinJs.Observable.of(true), changeEvents.mapTo(false), changeEvents.let((0, (_observable || _load_observable()).fastDebounce)(CHANGE_TOGGLE_MS)).mapTo(true)); + + const destroyEvents = (0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidDestroy.bind(editor)); + + return cursorPositions.let((0, (_observable || _load_observable()).toggle)(changeToggles)).switchMap((() => { + var _ref = (0, _asyncToGenerator.default)(function* (position) { + return { + editor, + ranges: yield _this._getHighlightedRanges(editor, position) + }; + }); + + return function (_x) { + return _ref.apply(this, arguments); + }; + })()).takeUntil(destroyEvents); + }).subscribe(({ editor, ranges }) => { + if (ranges != null) { + this._highlightRanges(editor, ranges); + } + }); } - async _getHighlightedRanges( - editor: atom$TextEditor, - position: atom$Point, - ): Promise> { - const provider = this._providers.getProviderForEditor(editor); - if (!provider) { - return null; - } - - try { - return await provider.highlight(editor, position); - } catch (e) { - getLogger('code-highlight').error('Error getting code highlights', e); - return null; - } + _getHighlightedRanges(editor, position) { + var _this2 = this; + + return (0, _asyncToGenerator.default)(function* () { + const provider = _this2._providers.getProviderForEditor(editor); + if (!provider) { + return null; + } + + try { + return yield provider.highlight(editor, position); + } catch (e) { + (0, (_log4js || _load_log4js()).getLogger)('code-highlight').error('Error getting code highlights', e); + return null; + } + })(); } - _highlightRanges(editor: atom$TextEditor, ranges: Array): void { + _highlightRanges(editor, ranges) { this._destroyMarkers(); this._markers = ranges.map(range => editor.markBufferRange(range, {})); this._markers.forEach(marker => { editor.decorateMarker(marker, { type: 'highlight', - class: 'code-highlight-marker', + class: 'code-highlight-marker' }); }); } - _isPositionInHighlightedRanges( - editor: atom$TextEditor, - position: atom$Point, - ): boolean { - return this._markers - .map(marker => marker.getBufferRange()) - .some(range => range.containsPoint(position)); + _isPositionInHighlightedRanges(editor, position) { + return this._markers.map(marker => marker.getBufferRange()).some(range => range.containsPoint(position)); } - _destroyMarkers(): void { + _destroyMarkers() { this._markers.splice(0).forEach(marker => marker.destroy()); } - addProvider(provider: CodeHighlightProvider): IDisposable { + addProvider(provider) { return this._providers.addProvider(provider); } @@ -143,3 +156,4 @@ export default class CodeHighlightManager { this._destroyMarkers(); } } +exports.default = CodeHighlightManager; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/main.js index 6bdcf457..1c2b2bb3 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/main.js @@ -1,34 +1,42 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {CodeHighlightProvider} from './types'; - -import createPackage from 'nuclide-commons-atom/createPackage'; -import CodeHighlightManager from './CodeHighlightManager'; +'use strict'; + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _CodeHighlightManager; + +function _load_CodeHighlightManager() { + return _CodeHighlightManager = _interopRequireDefault(require('./CodeHighlightManager')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class Activation { - _codeHighlightManager: CodeHighlightManager; constructor() { - this._codeHighlightManager = new CodeHighlightManager(); + this._codeHighlightManager = new (_CodeHighlightManager || _load_CodeHighlightManager()).default(); } dispose() { this._codeHighlightManager.dispose(); } - addProvider(provider: CodeHighlightProvider): IDisposable { + addProvider(provider) { return this._codeHighlightManager.addProvider(provider); } -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/types.js index 167d70c1..9a390c31 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/lib/types.js @@ -1,20 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -export type CodeHighlightProvider = { - highlight( - editor: atom$TextEditor, - bufferPosition: atom$Point, - ): Promise>, - priority: number, - grammarScopes: Array, -}; +"use strict"; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/spec/CodeHighlightManager-spec.js b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/spec/CodeHighlightManager-spec.js index 0e32da1a..d87c02ea 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-code-highlight/spec/CodeHighlightManager-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-code-highlight/spec/CodeHighlightManager-spec.js @@ -1,3 +1,25 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _os = _interopRequireDefault(require('os')); + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _atom = require('atom'); + +var _CodeHighlightManager; + +function _load_CodeHighlightManager() { + return _CodeHighlightManager = _interopRequireDefault(require('../lib/CodeHighlightManager')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,40 +28,34 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import os from 'os'; -import nuclideUri from 'nuclide-commons/nuclideUri'; -import {Point, Range} from 'atom'; - -import CodeHighlightManager from '../lib/CodeHighlightManager'; - describe('CodeHighlightManager', () => { let manager; let provider; let editor; beforeEach(() => { jasmine.useMockClock(); - waitsForPromise(async () => { - editor = await atom.workspace.open( - nuclideUri.join(os.tmpdir(), 'test.txt'), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + editor = yield atom.workspace.open((_nuclideUri || _load_nuclideUri()).default.join(_os.default.tmpdir(), 'test.txt')); editor.setText('abc\ndef\nghi'); - manager = new CodeHighlightManager(); + manager = new (_CodeHighlightManager || _load_CodeHighlightManager()).default(); provider = { priority: 1, grammarScopes: ['text.plain.null-grammar'], - highlight: (_editor, position) => Promise.resolve([]), + highlight: function (_editor, position) { + return Promise.resolve([]); + } }; manager.addProvider(provider); - }); + })); }); it('updates highlights on cursor move', () => { - const ranges = [new Range([0, 0], [0, 3])]; + const ranges = [new _atom.Range([0, 0], [0, 3])]; const spy = spyOn(provider, 'highlight').andReturn(ranges); // Just opening the editor should trigger highlights. @@ -52,8 +68,8 @@ describe('CodeHighlightManager', () => { waitsFor(() => manager._markers.length === 1); runs(() => { - ranges[0] = new Range([1, 0], [1, 3]); - editor.setCursorBufferPosition(new Point(1, 0)); + ranges[0] = new _atom.Range([1, 0], [1, 3]); + editor.setCursorBufferPosition(new _atom.Point(1, 0)); advanceClock(300); // trigger debounce // Old markers should be cleared immediately. expect(manager._markers.length).toBe(0); @@ -64,13 +80,11 @@ describe('CodeHighlightManager', () => { // If we're still inside the range, don't fire a new event. runs(() => { - editor.setCursorBufferPosition(new Point(1, 1)); + editor.setCursorBufferPosition(new _atom.Point(1, 1)); expect(spy.callCount).toBe(2); }); - waitsForPromise(() => - atom.workspace.open(nuclideUri.join(os.tmpdir(), 'test2.txt')), - ); + waitsForPromise(() => atom.workspace.open((_nuclideUri || _load_nuclideUri()).default.join(_os.default.tmpdir(), 'test2.txt'))); runs(() => { // Opening a new editor should clear out old markers. @@ -80,7 +94,7 @@ describe('CodeHighlightManager', () => { }); it('updates highlights on change', () => { - const ranges = [new Range([0, 0], [0, 1])]; + const ranges = [new _atom.Range([0, 0], [0, 1])]; const spy = spyOn(provider, 'highlight').andReturn(ranges); runs(() => { @@ -99,4 +113,4 @@ describe('CodeHighlightManager', () => { expect(manager._markers.length).toBe(0); }); }); -}); +}); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/getCurrentExecutorId.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/getCurrentExecutorId.js index 37e662b8..4ee4fd43 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/getCurrentExecutorId.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/getCurrentExecutorId.js @@ -1,22 +1,24 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {AppState} from './types'; - -export default function getCurrentExecutorId(state: AppState): ?string { - let {currentExecutorId} = state; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = getCurrentExecutorId; +function getCurrentExecutorId(state) { + let { currentExecutorId } = state; if (currentExecutorId == null) { const firstExecutor = Array.from(state.executors.values())[0]; currentExecutorId = firstExecutor && firstExecutor.id; } return currentExecutorId; -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/main.js index 1eda6a26..1c7ddf44 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/main.js @@ -1,114 +1,132 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type { - AppState, - ConsolePersistedState, - ConsoleService, - SourceInfo, - Message, - OutputProvider, - OutputProviderStatus, - OutputService, - Record, - RegisterExecutorFunction, - WatchEditorFunction, - Store, -} from './types'; -import type {CreatePasteFunction} from './types'; - -import {List} from 'immutable'; -import createPackage from 'nuclide-commons-atom/createPackage'; -import {destroyItemWhere} from 'nuclide-commons-atom/destroyItemWhere'; -import {Observable} from 'rxjs'; -import { - combineEpics, - createEpicMiddleware, -} from 'nuclide-commons/redux-observable'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import featureConfig from 'nuclide-commons-atom/feature-config'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import * as Actions from './redux/Actions'; -import * as Epics from './redux/Epics'; -import Reducers from './redux/Reducers'; -import {Console, WORKSPACE_VIEW_URI} from './ui/Console'; -import invariant from 'assert'; -import {applyMiddleware, createStore} from 'redux'; -import {makeToolbarButtonSpec} from 'nuclide-commons-ui/ToolbarUtils'; - -const MAXIMUM_SERIALIZED_MESSAGES_CONFIG = - 'atom-ide-console.maximumSerializedMessages'; -const MAXIMUM_SERIALIZED_HISTORY_CONFIG = - 'atom-ide-console.maximumSerializedHistory'; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _immutable; + +function _load_immutable() { + return _immutable = require('immutable'); +} + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _destroyItemWhere; + +function _load_destroyItemWhere() { + return _destroyItemWhere = require('nuclide-commons-atom/destroyItemWhere'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _reduxObservable; + +function _load_reduxObservable() { + return _reduxObservable = require('nuclide-commons/redux-observable'); +} + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _Actions; + +function _load_Actions() { + return _Actions = _interopRequireWildcard(require('./redux/Actions')); +} + +var _Epics; + +function _load_Epics() { + return _Epics = _interopRequireWildcard(require('./redux/Epics')); +} + +var _Reducers; + +function _load_Reducers() { + return _Reducers = _interopRequireDefault(require('./redux/Reducers')); +} + +var _Console; + +function _load_Console() { + return _Console = require('./ui/Console'); +} + +var _redux; + +function _load_redux() { + return _redux = require('redux'); +} + +var _ToolbarUtils; + +function _load_ToolbarUtils() { + return _ToolbarUtils = require('nuclide-commons-ui/ToolbarUtils'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const MAXIMUM_SERIALIZED_MESSAGES_CONFIG = 'atom-ide-console.maximumSerializedMessages'; +const MAXIMUM_SERIALIZED_HISTORY_CONFIG = 'atom-ide-console.maximumSerializedHistory'; class Activation { - _disposables: UniversalDisposable; - _rawState: ?Object; - _store: Store; - constructor(rawState: ?Object) { + constructor(rawState) { this._rawState = rawState; - this._disposables = new UniversalDisposable( - atom.contextMenu.add({ - '.console-record': [ - { - label: 'Copy Message', - command: 'console:copy-message', - }, - ], - }), - atom.commands.add('.console-record', 'console:copy-message', event => { - const el = event.target; - if (el == null || typeof el.innerText !== 'string') { - return; - } - atom.clipboard.write(el.innerText); - }), - atom.commands.add('atom-workspace', 'console:clear', () => - this._getStore().dispatch(Actions.clearRecords()), - ), - featureConfig.observe( - 'atom-ide-console.maximumMessageCount', - (maxMessageCount: any) => { - this._getStore().dispatch( - Actions.setMaxMessageCount(maxMessageCount), - ); - }, - ), - Observable.combineLatest( - observableFromSubscribeFunction(cb => - atom.config.observe('editor.fontSize', cb), - ), - featureConfig.observeAsStream('atom-ide-console.consoleFontScale'), - (fontSize, consoleFontScale) => fontSize * parseFloat(consoleFontScale), - ) - .map(Actions.setFontSize) - .subscribe(this._store.dispatch), - this._registerCommandAndOpener(), - ); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.contextMenu.add({ + '.console-record': [{ + label: 'Copy Message', + command: 'console:copy-message' + }] + }), atom.commands.add('.console-record', 'console:copy-message', event => { + const el = event.target; + if (el == null || typeof el.innerText !== 'string') { + return; + } + atom.clipboard.write(el.innerText); + }), atom.commands.add('atom-workspace', 'console:clear', () => this._getStore().dispatch((_Actions || _load_Actions()).clearRecords())), (_featureConfig || _load_featureConfig()).default.observe('atom-ide-console.maximumMessageCount', maxMessageCount => { + this._getStore().dispatch((_Actions || _load_Actions()).setMaxMessageCount(maxMessageCount)); + }), _rxjsBundlesRxMinJs.Observable.combineLatest((0, (_event || _load_event()).observableFromSubscribeFunction)(cb => atom.config.observe('editor.fontSize', cb)), (_featureConfig || _load_featureConfig()).default.observeAsStream('atom-ide-console.consoleFontScale'), (fontSize, consoleFontScale) => fontSize * parseFloat(consoleFontScale)).map((_Actions || _load_Actions()).setFontSize).subscribe(this._store.dispatch), this._registerCommandAndOpener()); } - _getStore(): Store { + _getStore() { if (this._store == null) { const initialState = deserializeAppState(this._rawState); - const epics = Object.keys(Epics) - .map(k => Epics[k]) - .filter(epic => typeof epic === 'function'); - const rootEpic = combineEpics(...epics); - this._store = createStore( - Reducers, - initialState, - applyMiddleware(createEpicMiddleware(rootEpic)), - ); + const epics = Object.keys(_Epics || _load_Epics()).map(k => (_Epics || _load_Epics())[k]).filter(epic => typeof epic === 'function'); + const rootEpic = (0, (_reduxObservable || _load_reduxObservable()).combineEpics)(...epics); + this._store = (0, (_redux || _load_redux()).createStore)((_Reducers || _load_Reducers()).default, initialState, (0, (_redux || _load_redux()).applyMiddleware)((0, (_reduxObservable || _load_reduxObservable()).createEpicMiddleware)(rootEpic))); } return this._store; } @@ -117,80 +135,78 @@ class Activation { this._disposables.dispose(); } - consumeToolBar(getToolBar: toolbar$GetToolbar): void { + consumeToolBar(getToolBar) { const toolBar = getToolBar('nuclide-console'); - toolBar.addButton( - makeToolbarButtonSpec({ - icon: 'terminal', - callback: 'console:toggle', - tooltip: 'Toggle Console', - priority: 700, - }), - ); + toolBar.addButton((0, (_ToolbarUtils || _load_ToolbarUtils()).makeToolbarButtonSpec)({ + icon: 'terminal', + callback: 'console:toggle', + tooltip: 'Toggle Console', + priority: 700 + })); this._disposables.add(() => { toolBar.removeItems(); }); } - consumePasteProvider(provider: any): IDisposable { - const createPaste: CreatePasteFunction = provider.createPaste; - this._getStore().dispatch(Actions.setCreatePasteFunction(createPaste)); - return new UniversalDisposable(() => { + consumePasteProvider(provider) { + const createPaste = provider.createPaste; + this._getStore().dispatch((_Actions || _load_Actions()).setCreatePasteFunction(createPaste)); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { if (this._getStore().getState().createPasteFunction === createPaste) { - this._getStore().dispatch(Actions.setCreatePasteFunction(null)); + this._getStore().dispatch((_Actions || _load_Actions()).setCreatePasteFunction(null)); } }); } - consumeWatchEditor(watchEditor: WatchEditorFunction): IDisposable { - this._getStore().dispatch(Actions.setWatchEditor(watchEditor)); - return new UniversalDisposable(() => { + consumeWatchEditor(watchEditor) { + this._getStore().dispatch((_Actions || _load_Actions()).setWatchEditor(watchEditor)); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { if (this._getStore().getState().watchEditor === watchEditor) { - this._getStore().dispatch(Actions.setWatchEditor(null)); + this._getStore().dispatch((_Actions || _load_Actions()).setWatchEditor(null)); } }); } - provideAutocomplete(): atom$AutocompleteProvider { + provideAutocomplete() { const activation = this; return { labels: ['nuclide-console'], selector: '*', // Copies Chrome devtools and puts history suggestions at the bottom. suggestionPriority: -1, - async getSuggestions(request) { - // History provides suggestion only on exact match to current input. - const prefix = request.editor.getText(); - const history = activation._getStore().getState().history; - // Use a set to remove duplicates. - const seen = new Set(history); - return Array.from(seen) - .filter(text => text.startsWith(prefix)) - .map(text => ({text, replacementPrefix: prefix})); - }, + getSuggestions(request) { + return (0, _asyncToGenerator.default)(function* () { + // History provides suggestion only on exact match to current input. + const prefix = request.editor.getText(); + const history = activation._getStore().getState().history; + // Use a set to remove duplicates. + const seen = new Set(history); + return Array.from(seen).filter(function (text) { + return text.startsWith(prefix); + }).map(function (text) { + return { text, replacementPrefix: prefix }; + }); + })(); + } }; } - _registerCommandAndOpener(): UniversalDisposable { - return new UniversalDisposable( - atom.workspace.addOpener(uri => { - if (uri === WORKSPACE_VIEW_URI) { - return new Console({store: this._getStore()}); - } - }), - () => destroyItemWhere(item => item instanceof Console), - atom.commands.add('atom-workspace', 'console:toggle', () => { - atom.workspace.toggle(WORKSPACE_VIEW_URI); - }), - ); + _registerCommandAndOpener() { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.workspace.addOpener(uri => { + if (uri === (_Console || _load_Console()).WORKSPACE_VIEW_URI) { + return new (_Console || _load_Console()).Console({ store: this._getStore() }); + } + }), () => (0, (_destroyItemWhere || _load_destroyItemWhere()).destroyItemWhere)(item => item instanceof (_Console || _load_Console()).Console), atom.commands.add('atom-workspace', 'console:toggle', () => { + atom.workspace.toggle((_Console || _load_Console()).WORKSPACE_VIEW_URI); + })); } - deserializeConsole(state: ConsolePersistedState): Console { - return new Console({ + deserializeConsole(state) { + return new (_Console || _load_Console()).Console({ store: this._getStore(), initialFilterText: state.filterText, initialEnableRegExpFilter: state.enableRegExpFilter, - initialUnselectedSourceIds: state.unselectedSourceIds, + initialUnselectedSourceIds: state.unselectedSourceIds }); } @@ -205,7 +221,7 @@ class Activation { * package is disabled). This will remove the source from the Console UI's filter list (as long as * there aren't any remaining messages from the source). */ - provideConsole(): ConsoleService { + provideConsole() { // Create a local, nullable reference so that the service consumers don't keep the Activation // instance in memory. let activation = this; @@ -213,64 +229,70 @@ class Activation { activation = null; }); - return (sourceInfo: SourceInfo) => { - invariant(activation != null); + return sourceInfo => { + if (!(activation != null)) { + throw new Error('Invariant violation: "activation != null"'); + } + let disposed; - activation._getStore().dispatch(Actions.registerSource(sourceInfo)); + activation._getStore().dispatch((_Actions || _load_Actions()).registerSource(sourceInfo)); const console = { // TODO: Update these to be (object: any, ...objects: Array): void. - log(object: string): void { - console.append({text: object, level: 'log'}); + log(object) { + console.append({ text: object, level: 'log' }); }, - warn(object: string): void { - console.append({text: object, level: 'warning'}); + warn(object) { + console.append({ text: object, level: 'warning' }); }, - error(object: string): void { - console.append({text: object, level: 'error'}); + error(object) { + console.append({ text: object, level: 'error' }); }, - info(object: string): void { - console.append({text: object, level: 'info'}); + info(object) { + console.append({ text: object, level: 'info' }); }, - success(object: string): void { - console.append({text: object, level: 'success'}); + success(object) { + console.append({ text: object, level: 'success' }); }, - append(message: Message): void { - invariant(activation != null && !disposed); - activation._getStore().dispatch( - Actions.recordReceived({ - text: message.text, - level: message.level, - data: message.data, - tags: message.tags, - scopeName: message.scopeName, - sourceId: sourceInfo.id, - kind: message.kind || 'message', - timestamp: new Date(), // TODO: Allow this to come with the message? - repeatCount: 1, - }), - ); + append(message) { + if (!(activation != null && !disposed)) { + throw new Error('Invariant violation: "activation != null && !disposed"'); + } + + activation._getStore().dispatch((_Actions || _load_Actions()).recordReceived({ + text: message.text, + level: message.level, + data: message.data, + tags: message.tags, + scopeName: message.scopeName, + sourceId: sourceInfo.id, + kind: message.kind || 'message', + timestamp: new Date(), // TODO: Allow this to come with the message? + repeatCount: 1 + })); }, - setStatus(status: OutputProviderStatus): void { - invariant(activation != null && !disposed); - activation - ._getStore() - .dispatch(Actions.updateStatus(sourceInfo.id, status)); + setStatus(status) { + if (!(activation != null && !disposed)) { + throw new Error('Invariant violation: "activation != null && !disposed"'); + } + + activation._getStore().dispatch((_Actions || _load_Actions()).updateStatus(sourceInfo.id, status)); }, - dispose(): void { - invariant(activation != null); + dispose() { + if (!(activation != null)) { + throw new Error('Invariant violation: "activation != null"'); + } + if (!disposed) { disposed = true; - activation - ._getStore() - .dispatch(Actions.removeSource(sourceInfo.id)); + activation._getStore().dispatch((_Actions || _load_Actions()).removeSource(sourceInfo.id)); } - }, + } }; return console; }; } - provideOutputService(): OutputService { + provideOutputService() { // Create a local, nullable reference so that the service consumers don't keep the Activation // instance in memory. let activation = this; @@ -279,23 +301,22 @@ class Activation { }); return { - registerOutputProvider(outputProvider: OutputProvider): IDisposable { - invariant(activation != null, 'Output service used after deactivation'); - activation - ._getStore() - .dispatch(Actions.registerOutputProvider(outputProvider)); - return new UniversalDisposable(() => { + registerOutputProvider(outputProvider) { + if (!(activation != null)) { + throw new Error('Output service used after deactivation'); + } + + activation._getStore().dispatch((_Actions || _load_Actions()).registerOutputProvider(outputProvider)); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { if (activation != null) { - activation - ._getStore() - .dispatch(Actions.unregisterOutputProvider(outputProvider)); + activation._getStore().dispatch((_Actions || _load_Actions()).unregisterOutputProvider(outputProvider)); } }); - }, + } }; } - provideRegisterExecutor(): RegisterExecutorFunction { + provideRegisterExecutor() { // Create a local, nullable reference so that the service consumers don't keep the Activation // instance in memory. let activation = this; @@ -304,71 +325,60 @@ class Activation { }); return executor => { - invariant( - activation != null, - 'Executor registration attempted after deactivation', - ); - activation._getStore().dispatch(Actions.registerExecutor(executor)); - return new UniversalDisposable(() => { + if (!(activation != null)) { + throw new Error('Executor registration attempted after deactivation'); + } + + activation._getStore().dispatch((_Actions || _load_Actions()).registerExecutor(executor)); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { if (activation != null) { - activation._getStore().dispatch(Actions.unregisterExecutor(executor)); + activation._getStore().dispatch((_Actions || _load_Actions()).unregisterExecutor(executor)); } }); }; } - serialize(): Object { + serialize() { if (this._store == null) { return {}; } - const maximumSerializedMessages: number = (featureConfig.get( - MAXIMUM_SERIALIZED_MESSAGES_CONFIG, - ): any); - const maximumSerializedHistory: number = (featureConfig.get( - MAXIMUM_SERIALIZED_HISTORY_CONFIG, - ): any); + const maximumSerializedMessages = (_featureConfig || _load_featureConfig()).default.get(MAXIMUM_SERIALIZED_MESSAGES_CONFIG); + const maximumSerializedHistory = (_featureConfig || _load_featureConfig()).default.get(MAXIMUM_SERIALIZED_HISTORY_CONFIG); return { - records: this._store - .getState() - .records.slice(-maximumSerializedMessages) - .toArray() - .map(record => { - // `Executor` is not serializable. Make sure to remove it first. - const {executor, ...rest} = record; - return rest; - }), - history: this._store.getState().history.slice(-maximumSerializedHistory), + records: this._store.getState().records.slice(-maximumSerializedMessages).toArray().map(record => { + // `Executor` is not serializable. Make sure to remove it first. + const { executor } = record, + rest = _objectWithoutProperties(record, ['executor']); + return rest; + }), + history: this._store.getState().history.slice(-maximumSerializedHistory) }; } } -function deserializeAppState(rawState: ?Object): AppState { +function deserializeAppState(rawState) { return { executors: new Map(), createPasteFunction: null, currentExecutorId: null, - records: - rawState && rawState.records - ? List(rawState.records.map(deserializeRecord)) - : List(), + records: rawState && rawState.records ? (0, (_immutable || _load_immutable()).List)(rawState.records.map(deserializeRecord)) : (0, (_immutable || _load_immutable()).List)(), history: rawState && rawState.history ? rawState.history : [], providers: new Map(), providerStatuses: new Map(), // This value will be replaced with the value form the config. We just use `POSITIVE_INFINITY` // here to conform to the AppState type defintion. - maxMessageCount: Number.POSITIVE_INFINITY, + maxMessageCount: Number.POSITIVE_INFINITY }; } -function deserializeRecord(record: Object): Record { - return { - ...record, - timestamp: parseDate(record.timestamp) || new Date(0), - }; +function deserializeRecord(record) { + return Object.assign({}, record, { + timestamp: parseDate(record.timestamp) || new Date(0) + }); } -function parseDate(raw: ?string): ?Date { +function parseDate(raw) { if (raw == null) { return null; } @@ -376,4 +386,4 @@ function parseDate(raw: ?string): ?Date { return isNaN(date.getTime()) ? null : date; } -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/parseText.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/parseText.js index 19ec535e..8ec09bc3 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/parseText.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/parseText.js @@ -1,3 +1,34 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = parseText; + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _string; + +function _load_string() { + return _string = require('nuclide-commons/string'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,25 +37,17 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; -import * as React from 'react'; -import featureConfig from 'nuclide-commons-atom/feature-config'; - -import {URL_REGEX} from 'nuclide-commons/string'; const DIFF_PATTERN = '\\b[dD][1-9][0-9]{5,}\\b'; const TASK_PATTERN = '\\b[tT]\\d+\\b'; -const FILE_PATH_PATTERN = - '([/A-Za-z_-s0-9.-]+[.][A-Za-z]+)(:([0-9]+))?(:([0-9]+))?'; -const CLICKABLE_PATTERNS = `(${DIFF_PATTERN})|(${TASK_PATTERN})|(${ - URL_REGEX.source -})|${FILE_PATH_PATTERN}`; +const FILE_PATH_PATTERN = '([/A-Za-z_-s0-9.-]+[.][A-Za-z]+)(:([0-9]+))?(:([0-9]+))?'; +const CLICKABLE_PATTERNS = `(${DIFF_PATTERN})|(${TASK_PATTERN})|(${(_string || _load_string()).URL_REGEX.source})|${FILE_PATH_PATTERN}`; const CLICKABLE_RE = new RegExp(CLICKABLE_PATTERNS, 'g'); -function toString(value: mixed): string { +function toString(value) { return typeof value === 'string' ? value : ''; } @@ -34,9 +57,7 @@ function toString(value: mixed): string { * that only they can know (e.g. relative paths output in BUCK messages). For now, however, we'll * just use some pattern settings and hardcode the patterns we care about. */ -export default function parseText( - text: string, -): Array> { +function parseText(text) { const chunks = []; let lastIndex = 0; let index = 0; @@ -49,26 +70,20 @@ export default function parseText( const matchedText = match[0]; // Add all the text since our last match. - chunks.push( - text.slice(lastIndex, CLICKABLE_RE.lastIndex - matchedText.length), - ); + chunks.push(text.slice(lastIndex, CLICKABLE_RE.lastIndex - matchedText.length)); lastIndex = CLICKABLE_RE.lastIndex; let href; let handleOnClick; if (match[1] != null) { // It's a diff - const url = toString( - featureConfig.get('atom-ide-console.diffUrlPattern'), - ); + const url = toString((_featureConfig || _load_featureConfig()).default.get('atom-ide-console.diffUrlPattern')); if (url !== '') { href = url.replace('%s', matchedText); } } else if (match[2] != null) { // It's a task - const url = toString( - featureConfig.get('atom-ide-console.taskUrlPattern'), - ); + const url = toString((_featureConfig || _load_featureConfig()).default.get('atom-ide-console.taskUrlPattern')); if (url !== '') { href = url.replace('%s', matchedText.slice(1)); } @@ -79,27 +94,24 @@ export default function parseText( // It's a file path href = '#'; handleOnClick = () => { - goToLocation(match[5], { + (0, (_goToLocation || _load_goToLocation()).goToLocation)(match[5], { line: match[7] ? parseInt(match[7], 10) - 1 : 0, - column: match[9] ? parseInt(match[9], 10) - 1 : 0, + column: match[9] ? parseInt(match[9], 10) - 1 : 0 }); }; } chunks.push( - // flowlint-next-line sketchy-null-string:off - href ? ( - - {matchedText} - - ) : ( - matchedText - ), - ); + // flowlint-next-line sketchy-null-string:off + href ? _react.createElement( + 'a', + { + key: `r${index}`, + href: href, + target: '_blank', + onClick: handleOnClick }, + matchedText + ) : matchedText); index++; } @@ -108,4 +120,4 @@ export default function parseText( chunks.push(text.slice(lastIndex)); return chunks; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/recordsChanged.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/recordsChanged.js index ab27f72a..8577bdab 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/recordsChanged.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/recordsChanged.js @@ -1,3 +1,22 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = recordsChanged; + +var _idx; + +function _load_idx() { + return _idx = _interopRequireDefault(require('idx')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Check to see if the records have changed. This is optimized to take advantage of the knowledge + * knowledge that record lists are only ever appended. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,25 +25,14 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {DisplayableRecord} from './types'; +function recordsChanged(a, b) { + var _ref, _ref2; -import idx from 'idx'; - -/** - * Check to see if the records have changed. This is optimized to take advantage of the knowledge - * knowledge that record lists are only ever appended. - */ -export default function recordsChanged( - a: Array, - b: Array, -): boolean { - return ( - a.length !== b.length || idx(last(a), _ => _.id) !== idx(last(b), _ => _.id) - ); + return a.length !== b.length || ((_ref = last(a)) != null ? _ref.id : _ref) !== ((_ref2 = last(b)) != null ? _ref2.id : _ref2); } -const last = arr => arr[arr.length - 1]; +const last = arr => arr[arr.length - 1]; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Actions.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Actions.js index 66bf0761..842334b9 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Actions.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Actions.js @@ -1,3 +1,25 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.clearRecords = clearRecords; +exports.recordReceived = recordReceived; +exports.registerExecutor = registerExecutor; +exports.execute = execute; +exports.registerOutputProvider = registerOutputProvider; +exports.registerRecordProvider = registerRecordProvider; +exports.registerSource = registerSource; +exports.unregisterRecordProvider = unregisterRecordProvider; +exports.unregisterOutputProvider = unregisterOutputProvider; +exports.selectExecutor = selectExecutor; +exports.setMaxMessageCount = setMaxMessageCount; +exports.removeSource = removeSource; +exports.unregisterExecutor = unregisterExecutor; +exports.updateStatus = updateStatus; +exports.setCreatePasteFunction = setCreatePasteFunction; +exports.setWatchEditor = setWatchEditor; +exports.setFontSize = setFontSize; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,68 +28,54 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type { - Action, - Executor, - OutputProvider, - OutputProviderStatus, - Record, - RecordProvider, - SourceInfo, - WatchEditorFunction, -} from '../types'; - -import type {CreatePasteFunction} from '../types'; - -export const CLEAR_RECORDS = 'CLEAR_RECORDS'; -export const SET_CREATE_PASTE_FUNCTION = 'SET_CREATE_PASTE_FUNCTION'; -export const SET_WATCH_EDITOR_FUNCTION = 'SET_WATCH_EDITOR_FUNCTION'; -export const REGISTER_EXECUTOR = 'REGISTER_EXECUTOR'; -export const EXECUTE = 'EXECUTE'; -export const REGISTER_RECORD_PROVIDER = 'REGISTER_RECORD_PROVIDER'; -export const SELECT_EXECUTOR = 'SELECT_EXECUTOR'; -export const SET_MAX_MESSAGE_COUNT = 'SET_MAX_MESSAGE_COUNT'; -export const RECORD_RECEIVED = 'RECORD_RECEIVED'; -export const REGISTER_SOURCE = 'REGISTER_SOURCE'; -export const REMOVE_SOURCE = 'REMOVE_SOURCE'; -export const UPDATE_STATUS = 'UPDATE_STATUS'; -export const SET_FONT_SIZE = 'SET_FONT_SIZE'; - -export function clearRecords(): Action { - return {type: CLEAR_RECORDS}; -} - -export function recordReceived(record: Record): Action { +const CLEAR_RECORDS = exports.CLEAR_RECORDS = 'CLEAR_RECORDS'; +const SET_CREATE_PASTE_FUNCTION = exports.SET_CREATE_PASTE_FUNCTION = 'SET_CREATE_PASTE_FUNCTION'; +const SET_WATCH_EDITOR_FUNCTION = exports.SET_WATCH_EDITOR_FUNCTION = 'SET_WATCH_EDITOR_FUNCTION'; +const REGISTER_EXECUTOR = exports.REGISTER_EXECUTOR = 'REGISTER_EXECUTOR'; +const EXECUTE = exports.EXECUTE = 'EXECUTE'; +const REGISTER_RECORD_PROVIDER = exports.REGISTER_RECORD_PROVIDER = 'REGISTER_RECORD_PROVIDER'; +const SELECT_EXECUTOR = exports.SELECT_EXECUTOR = 'SELECT_EXECUTOR'; +const SET_MAX_MESSAGE_COUNT = exports.SET_MAX_MESSAGE_COUNT = 'SET_MAX_MESSAGE_COUNT'; +const RECORD_RECEIVED = exports.RECORD_RECEIVED = 'RECORD_RECEIVED'; +const REGISTER_SOURCE = exports.REGISTER_SOURCE = 'REGISTER_SOURCE'; +const REMOVE_SOURCE = exports.REMOVE_SOURCE = 'REMOVE_SOURCE'; +const UPDATE_STATUS = exports.UPDATE_STATUS = 'UPDATE_STATUS'; +const SET_FONT_SIZE = exports.SET_FONT_SIZE = 'SET_FONT_SIZE'; + +function clearRecords() { + return { type: CLEAR_RECORDS }; +} + +function recordReceived(record) { return { type: RECORD_RECEIVED, - payload: {record}, + payload: { record } }; } -export function registerExecutor(executor: Executor): Action { +function registerExecutor(executor) { return { type: REGISTER_EXECUTOR, - payload: {executor}, + payload: { executor } }; } -export function execute(code: string): Action { +function execute(code) { return { type: EXECUTE, - payload: {code}, + payload: { code } }; } -export function registerOutputProvider(outputProvider: OutputProvider): Action { +function registerOutputProvider(outputProvider) { // Transform the messages into actions and merge them into the action stream. // TODO: Add enabling/disabling of registered source and only subscribe when enabled. That // way, we won't trigger cold observer side-effects when we don't need the results. - return registerRecordProvider({ - ...outputProvider, + return registerRecordProvider(Object.assign({}, outputProvider, { records: outputProvider.messages.map(message => ({ // We duplicate the properties here instead of using spread because Flow (currently) has some // issues with spread. @@ -81,91 +89,82 @@ export function registerOutputProvider(outputProvider: OutputProvider): Action { sourceId: outputProvider.id, scopeName: null, // Eventually, we'll want to allow providers to specify custom timestamps for records. - timestamp: new Date(), - })), - }); + timestamp: new Date() + })) + })); } -export function registerRecordProvider(recordProvider: RecordProvider): Action { +function registerRecordProvider(recordProvider) { return { type: REGISTER_RECORD_PROVIDER, - payload: {recordProvider}, + payload: { recordProvider } }; } -export function registerSource(source: SourceInfo): Action { +function registerSource(source) { return { type: REGISTER_SOURCE, - payload: {source}, + payload: { source } }; } -export function unregisterRecordProvider( - recordProvider: RecordProvider, -): Action { +function unregisterRecordProvider(recordProvider) { return removeSource(recordProvider.id); } -export function unregisterOutputProvider( - outputProvider: OutputProvider, -): Action { +function unregisterOutputProvider(outputProvider) { return removeSource(outputProvider.id); } -export function selectExecutor(executorId: string): Action { +function selectExecutor(executorId) { return { type: SELECT_EXECUTOR, - payload: {executorId}, + payload: { executorId } }; } -export function setMaxMessageCount(maxMessageCount: number): Action { +function setMaxMessageCount(maxMessageCount) { return { type: SET_MAX_MESSAGE_COUNT, - payload: {maxMessageCount}, + payload: { maxMessageCount } }; } -export function removeSource(sourceId: string): Action { +function removeSource(sourceId) { return { type: REMOVE_SOURCE, - payload: {sourceId}, + payload: { sourceId } }; } -export function unregisterExecutor(executor: Executor): Action { +function unregisterExecutor(executor) { return removeSource(executor.id); } -export function updateStatus( - providerId: string, - status: OutputProviderStatus, -): Action { +function updateStatus(providerId, status) { return { type: UPDATE_STATUS, - payload: {providerId, status}, + payload: { providerId, status } }; } -export function setCreatePasteFunction( - createPasteFunction: ?CreatePasteFunction, -): Action { +function setCreatePasteFunction(createPasteFunction) { return { type: SET_CREATE_PASTE_FUNCTION, - payload: {createPasteFunction}, + payload: { createPasteFunction } }; } -export function setWatchEditor(watchEditor: ?WatchEditorFunction): Action { +function setWatchEditor(watchEditor) { return { type: SET_WATCH_EDITOR_FUNCTION, - payload: {watchEditor}, + payload: { watchEditor } }; } -export function setFontSize(fontSize: number): Action { +function setFontSize(fontSize) { return { type: SET_FONT_SIZE, - payload: {fontSize}, + payload: { fontSize } }; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Epics.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Epics.js index 1d2d4f02..4aca056b 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Epics.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Epics.js @@ -1,3 +1,39 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.registerExecutorEpic = registerExecutorEpic; +exports.executeEpic = executeEpic; +exports.registerRecordProviderEpic = registerRecordProviderEpic; + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _Actions; + +function _load_Actions() { + return _Actions = _interopRequireWildcard(require('./Actions')); +} + +var _getCurrentExecutorId; + +function _load_getCurrentExecutorId() { + return _getCurrentExecutorId = _interopRequireDefault(require('../getCurrentExecutorId')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +/** + * Register a record provider for every executor. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,41 +42,28 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {Action, Store} from '../types'; -import type {ActionsObservable} from 'nuclide-commons/redux-observable'; +function registerExecutorEpic(actions, store) { + return actions.ofType((_Actions || _load_Actions()).REGISTER_EXECUTOR).map(action => { + if (!(action.type === (_Actions || _load_Actions()).REGISTER_EXECUTOR)) { + throw new Error('Invariant violation: "action.type === Actions.REGISTER_EXECUTOR"'); + } -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import * as Actions from './Actions'; -import getCurrentExecutorId from '../getCurrentExecutorId'; -import invariant from 'assert'; -import {Observable} from 'rxjs'; - -/** - * Register a record provider for every executor. - */ -export function registerExecutorEpic( - actions: ActionsObservable, - store: Store, -): Observable { - return actions.ofType(Actions.REGISTER_EXECUTOR).map(action => { - invariant(action.type === Actions.REGISTER_EXECUTOR); - const {executor} = action.payload; - return Actions.registerRecordProvider({ + const { executor } = action.payload; + return (_Actions || _load_Actions()).registerRecordProvider({ id: executor.id, // $FlowIssue: Flow is having some trouble with the spread here. - records: executor.output.map(message => ({ - ...message, + records: executor.output.map(message => Object.assign({}, message, { kind: 'response', sourceId: executor.id, scopeName: null, // The output won't be in the language's grammar. // Eventually, we'll want to allow providers to specify custom timestamps for records. timestamp: new Date(), - executor, - })), + executor + })) }); }); } @@ -48,78 +71,72 @@ export function registerExecutorEpic( /** * Execute the provided code using the current executor. */ -export function executeEpic( - actions: ActionsObservable, - store: Store, -): Observable { - return actions.ofType(Actions.EXECUTE).flatMap(action => { - invariant(action.type === Actions.EXECUTE); - const {code} = action.payload; - const currentExecutorId = getCurrentExecutorId(store.getState()); +function executeEpic(actions, store) { + return actions.ofType((_Actions || _load_Actions()).EXECUTE).flatMap(action => { + if (!(action.type === (_Actions || _load_Actions()).EXECUTE)) { + throw new Error('Invariant violation: "action.type === Actions.EXECUTE"'); + } + + const { code } = action.payload; + const currentExecutorId = (0, (_getCurrentExecutorId || _load_getCurrentExecutorId()).default)(store.getState()); // flowlint-next-line sketchy-null-string:off - invariant(currentExecutorId); + + if (!currentExecutorId) { + throw new Error('Invariant violation: "currentExecutorId"'); + } const executor = store.getState().executors.get(currentExecutorId); - invariant(executor != null); + + if (!(executor != null)) { + throw new Error('Invariant violation: "executor != null"'); + } // TODO: Is this the best way to do this? Might want to go through nuclide-executors and have // that register output sources? - return ( - Observable.of( - Actions.recordReceived({ - // Eventually, we'll want to allow providers to specify custom timestamps for records. - timestamp: new Date(), - sourceId: currentExecutorId, - kind: 'request', - level: 'log', - text: code, - scopeName: executor.scopeName, - data: null, - repeatCount: 1, - }), - ) - // Execute the code as a side-effect. - .finally(() => { - executor.send(code); - }) - ); + + + return _rxjsBundlesRxMinJs.Observable.of((_Actions || _load_Actions()).recordReceived({ + // Eventually, we'll want to allow providers to specify custom timestamps for records. + timestamp: new Date(), + sourceId: currentExecutorId, + kind: 'request', + level: 'log', + text: code, + scopeName: executor.scopeName, + data: null, + repeatCount: 1 + })) + // Execute the code as a side-effect. + .finally(() => { + executor.send(code); + }); }); } -export function registerRecordProviderEpic( - actions: ActionsObservable, - store: Store, -): Observable { - return actions.ofType(Actions.REGISTER_RECORD_PROVIDER).flatMap(action => { - invariant(action.type === Actions.REGISTER_RECORD_PROVIDER); - const {recordProvider} = action.payload; +function registerRecordProviderEpic(actions, store) { + return actions.ofType((_Actions || _load_Actions()).REGISTER_RECORD_PROVIDER).flatMap(action => { + if (!(action.type === (_Actions || _load_Actions()).REGISTER_RECORD_PROVIDER)) { + throw new Error('Invariant violation: "action.type === Actions.REGISTER_RECORD_PROVIDER"'); + } + + const { recordProvider } = action.payload; // Transform the messages into actions and merge them into the action stream. // TODO: Add enabling/disabling of registered source and only subscribe when enabled. That // way, we won't trigger cold observer side-effects when we don't need the results. - const messageActions = recordProvider.records.map(Actions.recordReceived); + const messageActions = recordProvider.records.map((_Actions || _load_Actions()).recordReceived); // TODO: Can this be delayed until sometime after registration? - const statusActions = - typeof recordProvider.observeStatus === 'function' - ? observableFromSubscribeFunction(recordProvider.observeStatus).map( - status => Actions.updateStatus(recordProvider.id, status), - ) - : Observable.empty(); - - const unregisteredEvents = actions - .ofType(Actions.REMOVE_SOURCE) - .filter(a => { - invariant(a.type === Actions.REMOVE_SOURCE); - return a.payload.sourceId === recordProvider.id; - }); - - return Observable.merge( - Observable.of( - Actions.registerSource({...recordProvider, name: recordProvider.id}), - ), - messageActions, - statusActions, - ).takeUntil(unregisteredEvents); + const statusActions = typeof recordProvider.observeStatus === 'function' ? (0, (_event || _load_event()).observableFromSubscribeFunction)(recordProvider.observeStatus).map(status => (_Actions || _load_Actions()).updateStatus(recordProvider.id, status)) : _rxjsBundlesRxMinJs.Observable.empty(); + + const unregisteredEvents = actions.ofType((_Actions || _load_Actions()).REMOVE_SOURCE).filter(a => { + if (!(a.type === (_Actions || _load_Actions()).REMOVE_SOURCE)) { + throw new Error('Invariant violation: "a.type === Actions.REMOVE_SOURCE"'); + } + + return a.payload.sourceId === recordProvider.id; + }); + + return _rxjsBundlesRxMinJs.Observable.merge(_rxjsBundlesRxMinJs.Observable.of((_Actions || _load_Actions()).registerSource(Object.assign({}, recordProvider, { name: recordProvider.id }))), messageActions, statusActions).takeUntil(unregisteredEvents); }); -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Reducers.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Reducers.js index 310e591e..2254f550 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Reducers.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/redux/Reducers.js @@ -1,3 +1,30 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = accumulateState; + +var _immutable; + +function _load_immutable() { + return _immutable = require('immutable'); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _Actions; + +function _load_Actions() { + return _Actions = _interopRequireWildcard(require('./Actions')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,190 +33,149 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {Action, AppState, Record} from '../types'; - -import {List} from 'immutable'; -import {arrayEqual} from 'nuclide-commons/collection'; -import * as Actions from './Actions'; - -const RECORD_PROPERTIES_TO_COMPARE = [ - 'text', - 'level', - 'scopeName', - 'sourceId', - 'kind', -]; - -function shouldAccumulateRecordCount( - recordA: Record, - recordB: Record, -): boolean { - if ( - String(recordA.sourceId) - .toLowerCase() - .includes('debugger') || - String(recordB.sourceId) - .toLowerCase() - .includes('debugger') - ) { +const RECORD_PROPERTIES_TO_COMPARE = ['text', 'level', 'scopeName', 'sourceId', 'kind']; + +function shouldAccumulateRecordCount(recordA, recordB) { + if (String(recordA.sourceId).toLowerCase().includes('debugger') || String(recordB.sourceId).toLowerCase().includes('debugger')) { return false; } - const areRelevantPropertiesEqual = RECORD_PROPERTIES_TO_COMPARE.every( - prop => recordA[prop] === recordB[prop], - ); + const areRelevantPropertiesEqual = RECORD_PROPERTIES_TO_COMPARE.every(prop => recordA[prop] === recordB[prop]); // if data exists, we should not accumulate this into the previous record const doesDataExist = recordA.data || recordB.data; const recATags = recordA.tags; const recBTags = recordB.tags; - const areTagsEqual = - (!recATags && !recBTags) || - (recATags && recBTags && arrayEqual(recATags, recBTags)); - - return ( - areRelevantPropertiesEqual && - !Boolean(doesDataExist) && - Boolean(areTagsEqual) - ); + const areTagsEqual = !recATags && !recBTags || recATags && recBTags && (0, (_collection || _load_collection()).arrayEqual)(recATags, recBTags); + + return areRelevantPropertiesEqual && !Boolean(doesDataExist) && Boolean(areTagsEqual); } -export default function accumulateState( - state: AppState, - action: Action, -): AppState { +function accumulateState(state, action) { switch (action.type) { - case Actions.RECORD_RECEIVED: { - const {record} = action.payload; - let nextRecords = state.records; - - // check if the message is exactly the same as the previous one, if so - // we add a count to it. - const lastRecord = nextRecords.last(); - if ( - lastRecord != null && - shouldAccumulateRecordCount(lastRecord, record) - ) { - // Update the last record. Don't use `splice()` because that's O(n) - const updatedRecord: Record = { - ...lastRecord, - repeatCount: lastRecord.repeatCount + 1, - timestamp: record.timestamp, - }; - nextRecords = nextRecords.pop().push(updatedRecord); - } else { - nextRecords = nextRecords.push(record); - } + case (_Actions || _load_Actions()).RECORD_RECEIVED: + { + const { record } = action.payload; + let nextRecords = state.records; - if (nextRecords.size > state.maxMessageCount) { - // We could only have gone over by one. - nextRecords = nextRecords.shift(); - } + // check if the message is exactly the same as the previous one, if so + // we add a count to it. + const lastRecord = nextRecords.last(); + if (lastRecord != null && shouldAccumulateRecordCount(lastRecord, record)) { + // Update the last record. Don't use `splice()` because that's O(n) + const updatedRecord = Object.assign({}, lastRecord, { + repeatCount: lastRecord.repeatCount + 1, + timestamp: record.timestamp + }); + nextRecords = nextRecords.pop().push(updatedRecord); + } else { + nextRecords = nextRecords.push(record); + } + + if (nextRecords.size > state.maxMessageCount) { + // We could only have gone over by one. + nextRecords = nextRecords.shift(); + } - return { - ...state, - records: nextRecords, - }; - } - case Actions.SET_MAX_MESSAGE_COUNT: { - const {maxMessageCount} = action.payload; - if (maxMessageCount <= 0) { - return state; + return Object.assign({}, state, { + records: nextRecords + }); + } + case (_Actions || _load_Actions()).SET_MAX_MESSAGE_COUNT: + { + const { maxMessageCount } = action.payload; + if (maxMessageCount <= 0) { + return state; + } + return Object.assign({}, state, { + maxMessageCount, + records: state.records.slice(-maxMessageCount) + }); + } + case (_Actions || _load_Actions()).REGISTER_SOURCE: + { + const { source } = action.payload; + return Object.assign({}, state, { + providers: new Map(state.providers).set(source.id, Object.assign({}, source, { + name: source.name || source.id + })) + }); + } + case (_Actions || _load_Actions()).CLEAR_RECORDS: + { + return Object.assign({}, state, { + records: (0, (_immutable || _load_immutable()).List)() + }); + } + case (_Actions || _load_Actions()).REGISTER_EXECUTOR: + { + const { executor } = action.payload; + return Object.assign({}, state, { + executors: new Map(state.executors).set(executor.id, executor) + }); + } + case (_Actions || _load_Actions()).SELECT_EXECUTOR: + { + const { executorId } = action.payload; + return Object.assign({}, state, { + currentExecutorId: executorId + }); + } + case (_Actions || _load_Actions()).REMOVE_SOURCE: + { + const { sourceId } = action.payload; + const providers = new Map(state.providers); + const providerStatuses = new Map(state.providerStatuses); + const executors = new Map(state.executors); + providers.delete(sourceId); + providerStatuses.delete(sourceId); + executors.delete(sourceId); + return Object.assign({}, state, { + providers, + providerStatuses, + executors + }); + } + case (_Actions || _load_Actions()).UPDATE_STATUS: + { + const { status, providerId } = action.payload; + return Object.assign({}, state, { + providerStatuses: new Map(state.providerStatuses).set(providerId, status) + }); + } + case (_Actions || _load_Actions()).EXECUTE: + { + const command = action.payload.code; + return Object.assign({}, state, { + history: state.history.concat(command).slice(-1000) + }); + } + case (_Actions || _load_Actions()).SET_CREATE_PASTE_FUNCTION: + { + const { createPasteFunction } = action.payload; + return Object.assign({}, state, { + createPasteFunction + }); + } + case (_Actions || _load_Actions()).SET_WATCH_EDITOR_FUNCTION: + { + const { watchEditor } = action.payload; + return Object.assign({}, state, { + watchEditor + }); + } + case (_Actions || _load_Actions()).SET_FONT_SIZE: + { + const { fontSize } = action.payload; + return Object.assign({}, state, { + fontSize + }); } - return { - ...state, - maxMessageCount, - records: state.records.slice(-maxMessageCount), - }; - } - case Actions.REGISTER_SOURCE: { - const {source} = action.payload; - return { - ...state, - providers: new Map(state.providers).set(source.id, { - ...source, - name: source.name || source.id, - }), - }; - } - case Actions.CLEAR_RECORDS: { - return { - ...state, - records: List(), - }; - } - case Actions.REGISTER_EXECUTOR: { - const {executor} = action.payload; - return { - ...state, - executors: new Map(state.executors).set(executor.id, executor), - }; - } - case Actions.SELECT_EXECUTOR: { - const {executorId} = action.payload; - return { - ...state, - currentExecutorId: executorId, - }; - } - case Actions.REMOVE_SOURCE: { - const {sourceId} = action.payload; - const providers = new Map(state.providers); - const providerStatuses = new Map(state.providerStatuses); - const executors = new Map(state.executors); - providers.delete(sourceId); - providerStatuses.delete(sourceId); - executors.delete(sourceId); - return { - ...state, - providers, - providerStatuses, - executors, - }; - } - case Actions.UPDATE_STATUS: { - const {status, providerId} = action.payload; - return { - ...state, - providerStatuses: new Map(state.providerStatuses).set( - providerId, - status, - ), - }; - } - case Actions.EXECUTE: { - const command = action.payload.code; - return { - ...state, - history: state.history.concat(command).slice(-1000), - }; - } - case Actions.SET_CREATE_PASTE_FUNCTION: { - const {createPasteFunction} = action.payload; - return { - ...state, - createPasteFunction, - }; - } - case Actions.SET_WATCH_EDITOR_FUNCTION: { - const {watchEditor} = action.payload; - return { - ...state, - watchEditor, - }; - } - case Actions.SET_FONT_SIZE: { - const {fontSize} = action.payload; - return { - ...state, - fontSize, - }; - } } return state; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/types.js index cd5a52d8..a726efc4 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/types.js @@ -1,312 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Observable} from 'rxjs'; -import type {List} from 'immutable'; -import type {EvaluationResult} from 'nuclide-commons-ui/TextRenderer'; -import type {ExpansionResult} from 'nuclide-commons-ui/LazyNestedValueComponent'; - -// The type of the object passed to your package's `consumeConsole()` function. -export type ConsoleService = (options: SourceInfo) => ConsoleApi; - -// The console API. An object of this type is returned when you invoke the function provided by the -// console service. -export type ConsoleApi = { - // The primary means of interacting with the console. - // TODO: Update these to be `(object: any, ...objects: Array): void` to allow for logging objects. - log(object: string, _: void): void, - error(object: string, _: void): void, - warn(object: string, _: void): void, - info(object: string, _: void): void, - success(object: string, _: void): void, - - // A generic API for sending a message of any level (log, error, etc.). - append(message: Message): void, - - // Dispose of the console. Invoke this when your package is disabled. - dispose(): void, - - // Set the status of the source. See "Stoppable Sources" below. - setStatus(status: OutputProviderStatus): void, -}; - -// A type representing the possible values for the `console.setStatus()` API. -export type OutputProviderStatus = 'starting' | 'running' | 'stopped'; - -// The shape of the argument to the `ConsoleService` function. -export type SourceInfo = { - id: string, // A unique identifier representing this source. - name: string, // A human-readable name for the source. This will be used in the UI. - - // `start()` and `stop()` functions can optionally be provided. See [User-Controllable Console - // Sources](https://github.com/facebook-atom/atom-ide-ui/blob/master/docs/console.md#user-controllable-console-sources) - // for more information. - start?: () => void, - stop?: () => void, -}; - -// Message levels. For use with the `console.append()` API. -export type Level = - | 'info' - | 'log' - | 'warning' - | 'error' - | 'debug' - | 'success' - | Color; -type Color = - | 'red' - | 'orange' - | 'yellow' - | 'green' - | 'blue' - | 'purple' - | 'violet' - | 'rainbow'; - -// A message object, for use with the `console.append()` API. -export type Message = { - text: string, - level: Level, - - // Internally used properties. These are subject to change so don't use em! - data?: EvaluationResult, - tags?: ?Array, - kind?: ?MessageKind, - scopeName?: ?string, -}; - -// -// -// The following types are part of deprecated APIs and shouldn't be used outside of this package. -// -// - -type BasicOutputProvider = { - messages: Observable, - // The source can't be part of the message because we want to be able to populate a filter menu - // before we even have any messages. - id: string, - getProperties?: (objectId: string) => Observable, -}; - -type ControllableOutputProviderProps = { - observeStatus(callback: (status: OutputProviderStatus) => mixed): IDisposable, - start(): void, - stop(): void, -}; - -type ControllableOutputProvider = BasicOutputProvider & - ControllableOutputProviderProps; - -export type OutputProvider = BasicOutputProvider | ControllableOutputProvider; - -export type OutputService = { - registerOutputProvider(outputProvider: OutputProvider): IDisposable, -}; - -// -// -// The following types aren't part of public API but rather are used within the package. -// -// - -type MessageKind = 'message' | 'request' | 'response'; - -// A normalized type used internally to represent all possible kinds of messages. Responses and -// Messages are transformed into these. -// Make sure areRecordsIdentical in reducers.js is up to date with these fields -export type Record = { - text: string, - level: Level, - tags?: ?Array, - repeatCount: number, - - kind: MessageKind, - sourceId: string, - scopeName: ?string, - data?: ?EvaluationResult, - timestamp: Date, - - executor?: Executor, -}; - -export type AppState = { - createPasteFunction: ?CreatePasteFunction, - currentExecutorId: ?string, - executors: Map, - maxMessageCount: number, - // We use Immutable for the records list so that adding an item is O(1). However, rendering the - // items after the addition is O(n), so it's important that we schedule and throttle our renders - // or we'll lose the benefit of an O(1) insertion. - records: List, - history: Array, - providers: Map, - providerStatuses: Map, -}; - -// A special type used internally by the Console component to represent each record that is -// displayed with its height. This is stored at the component level since the expansion state of any -// record (which affects its height) is unique to each Console pane (whereas the records themselves -// are shared between all Console panes). The height is needed for partial rendering. -export type DisplayableRecord = { - id: number, - record: Record, - height: number, - expansionStateId: Object, -}; - -export type RecordHeightChangeHandler = ( - recordId: number, - newHeight: number, - callback: () => void, -) => void; - -export type Source = { - id: string, - name: string, - status: OutputProviderStatus, - start?: () => void, - stop?: () => void, -}; - -type BasicRecordProvider = { - records: Observable, - id: string, - getProperties?: (objectId: string) => Observable, -}; - -type ControllableRecordProvider = BasicRecordProvider & - ControllableOutputProviderProps; - -export type RecordProvider = BasicRecordProvider | ControllableRecordProvider; - -// Serialized state specific to each instance of the console view. For example, each instance has -// its own, distinct filter, so that's here. They don't, however, have distinct records, so they -// aren't. -export type ConsolePersistedState = { - deserializer: 'nuclide.Console', - filterText?: string, - enableRegExpFilter?: boolean, - unselectedSourceIds?: Array, -}; - -export type Executor = { - id: string, - name: string, - send(message: string): void, - output: Observable, - scopeName: string, - provideSymbols?: (prefix: string) => Array, - getProperties?: (objectId: string) => Observable, -}; - -export type RegisterExecutorFunction = (executor: Executor) => IDisposable; - -export type WatchEditorFunction = ( - editor: atom$TextEditor, - labels?: Array, -) => IDisposable; - -export type PasteOptions = { - language?: ?string, - title?: ?string, -}; - -export type CreatePasteFunction = ( - message: string, - options: PasteOptions, - source: string, -) => Promise; - -export type Store = { - getState(): AppState, - dispatch(action: Action): void, -}; - -export type Action = - | { - type: 'CLEAR_RECORDS', - } - | { - type: 'REGISTER_EXECUTOR', - payload: { - executor: Executor, - }, - } - | { - type: 'EXECUTE', - payload: { - code: string, - }, - } - | { - type: 'RECORD_RECEIVED', - payload: { - record: Record, - }, - } - | { - type: 'REGISTER_RECORD_PROVIDER', - payload: { - recordProvider: RecordProvider, - }, - } - | { - type: 'REGISTER_SOURCE', - payload: { - source: SourceInfo, - }, - } - | { - type: 'REMOVE_SOURCE', - payload: { - sourceId: string, - }, - } - | { - type: 'SELECT_EXECUTOR', - payload: { - executorId: string, - }, - } - | { - type: 'SET_CREATE_PASTE_FUNCTION', - payload: { - createPasteFunction: ?CreatePasteFunction, - }, - } - | { - type: 'SET_WATCH_EDITOR_FUNCTION', - payload: { - watchEditor: ?WatchEditorFunction, - }, - } - | { - type: 'SET_MAX_MESSAGE_COUNT', - payload: { - maxMessageCount: number, - }, - } - | { - type: 'UPDATE_STATUS', - payload: { - providerId: string, - status: OutputProviderStatus, - }, - } - | { - type: 'SET_FONT_SIZE', - payload: { - fontSize: number, - }, - }; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/Console.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/Console.js index 78cdb32a..c315fe7d 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/Console.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/Console.js @@ -1,3 +1,208 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Console = exports.WORKSPACE_VIEW_URI = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +let serializeRecordObject = (() => { + var _ref2 = (0, _asyncToGenerator.default)(function* (executor, visited, data, text, level) { + const getText = function (record) { + let indent = ''; + for (let i = 0; i < level; i++) { + indent += '\t'; + } + return indent + (record.description != null ? record.description : record.value != null ? record.value : ''); + }; + + if (data.objectId == null) { + // Leaf node. + return text + getText(data); + } + + const id = data.objectId; + if (visited.has(id)) { + // Guard against cycles. + return text; + } + + visited.add(id); + + if (executor.getProperties == null) { + return text; + } + + const childProperties = (yield executor.getProperties(id).toPromise()) || []; + const serializedProps = childProperties.map(function (childProp) { + return serializeRecordObject(executor, visited, childProp.value, '', level + 1); + }); + return getText(data) + '\n' + (yield Promise.all(serializedProps)).join('\n'); + }); + + return function serializeRecordObject(_x, _x2, _x3, _x4, _x5) { + return _ref2.apply(this, arguments); + }; +})(); + +let createPaste = (() => { + var _ref3 = (0, _asyncToGenerator.default)(function* (createPasteImpl, records) { + const linePromises = records.filter(function (displayable) { + return displayable.record.kind === 'message' || displayable.record.kind === 'request' || displayable.record.kind === 'response'; + }).map((() => { + var _ref4 = (0, _asyncToGenerator.default)(function* (displayable) { + const record = displayable.record; + const level = record.level != null ? record.level.toString().toUpperCase() : 'LOG'; + const timestamp = record.timestamp.toLocaleString(); + let text = record.text || record.data && record.data.value || ERROR_TRANSCRIBING_MESSAGE; + + if (record.kind === 'response' && record.data != null && record.data.objectId != null && record.data.objectId !== '') { + const executor = record.executor; + if (executor != null) { + // If the record has a data object, and the object has an ID, + // recursively expand the nodes of the object and serialize it + // for the paste. + text = yield serializeRecordObject(executor, new Set(), record.data, '', 0); + } + } + + return `[${level}][${record.sourceId}][${timestamp}]\t ${text}`; + }); + + return function (_x8) { + return _ref4.apply(this, arguments); + }; + })()); + + const lines = (yield Promise.all(linePromises)).join('\n'); + + if (lines === '') { + // Can't create an empty paste! + atom.notifications.addWarning('There is nothing in your console to Paste! Check your console filters and try again.'); + return; + } + + atom.notifications.addInfo('Creating Paste...'); + + try { + const uri = yield createPasteImpl(lines, { + title: 'Nuclide Console Paste' + }, 'console paste'); + atom.notifications.addSuccess(`Created Paste at ${uri}`); + } catch (error) { + if (error.stdout == null) { + atom.notifications.addError(`Failed to create paste: ${String(error.message || error)}`); + return; + } + const errorMessages = error.stdout.trim().split('\n').map(JSON.parse).map(function (e) { + return e.message; + }); + atom.notifications.addError('Failed to create paste', { + detail: errorMessages.join('\n'), + dismissable: true + }); + } + }); + + return function createPaste(_x6, _x7) { + return _ref3.apply(this, arguments); + }; +})(); + +var _observePaneItemVisibility; + +function _load_observePaneItemVisibility() { + return _observePaneItemVisibility = _interopRequireDefault(require('nuclide-commons-atom/observePaneItemVisibility')); +} + +var _Model; + +function _load_Model() { + return _Model = _interopRequireDefault(require('nuclide-commons/Model')); +} + +var _shallowequal; + +function _load_shallowequal() { + return _shallowequal = _interopRequireDefault(require('shallowequal')); +} + +var _bindObservableAsProps; + +function _load_bindObservableAsProps() { + return _bindObservableAsProps = require('nuclide-commons-ui/bindObservableAsProps'); +} + +var _renderReactRoot; + +function _load_renderReactRoot() { + return _renderReactRoot = require('nuclide-commons-ui/renderReactRoot'); +} + +var _memoizeUntilChanged; + +function _load_memoizeUntilChanged() { + return _memoizeUntilChanged = _interopRequireDefault(require('nuclide-commons/memoizeUntilChanged')); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _RegExpFilter; + +function _load_RegExpFilter() { + return _RegExpFilter = require('nuclide-commons-ui/RegExpFilter'); +} + +var _getCurrentExecutorId; + +function _load_getCurrentExecutorId() { + return _getCurrentExecutorId = _interopRequireDefault(require('../getCurrentExecutorId')); +} + +var _Actions; + +function _load_Actions() { + return _Actions = _interopRequireWildcard(require('../redux/Actions')); +} + +var _ConsoleView; + +function _load_ConsoleView() { + return _ConsoleView = _interopRequireDefault(require('./ConsoleView')); +} + +var _immutable; + +function _load_immutable() { + return _immutable = require('immutable'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// Other Nuclide packages (which cannot import this) depend on this URI. If this +// needs to be changed, grep for CONSOLE_VIEW_URI and ensure that the URIs match. + + +// +// State unique to this particular Console instance +// /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,71 +211,15 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ /* eslint-env browser */ -import type { - ConsolePersistedState, - DisplayableRecord, - OutputProviderStatus, - Record, - Source, - Store, - SourceInfo, -} from '../types'; -import type {CreatePasteFunction} from '../types'; -import type {RegExpFilterChange} from 'nuclide-commons-ui/RegExpFilter'; -import type {Executor} from '../types'; - -import observePaneItemVisibility from 'nuclide-commons-atom/observePaneItemVisibility'; -import Model from 'nuclide-commons/Model'; -import shallowEqual from 'shallowequal'; -import {bindObservableAsProps} from 'nuclide-commons-ui/bindObservableAsProps'; -import {renderReactRoot} from 'nuclide-commons-ui/renderReactRoot'; -import memoizeUntilChanged from 'nuclide-commons/memoizeUntilChanged'; -import {toggle} from 'nuclide-commons/observable'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {nextAnimationFrame} from 'nuclide-commons/observable'; -import {getFilterPattern} from 'nuclide-commons-ui/RegExpFilter'; -import getCurrentExecutorId from '../getCurrentExecutorId'; -import * as Actions from '../redux/Actions'; -import ConsoleView from './ConsoleView'; -import {List} from 'immutable'; -import * as React from 'react'; -import {Observable, ReplaySubject} from 'rxjs'; - -type Options = { - store: Store, - initialFilterText?: string, - initialEnableRegExpFilter?: boolean, - initialUnselectedSourceIds?: Array, -}; - -// -// State unique to this particular Console instance -// -type State = { - displayableRecords: Array, - filterText: string, - enableRegExpFilter: boolean, - unselectedSourceIds: Array, -}; - -type BoundActionCreators = { - execute: (code: string) => void, - selectExecutor: (executorId: string) => void, - clearRecords: () => void, -}; +const WORKSPACE_VIEW_URI = exports.WORKSPACE_VIEW_URI = 'atom://nuclide/console'; -// Other Nuclide packages (which cannot import this) depend on this URI. If this -// needs to be changed, grep for CONSOLE_VIEW_URI and ensure that the URIs match. -export const WORKSPACE_VIEW_URI = 'atom://nuclide/console'; - -const ERROR_TRANSCRIBING_MESSAGE = - "// Nuclide couldn't find the right text to display"; +const ERROR_TRANSCRIBING_MESSAGE = "// Nuclide couldn't find the right text to display"; const INITIAL_RECORD_HEIGHT = 21; /** @@ -78,59 +227,95 @@ const INITIAL_RECORD_HEIGHT = 21; * (via `getElement()`). That view is bound to both global state (from the store) and view-specific * state (from this instance's `_model`). */ -export class Console { - _actionCreators: BoundActionCreators; +class Console { - // Associates Records with their display state (height, expansionStateId). - _displayableRecords: WeakMap; + constructor(options) { + var _this = this; + + this._getSourcesMemoized = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(getSources, opts => opts, (a, b) => (0, (_shallowequal || _load_shallowequal()).default)(a, b)); + + this._resetAllFilters = () => { + this._selectSources(this._getSources().map(s => s.id)); + this._model.setState({ filterText: '' }); + }; + + this._createPaste = (0, _asyncToGenerator.default)(function* () { + const displayableRecords = _this._getDisplayableRecords(); + const createPasteImpl = _this._store.getState().createPasteFunction; + if (createPasteImpl == null) { + return; + } + return createPaste(createPasteImpl, displayableRecords); + }); + + this._selectSources = selectedSourceIds => { + const sourceIds = this._getSources().map(source => source.id); + const unselectedSourceIds = sourceIds.filter(sourceId => selectedSourceIds.indexOf(sourceId) === -1); + this._model.setState({ unselectedSourceIds }); + }; + + this._updateFilter = change => { + const { text, isRegExp } = change; + this._model.setState({ + filterText: text, + enableRegExpFilter: isRegExp + }); + }; + + this._handleDisplayableRecordHeightChange = (recordId, newHeight, callback) => { + const { records } = this._store.getState(); + const nextDisplayableRecords = Array(records.size); + records.forEach((record, i) => { + let displayableRecord = this._toDisplayableRecord(record); + if (displayableRecord.id === recordId) { + // Update the record with the new height. + displayableRecord = Object.assign({}, displayableRecord, { + height: newHeight + }); + this._displayableRecords.set(record, displayableRecord); + } + nextDisplayableRecords[i] = displayableRecord; + }); - _nextRecordId: number; - _titleChanges: Observable; - _model: Model; - _store: Store; - _element: ?HTMLElement; - _destroyed: ReplaySubject; + this._model.setState({ displayableRecords: nextDisplayableRecords }); + requestAnimationFrame(callback); + }; - constructor(options: Options) { const { store, initialFilterText, initialEnableRegExpFilter, - initialUnselectedSourceIds, + initialUnselectedSourceIds } = options; - this._model = new Model({ + this._model = new (_Model || _load_Model()).default({ displayableRecords: [], filterText: initialFilterText == null ? '' : initialFilterText, enableRegExpFilter: Boolean(initialEnableRegExpFilter), - unselectedSourceIds: - initialUnselectedSourceIds == null ? [] : initialUnselectedSourceIds, + unselectedSourceIds: initialUnselectedSourceIds == null ? [] : initialUnselectedSourceIds }); this._store = store; this._nextRecordId = 0; this._displayableRecords = new WeakMap(); - this._destroyed = new ReplaySubject(1); - - this._titleChanges = Observable.combineLatest( - this._model.toObservable(), - // $FlowIssue: Flow doesn't know about Symbol.observable - Observable.from(store), - ) - .takeUntil(this._destroyed) - .map(() => this.getTitle()) - .distinctUntilChanged() - .share(); + this._destroyed = new _rxjsBundlesRxMinJs.ReplaySubject(1); + + this._titleChanges = _rxjsBundlesRxMinJs.Observable.combineLatest(this._model.toObservable(), + // $FlowIssue: Flow doesn't know about Symbol.observable + _rxjsBundlesRxMinJs.Observable.from(store)).takeUntil(this._destroyed).map(() => this.getTitle()).distinctUntilChanged().share(); } - getIconName(): string { + // Associates Records with their display state (height, expansionStateId). + + + getIconName() { return 'terminal'; } // Get the pane item's title. If there's only one source selected, we'll use that to make a more // descriptive title. - getTitle(): string { + getTitle() { const enabledProviderCount = this._store.getState().providers.size; - const {unselectedSourceIds} = this._model.state; + const { unselectedSourceIds } = this._model.state; // Calling `_getSources()` is (currently) expensive because it needs to search all the records // for sources that have been disabled but still have records. We try to avoid calling it if we @@ -142,9 +327,7 @@ export class Console { // If there's only one source selected, use its name in the tab title. const sources = this._getSources(); if (sources.length - unselectedSourceIds.length === 1) { - const selectedSource = sources.find( - source => unselectedSourceIds.indexOf(source.id) === -1, - ); + const selectedSource = sources.find(source => unselectedSourceIds.indexOf(source.id) === -1); if (selectedSource) { return `Console: ${selectedSource.name}`; } @@ -153,21 +336,21 @@ export class Console { return 'Console'; } - getDefaultLocation(): string { + getDefaultLocation() { return 'bottom'; } - getURI(): string { + getURI() { return WORKSPACE_VIEW_URI; } - onDidChangeTitle(callback: (title: string) => mixed): IDisposable { - return new UniversalDisposable(this._titleChanges.subscribe(callback)); + onDidChangeTitle(callback) { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(this._titleChanges.subscribe(callback)); } - _getSources(): Array { - const {providers, providerStatuses, records} = this._store.getState(); - return this._getSourcesMemoized({providers, providerStatuses, records}); + _getSources() { + const { providers, providerStatuses, records } = this._store.getState(); + return this._getSourcesMemoized({ providers, providerStatuses, records }); } // Memoize `getSources()`. Unfortunately, since we look for unrepresented sources in the record @@ -175,203 +358,118 @@ export class Console { // TODO: Consider removing records when their source is removed. This will likely require adding // the ability to enable and disable sources so, for example, when the debugger is no longer // active, it still remains in the source list. - _getSourcesMemoized = memoizeUntilChanged( - getSources, - opts => opts, - (a, b) => shallowEqual(a, b), - ); - destroy(): void { + + destroy() { this._destroyed.next(); } - copy(): Console { + copy() { return new Console({ store: this._store, initialFilterText: this._model.state.filterText, initialEnableRegExpFilter: this._model.state.enableRegExpFilter, - initialUnselectedSourceIds: this._model.state.unselectedSourceIds, + initialUnselectedSourceIds: this._model.state.unselectedSourceIds }); } - _getBoundActionCreators(): BoundActionCreators { + _getBoundActionCreators() { if (this._actionCreators == null) { this._actionCreators = { execute: code => { - this._store.dispatch(Actions.execute(code)); + this._store.dispatch((_Actions || _load_Actions()).execute(code)); }, selectExecutor: executorId => { - this._store.dispatch(Actions.selectExecutor(executorId)); + this._store.dispatch((_Actions || _load_Actions()).selectExecutor(executorId)); }, clearRecords: () => { - this._store.dispatch(Actions.clearRecords()); - }, + this._store.dispatch((_Actions || _load_Actions()).clearRecords()); + } }; } return this._actionCreators; } - _resetAllFilters = (): void => { - this._selectSources(this._getSources().map(s => s.id)); - this._model.setState({filterText: ''}); - }; - - _createPaste = async (): Promise => { - const displayableRecords = this._getDisplayableRecords(); - const createPasteImpl = this._store.getState().createPasteFunction; - if (createPasteImpl == null) { - return; - } - return createPaste(createPasteImpl, displayableRecords); - }; - - _getFilterInfo(): { - invalid: boolean, - selectedSourceIds: Array, - filteredRecords: Array, - } { - const {pattern, invalid} = getFilterPattern( - this._model.state.filterText, - this._model.state.enableRegExpFilter, - ); + _getFilterInfo() { + const { pattern, invalid } = (0, (_RegExpFilter || _load_RegExpFilter()).getFilterPattern)(this._model.state.filterText, this._model.state.enableRegExpFilter); const sources = this._getSources(); - const selectedSourceIds = sources - .map(source => source.id) - .filter( - sourceId => - this._model.state.unselectedSourceIds.indexOf(sourceId) === -1, - ); - - const filteredRecords = filterRecords( - this._getDisplayableRecords(), - selectedSourceIds, - pattern, - sources.length !== selectedSourceIds.length, - ); + const selectedSourceIds = sources.map(source => source.id).filter(sourceId => this._model.state.unselectedSourceIds.indexOf(sourceId) === -1); + + const filteredRecords = filterRecords(this._getDisplayableRecords(), selectedSourceIds, pattern, sources.length !== selectedSourceIds.length); return { invalid, selectedSourceIds, - filteredRecords, + filteredRecords }; } - getElement(): HTMLElement { + getElement() { if (this._element != null) { return this._element; } const actionCreators = this._getBoundActionCreators(); - const props = Observable.combineLatest( - this._model.toObservable(), - // $FlowIssue: Flow doesn't know about Symbol.observable - Observable.from(this._store), - ) - // Don't re-render when the console isn't visible. - .let(toggle(observePaneItemVisibility(this))) - .audit(() => nextAnimationFrame) - .map(([localState, globalState]) => { - const { - invalid, - selectedSourceIds, - filteredRecords, - } = this._getFilterInfo(); - - const currentExecutorId = getCurrentExecutorId(globalState); - const currentExecutor = - currentExecutorId != null - ? globalState.executors.get(currentExecutorId) - : null; - - return { - invalidFilterInput: invalid, - execute: actionCreators.execute, - selectExecutor: actionCreators.selectExecutor, - clearRecords: actionCreators.clearRecords, - createPaste: - globalState.createPasteFunction == null ? null : this._createPaste, - watchEditor: globalState.watchEditor, - currentExecutor, - unselectedSourceIds: localState.unselectedSourceIds, - filterText: localState.filterText, - enableRegExpFilter: localState.enableRegExpFilter, - displayableRecords: filteredRecords, - filteredRecordCount: - globalState.records.size - filteredRecords.length, - history: globalState.history, - sources: this._getSources(), - selectedSourceIds, - selectSources: this._selectSources, - executors: globalState.executors, - getProvider: id => globalState.providers.get(id), - updateFilter: this._updateFilter, - onDisplayableRecordHeightChange: this - ._handleDisplayableRecordHeightChange, - resetAllFilters: this._resetAllFilters, - fontSize: globalState.fontSize, - }; - }); + const props = _rxjsBundlesRxMinJs.Observable.combineLatest(this._model.toObservable(), + // $FlowIssue: Flow doesn't know about Symbol.observable + _rxjsBundlesRxMinJs.Observable.from(this._store)) + // Don't re-render when the console isn't visible. + .let((0, (_observable || _load_observable()).toggle)((0, (_observePaneItemVisibility || _load_observePaneItemVisibility()).default)(this))).audit(() => (_observable || _load_observable()).nextAnimationFrame).map(([localState, globalState]) => { + const { + invalid, + selectedSourceIds, + filteredRecords + } = this._getFilterInfo(); + + const currentExecutorId = (0, (_getCurrentExecutorId || _load_getCurrentExecutorId()).default)(globalState); + const currentExecutor = currentExecutorId != null ? globalState.executors.get(currentExecutorId) : null; + + return { + invalidFilterInput: invalid, + execute: actionCreators.execute, + selectExecutor: actionCreators.selectExecutor, + clearRecords: actionCreators.clearRecords, + createPaste: globalState.createPasteFunction == null ? null : this._createPaste, + watchEditor: globalState.watchEditor, + currentExecutor, + unselectedSourceIds: localState.unselectedSourceIds, + filterText: localState.filterText, + enableRegExpFilter: localState.enableRegExpFilter, + displayableRecords: filteredRecords, + filteredRecordCount: globalState.records.size - filteredRecords.length, + history: globalState.history, + sources: this._getSources(), + selectedSourceIds, + selectSources: this._selectSources, + executors: globalState.executors, + getProvider: id => globalState.providers.get(id), + updateFilter: this._updateFilter, + onDisplayableRecordHeightChange: this._handleDisplayableRecordHeightChange, + resetAllFilters: this._resetAllFilters, + fontSize: globalState.fontSize + }; + }); - const StatefulConsoleView = bindObservableAsProps(props, ConsoleView); - return (this._element = renderReactRoot()); + const StatefulConsoleView = (0, (_bindObservableAsProps || _load_bindObservableAsProps()).bindObservableAsProps)(props, (_ConsoleView || _load_ConsoleView()).default); + return this._element = (0, (_renderReactRoot || _load_renderReactRoot()).renderReactRoot)(_react.createElement(StatefulConsoleView, null)); } - serialize(): ConsolePersistedState { + serialize() { const { filterText, enableRegExpFilter, - unselectedSourceIds, + unselectedSourceIds } = this._model.state; return { deserializer: 'nuclide.Console', filterText, enableRegExpFilter, - unselectedSourceIds, + unselectedSourceIds }; } - _selectSources = (selectedSourceIds: Array): void => { - const sourceIds = this._getSources().map(source => source.id); - const unselectedSourceIds = sourceIds.filter( - sourceId => selectedSourceIds.indexOf(sourceId) === -1, - ); - this._model.setState({unselectedSourceIds}); - }; - - _updateFilter = (change: RegExpFilterChange): void => { - const {text, isRegExp} = change; - this._model.setState({ - filterText: text, - enableRegExpFilter: isRegExp, - }); - }; - - _handleDisplayableRecordHeightChange = ( - recordId: number, - newHeight: number, - callback: () => void, - ): void => { - const {records} = this._store.getState(); - const nextDisplayableRecords = Array(records.size); - records.forEach((record, i) => { - let displayableRecord = this._toDisplayableRecord(record); - if (displayableRecord.id === recordId) { - // Update the record with the new height. - displayableRecord = { - ...displayableRecord, - height: newHeight, - }; - this._displayableRecords.set(record, displayableRecord); - } - nextDisplayableRecords[i] = displayableRecord; - }); - - this._model.setState({displayableRecords: nextDisplayableRecords}); - requestAnimationFrame(callback); - }; - - _getDisplayableRecords(): Array { - const {records} = this._store.getState(); + _getDisplayableRecords() { + const { records } = this._store.getState(); const displayableRecords = Array(records.size); records.forEach((record, i) => { displayableRecords[i] = this._toDisplayableRecord(record); @@ -384,7 +482,7 @@ export class Console { * per-Console instance because the same record can have different heights in different * containers. */ - _toDisplayableRecord(record: Record): DisplayableRecord { + _toDisplayableRecord(record) { const displayableRecord = this._displayableRecords.get(record); if (displayableRecord != null) { return displayableRecord; @@ -393,34 +491,28 @@ export class Console { id: this._nextRecordId++, record, height: INITIAL_RECORD_HEIGHT, - expansionStateId: {}, + expansionStateId: {} }; this._displayableRecords.set(record, newDisplayableRecord); return newDisplayableRecord; } } -function getSources(options: { - records: List, - providers: Map, - providerStatuses: Map, -}): Array { - const {providers, providerStatuses, records} = options; +exports.Console = Console; +function getSources(options) { + const { providers, providerStatuses, records } = options; // Convert the providers to a map of sources. - const mapOfSources = new Map( - Array.from(providers.entries()).map(([k, provider]) => { - const source = { - id: provider.id, - name: provider.id, - status: providerStatuses.get(provider.id) || 'stopped', - start: - typeof provider.start === 'function' ? provider.start : undefined, - stop: typeof provider.stop === 'function' ? provider.stop : undefined, - }; - return [k, source]; - }), - ); + const mapOfSources = new Map(Array.from(providers.entries()).map(([k, provider]) => { + const source = { + id: provider.id, + name: provider.id, + status: providerStatuses.get(provider.id) || 'stopped', + start: typeof provider.start === 'function' ? provider.start : undefined, + stop: typeof provider.stop === 'function' ? provider.stop : undefined + }; + return [k, source]; + })); // Some providers may have been unregistered, but still have records. Add sources for them too. // TODO: Iterating over all the records to get this every time we get a new record is inefficient. @@ -431,7 +523,7 @@ function getSources(options: { name: record.sourceId, status: 'stopped', start: undefined, - stop: undefined, + stop: undefined }); } }); @@ -439,165 +531,18 @@ function getSources(options: { return Array.from(mapOfSources.values()); } -function filterRecords( - displayableRecords: Array, - selectedSourceIds: Array, - filterPattern: ?RegExp, - filterSources: boolean, -): Array { +function filterRecords(displayableRecords, selectedSourceIds, filterPattern, filterSources) { if (!filterSources && filterPattern == null) { return displayableRecords; } - return displayableRecords.filter(({record}) => { + return displayableRecords.filter(({ record }) => { // Only filter regular messages if (record.kind !== 'message') { return true; } const sourceMatches = selectedSourceIds.indexOf(record.sourceId) !== -1; - return ( - sourceMatches && - (filterPattern == null || filterPattern.test(record.text)) - ); + return sourceMatches && (filterPattern == null || filterPattern.test(record.text)); }); -} - -async function serializeRecordObject( - executor: Executor, - visited: Set, - data: { - objectId?: string, - description?: string, - value?: string, - }, - text: string, - level: number, -): Promise { - const getText = record => { - let indent = ''; - for (let i = 0; i < level; i++) { - indent += '\t'; - } - return ( - indent + - (record.description != null - ? record.description - : record.value != null ? record.value : '') - ); - }; - - if (data.objectId == null) { - // Leaf node. - return text + getText(data); - } - - const id = data.objectId; - if (visited.has(id)) { - // Guard against cycles. - return text; - } - - visited.add(id); - - if (executor.getProperties == null) { - return text; - } - - const childProperties = (await executor.getProperties(id).toPromise()) || []; - const serializedProps = childProperties.map(childProp => { - return serializeRecordObject( - executor, - visited, - childProp.value, - '', - level + 1, - ); - }); - return getText(data) + '\n' + (await Promise.all(serializedProps)).join('\n'); -} - -async function createPaste( - createPasteImpl: CreatePasteFunction, - records: Array, -): Promise { - const linePromises = records - .filter( - displayable => - displayable.record.kind === 'message' || - displayable.record.kind === 'request' || - displayable.record.kind === 'response', - ) - .map(async displayable => { - const record = displayable.record; - const level = - record.level != null ? record.level.toString().toUpperCase() : 'LOG'; - const timestamp = record.timestamp.toLocaleString(); - let text = - record.text || - (record.data && record.data.value) || - ERROR_TRANSCRIBING_MESSAGE; - - if ( - record.kind === 'response' && - record.data != null && - record.data.objectId != null && - record.data.objectId !== '' - ) { - const executor = record.executor; - if (executor != null) { - // If the record has a data object, and the object has an ID, - // recursively expand the nodes of the object and serialize it - // for the paste. - text = await serializeRecordObject( - executor, - new Set(), - record.data, - '', - 0, - ); - } - } - - return `[${level}][${record.sourceId}][${timestamp}]\t ${text}`; - }); - - const lines = (await Promise.all(linePromises)).join('\n'); - - if (lines === '') { - // Can't create an empty paste! - atom.notifications.addWarning( - 'There is nothing in your console to Paste! Check your console filters and try again.', - ); - return; - } - - atom.notifications.addInfo('Creating Paste...'); - - try { - const uri = await createPasteImpl( - lines, - { - title: 'Nuclide Console Paste', - }, - 'console paste', - ); - atom.notifications.addSuccess(`Created Paste at ${uri}`); - } catch (error) { - if (error.stdout == null) { - atom.notifications.addError( - `Failed to create paste: ${String(error.message || error)}`, - ); - return; - } - const errorMessages = error.stdout - .trim() - .split('\n') - .map(JSON.parse) - .map(e => e.message); - atom.notifications.addError('Failed to create paste', { - detail: errorMessages.join('\n'), - dismissable: true, - }); - } -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleHeader.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleHeader.js index ba280b4e..7496be96 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleHeader.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleHeader.js @@ -1,178 +1,213 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Source} from '../types'; -import type {RegExpFilterChange} from 'nuclide-commons-ui/RegExpFilter'; - -import {LoadingSpinner} from 'nuclide-commons-ui/LoadingSpinner'; -import * as React from 'react'; -import {ModalMultiSelect} from 'nuclide-commons-ui/ModalMultiSelect'; -import RegExpFilter from 'nuclide-commons-ui/RegExpFilter'; -import {Toolbar} from 'nuclide-commons-ui/Toolbar'; -import {ToolbarLeft} from 'nuclide-commons-ui/ToolbarLeft'; -import {ToolbarRight} from 'nuclide-commons-ui/ToolbarRight'; -import addTooltip from 'nuclide-commons-ui/addTooltip'; - -import {Button, ButtonSizes} from 'nuclide-commons-ui/Button'; -import invariant from 'assert'; - -type Props = { - clear: () => void, - createPaste: ?() => Promise, - invalidFilterInput: boolean, - enableRegExpFilter: boolean, - onFilterChange: (change: RegExpFilterChange) => void, - selectedSourceIds: Array, - sources: Array, - onSelectedSourcesChange: (sourceIds: Array) => void, - filterText: string, -}; - -export default class ConsoleHeader extends React.Component { - _handleClearButtonClick = (event: SyntheticMouseEvent<>): void => { - this.props.clear(); - }; - - _handleCreatePasteButtonClick = (event: SyntheticMouseEvent<>): void => { - if (this.props.createPaste != null) { - this.props.createPaste(); - } - }; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _LoadingSpinner; + +function _load_LoadingSpinner() { + return _LoadingSpinner = require('nuclide-commons-ui/LoadingSpinner'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _ModalMultiSelect; + +function _load_ModalMultiSelect() { + return _ModalMultiSelect = require('nuclide-commons-ui/ModalMultiSelect'); +} + +var _RegExpFilter; + +function _load_RegExpFilter() { + return _RegExpFilter = _interopRequireDefault(require('nuclide-commons-ui/RegExpFilter')); +} - _handleFilterChange = (value: RegExpFilterChange): void => { - this.props.onFilterChange(value); - }; +var _Toolbar; + +function _load_Toolbar() { + return _Toolbar = require('nuclide-commons-ui/Toolbar'); +} + +var _ToolbarLeft; + +function _load_ToolbarLeft() { + return _ToolbarLeft = require('nuclide-commons-ui/ToolbarLeft'); +} + +var _ToolbarRight; + +function _load_ToolbarRight() { + return _ToolbarRight = require('nuclide-commons-ui/ToolbarRight'); +} + +var _addTooltip; + +function _load_addTooltip() { + return _addTooltip = _interopRequireDefault(require('nuclide-commons-ui/addTooltip')); +} - _renderProcessControlButton(source: Source): ?React.Element { +var _Button; + +function _load_Button() { + return _Button = require('nuclide-commons-ui/Button'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +class ConsoleHeader extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._handleClearButtonClick = event => { + this.props.clear(); + }, this._handleCreatePasteButtonClick = event => { + if (this.props.createPaste != null) { + this.props.createPaste(); + } + }, this._handleFilterChange = value => { + this.props.onFilterChange(value); + }, this._renderOption = optionProps => { + const { option } = optionProps; + const source = this.props.sources.find(s => s.id === option.value); + + if (!(source != null)) { + throw new Error('Invariant violation: "source != null"'); + } + + const startingSpinner = source.status !== 'starting' ? null : _react.createElement((_LoadingSpinner || _load_LoadingSpinner()).LoadingSpinner, { + className: 'inline-block console-process-starting-spinner', + size: 'EXTRA_SMALL' + }); + return _react.createElement( + 'span', + null, + option.label, + startingSpinner, + this._renderProcessControlButton(source) + ); + }, _temp; + } + + _renderProcessControlButton(source) { let action; let label; let icon; switch (source.status) { case 'starting': - case 'running': { - action = source.stop; - label = 'Stop Process'; - icon = 'primitive-square'; - break; - } - case 'stopped': { - action = source.start; - label = 'Start Process'; - icon = 'triangle-right'; - break; - } + case 'running': + { + action = source.stop; + label = 'Stop Process'; + icon = 'primitive-square'; + break; + } + case 'stopped': + { + action = source.start; + label = 'Start Process'; + icon = 'triangle-right'; + break; + } } if (action == null) { return; } const clickHandler = event => { event.stopPropagation(); - invariant(action != null); + + if (!(action != null)) { + throw new Error('Invariant violation: "action != null"'); + } + action(); }; - return ( - + return _react.createElement( + (_Button || _load_Button()).Button, + { + className: 'pull-right console-process-control-button', + icon: icon, + onClick: clickHandler }, + label ); } - _renderOption = (optionProps: { - option: {label: string, value: string}, - }): React.Element => { - const {option} = optionProps; - const source = this.props.sources.find(s => s.id === option.value); - invariant(source != null); - const startingSpinner = - source.status !== 'starting' ? null : ( - - ); - return ( - - {option.label} - {startingSpinner} - {this._renderProcessControlButton(source)} - + render() { + const options = this.props.sources.slice().sort((a, b) => sortAlpha(a.name, b.name)).map(source => ({ + label: source.id, + value: source.name + })); + + const sourceButton = options.length === 0 ? null : _react.createElement((_ModalMultiSelect || _load_ModalMultiSelect()).ModalMultiSelect, { + labelComponent: MultiSelectLabel, + optionComponent: this._renderOption, + size: (_Button || _load_Button()).ButtonSizes.SMALL, + options: options, + value: this.props.selectedSourceIds, + onChange: this.props.onSelectedSourcesChange, + className: 'inline-block' + }); + + const pasteButton = this.props.createPaste == null ? null : _react.createElement( + (_Button || _load_Button()).Button, + { + className: 'inline-block', + size: (_Button || _load_Button()).ButtonSizes.SMALL, + onClick: this._handleCreatePasteButtonClick, + ref: (0, (_addTooltip || _load_addTooltip()).default)({ + title: 'Creates a Paste from the current contents of the console' + }) }, + 'Create Paste' ); - }; - - render(): React.Node { - const options = this.props.sources - .slice() - .sort((a, b) => sortAlpha(a.name, b.name)) - .map(source => ({ - label: source.id, - value: source.name, - })); - - const sourceButton = - options.length === 0 ? null : ( - - ); - const pasteButton = - this.props.createPaste == null ? null : ( - - ); - - return ( - - - {sourceButton} - - - - {pasteButton} - - - + return _react.createElement( + (_Toolbar || _load_Toolbar()).Toolbar, + { location: 'top' }, + _react.createElement( + (_ToolbarLeft || _load_ToolbarLeft()).ToolbarLeft, + null, + sourceButton, + _react.createElement((_RegExpFilter || _load_RegExpFilter()).default, { + value: { + text: this.props.filterText, + isRegExp: this.props.enableRegExpFilter, + invalid: this.props.invalidFilterInput + }, + onChange: this._handleFilterChange + }) + ), + _react.createElement( + (_ToolbarRight || _load_ToolbarRight()).ToolbarRight, + null, + pasteButton, + _react.createElement( + (_Button || _load_Button()).Button, + { + size: (_Button || _load_Button()).ButtonSizes.SMALL, + onClick: this._handleClearButtonClick }, + 'Clear' + ) + ) ); } } -function sortAlpha(a: string, b: string): number { +exports.default = ConsoleHeader; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function sortAlpha(a, b) { const aLower = a.toLowerCase(); const bLower = b.toLowerCase(); if (aLower < bLower) { @@ -183,15 +218,13 @@ function sortAlpha(a: string, b: string): number { return 0; } -type LabelProps = { - selectedOptions: Array<{value: string, label: string}>, -}; - -function MultiSelectLabel(props: LabelProps): React.Element { - const {selectedOptions} = props; - const label = - selectedOptions.length === 1 - ? selectedOptions[0].label - : `${selectedOptions.length} Sources`; - return Showing: {label}; -} +function MultiSelectLabel(props) { + const { selectedOptions } = props; + const label = selectedOptions.length === 1 ? selectedOptions[0].label : `${selectedOptions.length} Sources`; + return _react.createElement( + 'span', + null, + 'Showing: ', + label + ); +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleView.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleView.js index 54028937..e3773960 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleView.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/ConsoleView.js @@ -1,3 +1,90 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _debounce; + +function _load_debounce() { + return _debounce = _interopRequireDefault(require('nuclide-commons/debounce')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _FilteredMessagesReminder; + +function _load_FilteredMessagesReminder() { + return _FilteredMessagesReminder = _interopRequireDefault(require('./FilteredMessagesReminder')); +} + +var _OutputTable; + +function _load_OutputTable() { + return _OutputTable = _interopRequireDefault(require('./OutputTable')); +} + +var _ConsoleHeader; + +function _load_ConsoleHeader() { + return _ConsoleHeader = _interopRequireDefault(require('./ConsoleHeader')); +} + +var _InputArea; + +function _load_InputArea() { + return _InputArea = _interopRequireDefault(require('./InputArea')); +} + +var _PromptButton; + +function _load_PromptButton() { + return _PromptButton = _interopRequireDefault(require('./PromptButton')); +} + +var _NewMessagesNotification; + +function _load_NewMessagesNotification() { + return _NewMessagesNotification = _interopRequireDefault(require('./NewMessagesNotification')); +} + +var _shallowequal; + +function _load_shallowequal() { + return _shallowequal = _interopRequireDefault(require('shallowequal')); +} + +var _recordsChanged; + +function _load_recordsChanged() { + return _recordsChanged = _interopRequireDefault(require('../recordsChanged')); +} + +var _StyleSheet; + +function _load_StyleSheet() { + return _StyleSheet = _interopRequireDefault(require('nuclide-commons-ui/StyleSheet')); +} + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// Maximum time (ms) for the console to try scrolling to the bottom. /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,97 +93,89 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type { - DisplayableRecord, - Executor, - OutputProvider, - RecordHeightChangeHandler, - Source, - WatchEditorFunction, -} from '../types'; -import type {RegExpFilterChange} from 'nuclide-commons-ui/RegExpFilter'; - -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import debounce from 'nuclide-commons/debounce'; -import * as React from 'react'; -import {Observable} from 'rxjs'; -import FilteredMessagesReminder from './FilteredMessagesReminder'; -import OutputTable from './OutputTable'; -import ConsoleHeader from './ConsoleHeader'; -import InputArea from './InputArea'; -import PromptButton from './PromptButton'; -import NewMessagesNotification from './NewMessagesNotification'; -import invariant from 'assert'; -import shallowEqual from 'shallowequal'; -import recordsChanged from '../recordsChanged'; -import StyleSheet from 'nuclide-commons-ui/StyleSheet'; -import classnames from 'classnames'; - -type Props = { - displayableRecords: Array, - history: Array, - clearRecords: () => void, - createPaste: ?() => Promise, - watchEditor: ?WatchEditorFunction, - execute: (code: string) => void, - currentExecutor: ?Executor, - executors: Map, - invalidFilterInput: boolean, - enableRegExpFilter: boolean, - selectedSourceIds: Array, - selectExecutor: (executorId: string) => void, - selectSources: (sourceIds: Array) => void, - sources: Array, - updateFilter: (change: RegExpFilterChange) => void, - getProvider: (id: string) => ?OutputProvider, - onDisplayableRecordHeightChange: RecordHeightChangeHandler, - filteredRecordCount: number, - filterText: string, - resetAllFilters: () => void, - fontSize: number, -}; - -type State = { - unseenMessages: boolean, - promptBufferChanged: boolean, -}; - -// Maximum time (ms) for the console to try scrolling to the bottom. const MAXIMUM_SCROLLING_TIME = 3000; let count = 0; -export default class ConsoleView extends React.Component { - _disposables: UniversalDisposable; - _isScrolledNearBottom: boolean; - _id: number; +class ConsoleView extends _react.Component { - // Used when _scrollToBottom is called. The console optimizes message loading - // so scrolling to the bottom once doesn't always scroll to the bottom since - // more messages can be loaded after. - _isScrollingToBottom: boolean; - _scrollingThrottle: rxjs$Subscription; + constructor(props) { + super(props); - _outputTable: ?OutputTable; + this._getExecutor = id => { + return this.props.executors.get(id); + }; + + this._getProvider = id => { + return this.props.getProvider(id); + }; + + this._executePrompt = code => { + this.props.execute(code); + // Makes the console to scroll to the bottom. + this._isScrolledNearBottom = true; + }; + + this._handleScroll = (offsetHeight, scrollHeight, scrollTop) => { + this._handleScrollEnd(offsetHeight, scrollHeight, scrollTop); + }; + + this._handleOutputTable = ref => { + this._outputTable = ref; + }; + + this._scrollToBottom = () => { + if (!this._outputTable) { + return; + } + + this._outputTable.scrollToBottom(); + + this.setState({ unseenMessages: false }); + }; + + this._startScrollToBottom = () => { + if (!this._isScrollingToBottom) { + this._isScrollingToBottom = true; + + this._scrollingThrottle = _rxjsBundlesRxMinJs.Observable.timer(MAXIMUM_SCROLLING_TIME).subscribe(() => { + this._isScrollingToBottom = false; + }); + } + + this._scrollToBottom(); + }; + + this._stopScrollToBottom = () => { + this._isScrollingToBottom = false; + this._scrollingThrottle.unsubscribe(); + }; + + this._shouldScrollToBottom = () => { + return this._isScrolledNearBottom || this._isScrollingToBottom; + }; - constructor(props: Props) { - super(props); this.state = { unseenMessages: false, - promptBufferChanged: false, + promptBufferChanged: false }; - this._disposables = new UniversalDisposable(); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(); this._isScrolledNearBottom = true; this._isScrollingToBottom = false; - (this: any)._handleScrollEnd = debounce(this._handleScrollEnd, 100); + this._handleScrollEnd = (0, (_debounce || _load_debounce()).default)(this._handleScrollEnd, 100); this._id = count++; } - componentDidMount(): void { + // Used when _scrollToBottom is called. The console optimizes message loading + // so scrolling to the bottom once doesn't always scroll to the bottom since + // more messages can be loaded after. + + + componentDidMount() { // Wait for `` to render itself via react-virtualized before scrolling and // re-measuring; Otherwise, the scrolled location will be inaccurate, preventing the Console // from auto-scrolling. @@ -108,215 +187,166 @@ export default class ConsoleView extends React.Component { }); } - componentWillUnmount(): void { + componentWillUnmount() { this._disposables.dispose(); } - componentDidUpdate(prevProps: Props): void { + componentDidUpdate(prevProps) { // If records are added while we're scrolled to the bottom (or very very close, at least), // automatically scroll. - if ( - this._isScrolledNearBottom && - recordsChanged( - prevProps.displayableRecords, - this.props.displayableRecords, - ) - ) { + if (this._isScrolledNearBottom && (0, (_recordsChanged || _load_recordsChanged()).default)(prevProps.displayableRecords, this.props.displayableRecords)) { this._startScrollToBottom(); } } - _renderPromptButton(): React.Element { - invariant(this.props.currentExecutor != null); - const {currentExecutor} = this.props; + _renderPromptButton() { + if (!(this.props.currentExecutor != null)) { + throw new Error('Invariant violation: "this.props.currentExecutor != null"'); + } + + const { currentExecutor } = this.props; const options = Array.from(this.props.executors.values()).map(executor => ({ id: executor.id, - label: executor.name, + label: executor.name })); - return ( - - ); + return _react.createElement((_PromptButton || _load_PromptButton()).default, { + value: currentExecutor.id, + onChange: this.props.selectExecutor, + options: options, + children: currentExecutor.name + }); } - _isScrolledToBottom( - offsetHeight: number, - scrollHeight: number, - scrollTop: number, - ): boolean { + _isScrolledToBottom(offsetHeight, scrollHeight, scrollTop) { return scrollHeight - (offsetHeight + scrollTop) < 5; } - componentWillReceiveProps(nextProps: Props): void { + componentWillReceiveProps(nextProps) { // If the messages were cleared, hide the notification. if (nextProps.displayableRecords.length === 0) { this._isScrolledNearBottom = true; - this.setState({unseenMessages: false}); + this.setState({ unseenMessages: false }); } else if ( - // If we receive new messages after we've scrolled away from the bottom, show the "new - // messages" notification. - !this._isScrolledNearBottom && - recordsChanged( - this.props.displayableRecords, - nextProps.displayableRecords, - ) - ) { - this.setState({unseenMessages: true}); + // If we receive new messages after we've scrolled away from the bottom, show the "new + // messages" notification. + !this._isScrolledNearBottom && (0, (_recordsChanged || _load_recordsChanged()).default)(this.props.displayableRecords, nextProps.displayableRecords)) { + this.setState({ unseenMessages: true }); } } - shouldComponentUpdate(nextProps: Props, nextState: State): boolean { - return ( - !shallowEqual(this.props, nextProps) || - !shallowEqual(this.state, nextState) - ); + shouldComponentUpdate(nextProps, nextState) { + return !(0, (_shallowequal || _load_shallowequal()).default)(this.props, nextProps) || !(0, (_shallowequal || _load_shallowequal()).default)(this.state, nextState); } - _getExecutor = (id: string): ?Executor => { - return this.props.executors.get(id); - }; - - _getProvider = (id: string): ?OutputProvider => { - return this.props.getProvider(id); - }; - - render(): React.Node { - return ( -
- - - {/* - We need an extra wrapper element here in order to have the new messages notification stick - to the bottom of the scrollable area (and not scroll with it). - - console-font-size is defined in main.js and updated via a user setting - */} -
-
- - =0.53.0) Flow suppress - ref={this._handleOutputTable} - displayableRecords={this.props.displayableRecords} - showSourceLabels={this.props.selectedSourceIds.length > 1} - fontSize={this.props.fontSize} - getExecutor={this._getExecutor} - getProvider={this._getProvider} - onScroll={this._handleScroll} - onDisplayableRecordHeightChange={ - this.props.onDisplayableRecordHeightChange - } - shouldScrollToBottom={this._shouldScrollToBottom} - /> - -
- {this._renderPrompt()} - {this._renderMultilineTip()} -
-
+ ` + }), + _react.createElement((_ConsoleHeader || _load_ConsoleHeader()).default, { + clear: this.props.clearRecords, + createPaste: this.props.createPaste, + invalidFilterInput: this.props.invalidFilterInput, + enableRegExpFilter: this.props.enableRegExpFilter, + filterText: this.props.filterText, + selectedSourceIds: this.props.selectedSourceIds, + sources: this.props.sources, + onFilterChange: this.props.updateFilter, + onSelectedSourcesChange: this.props.selectSources + }), + _react.createElement( + 'div', + { className: 'console-body', id: 'console-font-size-' + this._id }, + _react.createElement( + 'div', + { className: 'console-scroll-pane-wrapper' }, + _react.createElement((_FilteredMessagesReminder || _load_FilteredMessagesReminder()).default, { + filteredRecordCount: this.props.filteredRecordCount, + onReset: this.props.resetAllFilters + }), + _react.createElement((_OutputTable || _load_OutputTable()).default + // $FlowFixMe(>=0.53.0) Flow suppress + , { ref: this._handleOutputTable, + displayableRecords: this.props.displayableRecords, + showSourceLabels: this.props.selectedSourceIds.length > 1, + fontSize: this.props.fontSize, + getExecutor: this._getExecutor, + getProvider: this._getProvider, + onScroll: this._handleScroll, + onDisplayableRecordHeightChange: this.props.onDisplayableRecordHeightChange, + shouldScrollToBottom: this._shouldScrollToBottom + }), + _react.createElement((_NewMessagesNotification || _load_NewMessagesNotification()).default, { + visible: this.state.unseenMessages, + onClick: this._startScrollToBottom + }) + ), + this._renderPrompt(), + this._renderMultilineTip() + ) ); } - _renderMultilineTip(): ?React.Element { - const {currentExecutor} = this.props; + _renderMultilineTip() { + const { currentExecutor } = this.props; if (currentExecutor == null) { return; } - const keyCombo = - process.platform === 'darwin' ? ( - // Option + Enter on Mac - ⌥ + ⏎ - ) : ( - // Shift + Enter on Windows and Linux. - Shift + Enter - ); - - return ( -
- Tip: {keyCombo} to insert a newline -
+ const keyCombo = process.platform === 'darwin' ? + // Option + Enter on Mac + _react.createElement( + 'span', + null, + '\u2325 + \u23CE' + ) : + // Shift + Enter on Windows and Linux. + _react.createElement( + 'span', + null, + 'Shift + Enter' + ); + + return _react.createElement( + 'div', + { + className: (0, (_classnames || _load_classnames()).default)('console-multiline-tip', this.state.promptBufferChanged ? 'console-multiline-tip-dim' : 'console-multiline-tip-not-dim') }, + 'Tip: ', + keyCombo, + ' to insert a newline' ); } - _renderPrompt(): ?React.Element { - const {currentExecutor} = this.props; + _renderPrompt() { + const { currentExecutor } = this.props; if (currentExecutor == null) { return; } - return ( -
- {this._renderPromptButton()} - { - this.setState({promptBufferChanged: true}); - }} - /> -
+ return _react.createElement( + 'div', + { className: 'console-prompt' }, + this._renderPromptButton(), + _react.createElement((_InputArea || _load_InputArea()).default, { + scopeName: currentExecutor.scopeName, + onSubmit: this._executePrompt, + history: this.props.history, + watchEditor: this.props.watchEditor, + onDidTextBufferChange: () => { + this.setState({ promptBufferChanged: true }); + } + }) ); } - _executePrompt = (code: string): void => { - this.props.execute(code); - // Makes the console to scroll to the bottom. - this._isScrolledNearBottom = true; - }; - - _handleScroll = ( - offsetHeight: number, - scrollHeight: number, - scrollTop: number, - ): void => { - this._handleScrollEnd(offsetHeight, scrollHeight, scrollTop); - }; - - _handleScrollEnd( - offsetHeight: number, - scrollHeight: number, - scrollTop: number, - ): void { - const isScrolledToBottom = this._isScrolledToBottom( - offsetHeight, - scrollHeight, - scrollTop, - ); + _handleScrollEnd(offsetHeight, scrollHeight, scrollTop) { + const isScrolledToBottom = this._isScrolledToBottom(offsetHeight, scrollHeight, scrollTop); if (this._isScrollingToBottom && !isScrolledToBottom) { this._scrollToBottom(); @@ -324,46 +354,10 @@ export default class ConsoleView extends React.Component { this._isScrolledNearBottom = isScrolledToBottom; this._stopScrollToBottom(); this.setState({ - unseenMessages: - this.state.unseenMessages && !this._isScrolledNearBottom, + unseenMessages: this.state.unseenMessages && !this._isScrolledNearBottom }); } } - _handleOutputTable = (ref: OutputTable): void => { - this._outputTable = ref; - }; - - _scrollToBottom = (): void => { - if (!this._outputTable) { - return; - } - - this._outputTable.scrollToBottom(); - - this.setState({unseenMessages: false}); - }; - - _startScrollToBottom = (): void => { - if (!this._isScrollingToBottom) { - this._isScrollingToBottom = true; - - this._scrollingThrottle = Observable.timer( - MAXIMUM_SCROLLING_TIME, - ).subscribe(() => { - this._isScrollingToBottom = false; - }); - } - - this._scrollToBottom(); - }; - - _stopScrollToBottom = (): void => { - this._isScrollingToBottom = false; - this._scrollingThrottle.unsubscribe(); - }; - - _shouldScrollToBottom = (): boolean => { - return this._isScrolledNearBottom || this._isScrollingToBottom; - }; } +exports.default = ConsoleView; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/FilteredMessagesReminder.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/FilteredMessagesReminder.js index 8a56f66b..0b7e2c1a 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/FilteredMessagesReminder.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/FilteredMessagesReminder.js @@ -1,47 +1,64 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -type Props = { - filteredRecordCount: number, - onReset: () => void, -}; +var _react = _interopRequireWildcard(require('react')); -export default class FilteredMessagesReminder extends React.Component { - handleClick = (e: SyntheticEvent<>) => { - e.preventDefault(); - this.props.onReset(); - }; +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - render(): React.Node { - const {filteredRecordCount} = this.props; +class FilteredMessagesReminder extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this.handleClick = e => { + e.preventDefault(); + this.props.onReset(); + }, _temp; + } + + render() { + const { filteredRecordCount } = this.props; if (filteredRecordCount === 0) { return null; } - return ( -
-
-
-            {filteredRecordCount}{' '}
-            {filteredRecordCount === 1 ? 'message is' : 'messages are'} hidden
-            by filters.
-          
-
- -
Show all messages.
-
-
+ return _react.createElement( + 'div', + { className: 'console-filtered-reminder' }, + _react.createElement( + 'div', + { style: { flex: 1 } }, + _react.createElement( + 'pre', + null, + filteredRecordCount, + ' ', + filteredRecordCount === 1 ? 'message is' : 'messages are', + ' hidden by filters.' + ) + ), + _react.createElement( + 'a', + { href: '#', onClick: this.handleClick }, + _react.createElement( + 'pre', + null, + 'Show all messages.' + ) + ) ); } } +exports.default = FilteredMessagesReminder; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/InputArea.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/InputArea.js index 06e21003..031f3aea 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/InputArea.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/InputArea.js @@ -1,3 +1,31 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _AtomTextEditor; + +function _load_AtomTextEditor() { + return _AtomTextEditor = require('nuclide-commons-ui/AtomTextEditor'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,158 +34,125 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {WatchEditorFunction} from '../types'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import {AtomTextEditor} from 'nuclide-commons-ui/AtomTextEditor'; -import {Observable} from 'rxjs'; - -type Props = { - onSubmit: (value: string) => mixed, - scopeName: ?string, - history: Array, - watchEditor: ?WatchEditorFunction, - onDidTextBufferChange?: (event: atom$AggregatedTextEditEvent) => mixed, -}; - -type State = { - historyIndex: number, - draft: string, -}; - const ENTER_KEY_CODE = 13; const UP_KEY_CODE = 38; const DOWN_KEY_CODE = 40; -export default class InputArea extends React.Component { - _keySubscription: ?rxjs$ISubscription; - _textEditorModel: ?atom$TextEditor; +class InputArea extends _react.Component { - constructor(props: Props) { + constructor(props) { super(props); - this.state = { - historyIndex: -1, - draft: '', - }; - } - _submit = (): void => { - // Clear the text and trigger the `onSubmit` callback - const editor = this._textEditorModel; - if (editor == null) { - return; - } - - const text = editor.getText(); - if (text === '') { - return; - } - - editor.setText(''); // Clear the text field. - this.props.onSubmit(text); - this.setState({historyIndex: -1}); - }; - - _attachLabel = (editor: atom$TextEditor): IDisposable => { - const {watchEditor} = this.props; - const disposable = new UniversalDisposable(); - if (watchEditor) { - disposable.add(watchEditor(editor, ['nuclide-console'])); - } - return disposable; - }; - - _handleTextEditor = (component: ?AtomTextEditor): void => { - if (this._keySubscription) { - this._textEditorModel = null; - this._keySubscription.unsubscribe(); - } - if (component) { - this._textEditorModel = component.getModel(); - const el = ReactDOM.findDOMNode(component); - this._keySubscription = Observable.fromEvent(el, 'keydown').subscribe( - this._handleKeyDown, - ); - } - }; - - _handleKeyDown = (event: KeyboardEvent): void => { - const editor = this._textEditorModel; - // Detect AutocompletePlus menu element: https://git.io/vddLi - const isAutocompleteOpen = - document.querySelector('autocomplete-suggestion-list') != null; - if (editor == null) { - return; - } - if (event.which === ENTER_KEY_CODE) { - event.preventDefault(); - event.stopImmediatePropagation(); - - if (event.ctrlKey || event.altKey || event.shiftKey) { - editor.insertNewline(); + this._submit = () => { + // Clear the text and trigger the `onSubmit` callback + const editor = this._textEditorModel; + if (editor == null) { return; } - this._submit(); - } else if (event.which === UP_KEY_CODE && editor.getLineCount() <= 1) { - if (this.props.history.length === 0 || isAutocompleteOpen) { + const text = editor.getText(); + if (text === '') { return; } - event.preventDefault(); - event.stopImmediatePropagation(); - const historyIndex = Math.min( - this.state.historyIndex + 1, - this.props.history.length - 1, - ); - if (this.state.historyIndex === -1) { - this.setState({historyIndex, draft: editor.getText()}); - } else { - this.setState({historyIndex}); + + editor.setText(''); // Clear the text field. + this.props.onSubmit(text); + this.setState({ historyIndex: -1 }); + }; + + this._attachLabel = editor => { + const { watchEditor } = this.props; + const disposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(); + if (watchEditor) { + disposable.add(watchEditor(editor, ['nuclide-console'])); } - editor.setText( - this.props.history[this.props.history.length - historyIndex - 1], - ); - } else if (event.which === DOWN_KEY_CODE && editor.getLineCount() <= 1) { - if (this.props.history.length === 0 || isAutocompleteOpen) { + return disposable; + }; + + this._handleTextEditor = component => { + if (this._keySubscription) { + this._textEditorModel = null; + this._keySubscription.unsubscribe(); + } + if (component) { + this._textEditorModel = component.getModel(); + const el = _reactDom.default.findDOMNode(component); + this._keySubscription = _rxjsBundlesRxMinJs.Observable.fromEvent(el, 'keydown').subscribe(this._handleKeyDown); + } + }; + + this._handleKeyDown = event => { + const editor = this._textEditorModel; + // Detect AutocompletePlus menu element: https://git.io/vddLi + const isAutocompleteOpen = document.querySelector('autocomplete-suggestion-list') != null; + if (editor == null) { return; } - event.preventDefault(); - event.stopImmediatePropagation(); - const historyIndex = Math.max(this.state.historyIndex - 1, -1); - this.setState({historyIndex}); - if (historyIndex === -1) { - editor.setText(this.state.draft); - } else { - editor.setText( - this.props.history[this.props.history.length - historyIndex - 1], - ); + if (event.which === ENTER_KEY_CODE) { + event.preventDefault(); + event.stopImmediatePropagation(); + + if (event.ctrlKey || event.altKey || event.shiftKey) { + editor.insertNewline(); + return; + } + + this._submit(); + } else if (event.which === UP_KEY_CODE && editor.getLineCount() <= 1) { + if (this.props.history.length === 0 || isAutocompleteOpen) { + return; + } + event.preventDefault(); + event.stopImmediatePropagation(); + const historyIndex = Math.min(this.state.historyIndex + 1, this.props.history.length - 1); + if (this.state.historyIndex === -1) { + this.setState({ historyIndex, draft: editor.getText() }); + } else { + this.setState({ historyIndex }); + } + editor.setText(this.props.history[this.props.history.length - historyIndex - 1]); + } else if (event.which === DOWN_KEY_CODE && editor.getLineCount() <= 1) { + if (this.props.history.length === 0 || isAutocompleteOpen) { + return; + } + event.preventDefault(); + event.stopImmediatePropagation(); + const historyIndex = Math.max(this.state.historyIndex - 1, -1); + this.setState({ historyIndex }); + if (historyIndex === -1) { + editor.setText(this.state.draft); + } else { + editor.setText(this.props.history[this.props.history.length - historyIndex - 1]); + } } - } - }; - - render(): React.Node { - const grammar = - this.props.scopeName == null - ? null - : atom.grammars.grammarForScopeName(this.props.scopeName); - return ( -
- -
+ }; + + this.state = { + historyIndex: -1, + draft: '' + }; + } + + render() { + const grammar = this.props.scopeName == null ? null : atom.grammars.grammarForScopeName(this.props.scopeName); + return _react.createElement( + 'div', + { className: 'console-input-wrapper' }, + _react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { + ref: this._handleTextEditor, + grammar: grammar, + gutterHidden: true, + autoGrow: true, + lineNumberGutterVisible: false, + onConfirm: this._submit, + onInitialized: this._attachLabel, + onDidTextBufferChange: this.props.onDidTextBufferChange + }) ); } } +exports.default = InputArea; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/NewMessagesNotification.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/NewMessagesNotification.js index 8d6a9404..ca1175df 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/NewMessagesNotification.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/NewMessagesNotification.js @@ -1,3 +1,21 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,33 +24,21 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import classnames from 'classnames'; -import * as React from 'react'; - -type Props = { - onClick: () => mixed, - visible: boolean, -}; - -export default class NewMessagesNotification extends React.Component { - render(): React.Node { - const className = classnames( - 'console-new-messages-notification', - 'badge', - 'badge-info', - { - visible: this.props.visible, - }, - ); - return ( -
- - New Messages -
+class NewMessagesNotification extends _react.Component { + render() { + const className = (0, (_classnames || _load_classnames()).default)('console-new-messages-notification', 'badge', 'badge-info', { + visible: this.props.visible + }); + return _react.createElement( + 'div', + { className: className, onClick: this.props.onClick }, + _react.createElement('span', { className: 'console-new-messages-notification-icon icon icon-nuclicon-arrow-down' }), + 'New Messages' ); } } +exports.default = NewMessagesNotification; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/OutputTable.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/OutputTable.js index 1889fd6f..8de5f657 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/OutputTable.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/OutputTable.js @@ -1,243 +1,221 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type { - DisplayableRecord, - Executor, - OutputProvider, - Record, - RecordHeightChangeHandler, -} from '../types'; - -import Hasher from 'nuclide-commons/Hasher'; -import * as React from 'react'; -import List from 'react-virtualized/dist/commonjs/List'; -import RecordView from './RecordView'; -import recordsChanged from '../recordsChanged'; -import {ResizeSensitiveContainer} from 'nuclide-commons-ui/ResizeSensitiveContainer'; - -type Props = { - displayableRecords: Array, - showSourceLabels: boolean, - fontSize: number, - getExecutor: (id: string) => ?Executor, - getProvider: (id: string) => ?OutputProvider, - onScroll: ( - offsetHeight: number, - scrollHeight: number, - scrollTop: number, - ) => void, - onDisplayableRecordHeightChange: RecordHeightChangeHandler, - shouldScrollToBottom: () => boolean, -}; - -type State = { - width: number, - height: number, -}; - -type RowRendererParams = { - index: number, - key: string, - style: Object, - isScrolling: boolean, -}; - -type RowHeightParams = { - index: number, -}; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Hasher; + +function _load_Hasher() { + return _Hasher = _interopRequireDefault(require('nuclide-commons/Hasher')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _List; + +function _load_List() { + return _List = _interopRequireDefault(require('react-virtualized/dist/commonjs/List')); +} + +var _RecordView; + +function _load_RecordView() { + return _RecordView = _interopRequireDefault(require('./RecordView')); +} + +var _recordsChanged; + +function _load_recordsChanged() { + return _recordsChanged = _interopRequireDefault(require('../recordsChanged')); +} + +var _ResizeSensitiveContainer; + +function _load_ResizeSensitiveContainer() { + return _ResizeSensitiveContainer = require('nuclide-commons-ui/ResizeSensitiveContainer'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/* eslint-disable react/no-unused-prop-types */ -type OnScrollParams = { - clientHeight: number, - scrollHeight: number, - scrollTop: number, -}; /* eslint-enable react/no-unused-prop-types */ // The number of extra rows to render beyond what is visible -const OVERSCAN_COUNT = 5; -export default class OutputTable extends React.Component { - _hasher: Hasher; - // This is a from react-virtualized (untyped library) - _list: ?React.Element; - _wrapper: ?HTMLElement; - _renderedRecords: Map; - // The currently rendered range. - _startIndex: number; - _stopIndex: number; +/* eslint-disable react/no-unused-prop-types */ +const OVERSCAN_COUNT = 5; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class OutputTable extends _react.Component { - constructor(props: Props) { + // The currently rendered range. + constructor(props) { super(props); - this._hasher = new Hasher(); + + this._handleListRender = opts => { + this._startIndex = opts.startIndex; + this._stopIndex = opts.stopIndex; + }; + + this._getExecutor = id => { + return this.props.getExecutor(id); + }; + + this._getProvider = id => { + return this.props.getProvider(id); + }; + + this._renderRow = rowMetadata => { + const { index, style } = rowMetadata; + const displayableRecord = this.props.displayableRecords[index]; + const { record } = displayableRecord; + return _react.createElement( + 'div', + { + key: this._hasher.getHash(displayableRecord.record), + className: 'console-table-row-wrapper', + style: style }, + _react.createElement((_RecordView || _load_RecordView()).default, { + ref: view => { + if (view != null) { + this._renderedRecords.set(record, view); + } else { + this._renderedRecords.delete(record); + } + }, + getExecutor: this._getExecutor, + getProvider: this._getProvider, + displayableRecord: displayableRecord, + showSourceLabel: this.props.showSourceLabels, + onHeightChange: this._handleRecordHeightChange + }) + ); + }; + + this._getRowHeight = ({ index }) => { + return this.props.displayableRecords[index].height; + }; + + this._handleTableWrapper = tableWrapper => { + this._wrapper = tableWrapper; + }; + + this._handleListRef = listRef => { + this._list = listRef; + }; + + this._handleResize = (height, width) => { + this.setState({ + width, + height + }); + + // When this component resizes, the inner records will + // also resize and potentially have their heights change + // So we measure all of their heights again here + this._renderedRecords.forEach(recordView => recordView.measureAndNotifyHeight()); + }; + + this._handleRecordHeightChange = (recordId, newHeight) => { + this.props.onDisplayableRecordHeightChange(recordId, newHeight, () => { + // The react-virtualized List component is provided the row heights + // through a function, so it has no way of knowing that a row's height + // has changed unless we explicitly notify it to recompute the heights. + if (this._list == null) { + return; + } + // $FlowIgnore Untyped react-virtualized List component method + this._list.recomputeRowHeights(); + + // If we are already scrolled to the bottom, scroll to ensure that the scrollbar remains at + // the bottom. This is important not just for if the last record changes height through user + // interaction (e.g. expanding a debugger variable), but also because this is the mechanism + // through which the record's true initial height is reported. Therefore, we may have scrolled + // to the bottom, and only afterwards received its true height. In this case, it's important + // that we then scroll to the new bottom. + if (this.props.shouldScrollToBottom()) { + this.scrollToBottom(); + } + }); + }; + + this._onScroll = ({ + clientHeight, + scrollHeight, + scrollTop + }) => { + this.props.onScroll(clientHeight, scrollHeight, scrollTop); + }; + + this._hasher = new (_Hasher || _load_Hasher()).default(); this._renderedRecords = new Map(); this.state = { width: 0, - height: 0, + height: 0 }; this._startIndex = 0; this._stopIndex = 0; } + // This is a from react-virtualized (untyped library) - componentDidUpdate(prevProps: Props, prevState: State): void { - if ( - this._list != null && - recordsChanged( - prevProps.displayableRecords, - this.props.displayableRecords, - ) - ) { + + componentDidUpdate(prevProps, prevState) { + if (this._list != null && (0, (_recordsChanged || _load_recordsChanged()).default)(prevProps.displayableRecords, this.props.displayableRecords)) { // $FlowIgnore Untyped react-virtualized List method this._list.recomputeRowHeights(); } if (prevProps.fontSize !== this.props.fontSize) { - this._renderedRecords.forEach(recordView => - recordView.measureAndNotifyHeight(), - ); + this._renderedRecords.forEach(recordView => recordView.measureAndNotifyHeight()); } } - render(): React.Node { + render() { return ( // $FlowFixMe(>=0.53.0) Flow suppress - - {this._containerRendered() ? ( - =0.53.0) Flow suppress - ref={this._handleListRef} - height={this.state.height} - width={this.state.width} - rowCount={this.props.displayableRecords.length} - rowHeight={this._getRowHeight} - rowRenderer={this._renderRow} - overscanRowCount={OVERSCAN_COUNT} - onScroll={this._onScroll} - onRowsRendered={this._handleListRender} - /> - ) : null} - + _react.createElement( + (_ResizeSensitiveContainer || _load_ResizeSensitiveContainer()).ResizeSensitiveContainer, + { + className: 'console-table-wrapper native-key-bindings', + onResize: this._handleResize, + tabIndex: '1' }, + this._containerRendered() ? _react.createElement((_List || _load_List()).default + // $FlowFixMe(>=0.53.0) Flow suppress + , { ref: this._handleListRef, + height: this.state.height, + width: this.state.width, + rowCount: this.props.displayableRecords.length, + rowHeight: this._getRowHeight, + rowRenderer: this._renderRow, + overscanRowCount: OVERSCAN_COUNT, + onScroll: this._onScroll, + onRowsRendered: this._handleListRender + }) : null + ) ); } - _handleListRender = (opts: {startIndex: number, stopIndex: number}): void => { - this._startIndex = opts.startIndex; - this._stopIndex = opts.stopIndex; - }; - - scrollToBottom(): void { + scrollToBottom() { if (this._list != null) { // $FlowIgnore Untyped react-virtualized List method this._list.scrollToRow(this.props.displayableRecords.length - 1); } } - _getExecutor = (id: string): ?Executor => { - return this.props.getExecutor(id); - }; - - _getProvider = (id: string): ?OutputProvider => { - return this.props.getProvider(id); - }; - - _renderRow = (rowMetadata: RowRendererParams): React.Element => { - const {index, style} = rowMetadata; - const displayableRecord = this.props.displayableRecords[index]; - const {record} = displayableRecord; - return ( -
- { - if (view != null) { - this._renderedRecords.set(record, view); - } else { - this._renderedRecords.delete(record); - } - }} - getExecutor={this._getExecutor} - getProvider={this._getProvider} - displayableRecord={displayableRecord} - showSourceLabel={this.props.showSourceLabels} - onHeightChange={this._handleRecordHeightChange} - /> -
- ); - }; - - _containerRendered(): boolean { + _containerRendered() { return this.state.width !== 0 && this.state.height !== 0; } - _getRowHeight = ({index}: RowHeightParams): number => { - return this.props.displayableRecords[index].height; - }; - - _handleTableWrapper = (tableWrapper: HTMLElement): void => { - this._wrapper = tableWrapper; - }; - - _handleListRef = (listRef: React.Element): void => { - this._list = listRef; - }; - - _handleResize = (height: number, width: number): void => { - this.setState({ - width, - height, - }); - - // When this component resizes, the inner records will - // also resize and potentially have their heights change - // So we measure all of their heights again here - this._renderedRecords.forEach(recordView => - recordView.measureAndNotifyHeight(), - ); - }; - - _handleRecordHeightChange = (recordId: number, newHeight: number): void => { - this.props.onDisplayableRecordHeightChange(recordId, newHeight, () => { - // The react-virtualized List component is provided the row heights - // through a function, so it has no way of knowing that a row's height - // has changed unless we explicitly notify it to recompute the heights. - if (this._list == null) { - return; - } - // $FlowIgnore Untyped react-virtualized List component method - this._list.recomputeRowHeights(); - - // If we are already scrolled to the bottom, scroll to ensure that the scrollbar remains at - // the bottom. This is important not just for if the last record changes height through user - // interaction (e.g. expanding a debugger variable), but also because this is the mechanism - // through which the record's true initial height is reported. Therefore, we may have scrolled - // to the bottom, and only afterwards received its true height. In this case, it's important - // that we then scroll to the new bottom. - if (this.props.shouldScrollToBottom()) { - this.scrollToBottom(); - } - }); - }; - - _onScroll = ({ - clientHeight, - scrollHeight, - scrollTop, - }: OnScrollParams): void => { - this.props.onScroll(clientHeight, scrollHeight, scrollTop); - }; } +exports.default = OutputTable; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/PromptButton.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/PromptButton.js index 3e44e2da..8635dd50 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/PromptButton.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/PromptButton.js @@ -1,60 +1,65 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import invariant from 'assert'; -import * as React from 'react'; -import electron from 'electron'; - -const {remote} = electron; -invariant(remote != null); - -type PromptOption = { - id: string, - label: string, -}; - -type Props = { - value: string, - onChange: (value: string) => void, - children: ?any, - options: Array, -}; - -export default class PromptButton extends React.Component { - _disposables: IDisposable; - - render(): React.Node { - return ( - - {this.props.children} - - - ); - } +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +var _electron = _interopRequireDefault(require('electron')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const { remote } = _electron.default; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ - _handleClick = (event: SyntheticMouseEvent<>): void => { - const currentWindow = remote.getCurrentWindow(); - const menu = new remote.Menu(); - // TODO: Sort alphabetically by label - this.props.options.forEach(option => { - menu.append( - new remote.MenuItem({ +if (!(remote != null)) { + throw new Error('Invariant violation: "remote != null"'); +} + +class PromptButton extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._handleClick = event => { + const currentWindow = remote.getCurrentWindow(); + const menu = new remote.Menu(); + // TODO: Sort alphabetically by label + this.props.options.forEach(option => { + menu.append(new remote.MenuItem({ type: 'checkbox', checked: this.props.value === option.id, label: option.label, - click: () => this.props.onChange(option.id), - }), - ); - }); - menu.popup(currentWindow, event.clientX, event.clientY); - }; + click: () => this.props.onChange(option.id) + })); + }); + menu.popup(currentWindow, event.clientX, event.clientY); + }, _temp; + } + + render() { + return _react.createElement( + 'span', + { className: 'console-prompt-wrapper', onClick: this._handleClick }, + _react.createElement( + 'span', + { className: 'console-prompt-label' }, + this.props.children + ), + _react.createElement('span', { className: 'icon icon-chevron-right' }) + ); + } + } +exports.default = PromptButton; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/RecordView.js b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/RecordView.js index d5741f62..be8bb13e 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/RecordView.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/lib/ui/RecordView.js @@ -1,58 +1,116 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type { - Level, - Record, - DisplayableRecord, - Executor, - OutputProvider, -} from '../types'; - -import classnames from 'classnames'; -import {MeasuredComponent} from 'nuclide-commons-ui/MeasuredComponent'; -import * as React from 'react'; -import {LazyNestedValueComponent} from 'nuclide-commons-ui/LazyNestedValueComponent'; -import SimpleValueComponent from 'nuclide-commons-ui/SimpleValueComponent'; -import shallowEqual from 'shallowequal'; -import {TextRenderer} from 'nuclide-commons-ui/TextRenderer'; -import debounce from 'nuclide-commons/debounce'; -import {nextAnimationFrame} from 'nuclide-commons/observable'; -import parseText from '../parseText'; - -type Props = { - displayableRecord: DisplayableRecord, - showSourceLabel: boolean, - getExecutor: (id: string) => ?Executor, - getProvider: (id: string) => ?OutputProvider, - onHeightChange: (recordId: number, newHeight: number) => void, -}; - -const ONE_DAY = 1000 * 60 * 60 * 24; -export default class RecordView extends React.Component { - _wrapper: ?HTMLElement; - _debouncedMeasureAndNotifyHeight: () => void; - _rafDisposable: ?rxjs$Subscription; - - constructor(props: Props) { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _MeasuredComponent; + +function _load_MeasuredComponent() { + return _MeasuredComponent = require('nuclide-commons-ui/MeasuredComponent'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _LazyNestedValueComponent; + +function _load_LazyNestedValueComponent() { + return _LazyNestedValueComponent = require('nuclide-commons-ui/LazyNestedValueComponent'); +} + +var _SimpleValueComponent; + +function _load_SimpleValueComponent() { + return _SimpleValueComponent = _interopRequireDefault(require('nuclide-commons-ui/SimpleValueComponent')); +} + +var _shallowequal; + +function _load_shallowequal() { + return _shallowequal = _interopRequireDefault(require('shallowequal')); +} + +var _TextRenderer; + +function _load_TextRenderer() { + return _TextRenderer = require('nuclide-commons-ui/TextRenderer'); +} + +var _debounce; + +function _load_debounce() { + return _debounce = _interopRequireDefault(require('nuclide-commons/debounce')); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _parseText; + +function _load_parseText() { + return _parseText = _interopRequireDefault(require('../parseText')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const ONE_DAY = 1000 * 60 * 60 * 24; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class RecordView extends _react.Component { + + constructor(props) { super(props); // The MeasuredComponent can call this many times in quick succession as the // child components render, so we debounce it since we only want to know about // the height change once everything has settled down - (this: any)._debouncedMeasureAndNotifyHeight = debounce( - this.measureAndNotifyHeight, - 10, - ); + + this.measureAndNotifyHeight = () => { + // This method is called after the necessary DOM mutations have + // already occurred, however it is possible that the updates have + // not been flushed to the screen. So the height change update + // is deferred until the rendering is complete so that + // this._wrapper.offsetHeight gives us the correct final height + if (this._rafDisposable != null) { + this._rafDisposable.unsubscribe(); + } + this._rafDisposable = (_observable || _load_observable()).nextAnimationFrame.subscribe(() => { + if (this._wrapper == null) { + return; + } + const { offsetHeight } = this._wrapper; + const { displayableRecord, onHeightChange } = this.props; + if (offsetHeight !== displayableRecord.height) { + onHeightChange(displayableRecord.id, offsetHeight); + } + }); + }; + + this._handleRecordWrapper = wrapper => { + this._wrapper = wrapper; + }; + + this._debouncedMeasureAndNotifyHeight = (0, (_debounce || _load_debounce()).default)(this.measureAndNotifyHeight, 10); } componentDidMount() { @@ -67,13 +125,17 @@ export default class RecordView extends React.Component { } } - _renderContent(displayableRecord: DisplayableRecord): React.Element { - const {record} = displayableRecord; + _renderContent(displayableRecord) { + const { record } = displayableRecord; if (record.kind === 'request') { // TODO: We really want to use a text editor to render this so that we can get syntax // highlighting, but they're just too expensive. Figure out a less-expensive way to get syntax // highlighting. - return
{record.text || ' '}
; + return _react.createElement( + 'pre', + null, + record.text || ' ' + ); } else if (record.kind === 'response') { const executor = this.props.getExecutor(record.sourceId); return this._renderNestedValueComponent(displayableRecord, executor); @@ -83,128 +145,106 @@ export default class RecordView extends React.Component { } else { // If there's not text, use a space to make sure the row doesn't collapse. const text = record.text || ' '; - return
{parseText(text)}
; + return _react.createElement( + 'pre', + null, + (0, (_parseText || _load_parseText()).default)(text) + ); } } - shouldComponentUpdate(nextProps: Props): boolean { - return !shallowEqual(this.props, nextProps); + shouldComponentUpdate(nextProps) { + return !(0, (_shallowequal || _load_shallowequal()).default)(this.props, nextProps); } - _renderNestedValueComponent( - displayableRecord: DisplayableRecord, - provider: ?OutputProvider | ?Executor, - ): React.Element { - const {record, expansionStateId} = displayableRecord; + _renderNestedValueComponent(displayableRecord, provider) { + const { record, expansionStateId } = displayableRecord; const getProperties = provider == null ? null : provider.getProperties; const type = record.data == null ? null : record.data.type; const simpleValueComponent = getComponent(type); - return ( - - ); + return _react.createElement((_LazyNestedValueComponent || _load_LazyNestedValueComponent()).LazyNestedValueComponent, { + className: 'console-lazy-nested-value', + evaluationResult: record.data, + fetchChildren: getProperties, + simpleValueComponent: simpleValueComponent, + shouldCacheChildren: true, + expansionStateId: expansionStateId + }); } - render(): React.Node { - const {displayableRecord} = this.props; - const {record} = displayableRecord; - const {level, kind, timestamp, sourceId} = record; + render() { + const { displayableRecord } = this.props; + const { record } = displayableRecord; + const { level, kind, timestamp, sourceId } = record; - const classNames = classnames('console-record', `level-${level || 'log'}`, { + const classNames = (0, (_classnames || _load_classnames()).default)('console-record', `level-${level || 'log'}`, { request: kind === 'request', - response: kind === 'response', + response: kind === 'response' }); const iconName = getIconName(record); // flowlint-next-line sketchy-null-string:off - const icon = iconName ? : null; - const sourceLabel = this.props.showSourceLabel ? ( - - {sourceId} - + const icon = iconName ? _react.createElement('span', { className: `icon icon-${iconName}` }) : null; + const sourceLabel = this.props.showSourceLabel ? _react.createElement( + 'span', + { + className: `console-record-source-label ${getHighlightClassName(level)}` }, + sourceId ) : null; let renderedTimestamp; if (timestamp != null) { - const timestampLabel = - Date.now() - timestamp > ONE_DAY - ? timestamp.toLocaleString() - : timestamp.toLocaleTimeString(); - renderedTimestamp = ( -
{timestampLabel}
+ const timestampLabel = Date.now() - timestamp > ONE_DAY ? timestamp.toLocaleString() : timestamp.toLocaleTimeString(); + renderedTimestamp = _react.createElement( + 'div', + { className: 'console-record-timestamp' }, + timestampLabel ); } - return ( - - {/* $FlowFixMe(>=0.53.0) Flow suppress */} -
- {icon} -
- {displayableRecord.record.repeatCount > 1 && ( -
- {displayableRecord.record.repeatCount} -
- )} -
- {this._renderContent(displayableRecord)} -
-
- {sourceLabel} - {renderedTimestamp} -
-
+ return _react.createElement( + (_MeasuredComponent || _load_MeasuredComponent()).MeasuredComponent, + { + onMeasurementsChanged: this._debouncedMeasureAndNotifyHeight }, + _react.createElement( + 'div', + { ref: this._handleRecordWrapper, className: classNames }, + icon, + _react.createElement( + 'div', + { className: 'console-record-content-wrapper' }, + displayableRecord.record.repeatCount > 1 && _react.createElement( + 'div', + { className: 'console-record-duplicate-number' }, + displayableRecord.record.repeatCount + ), + _react.createElement( + 'div', + { className: 'console-record-content' }, + this._renderContent(displayableRecord) + ) + ), + sourceLabel, + renderedTimestamp + ) ); } - measureAndNotifyHeight = () => { - // This method is called after the necessary DOM mutations have - // already occurred, however it is possible that the updates have - // not been flushed to the screen. So the height change update - // is deferred until the rendering is complete so that - // this._wrapper.offsetHeight gives us the correct final height - if (this._rafDisposable != null) { - this._rafDisposable.unsubscribe(); - } - this._rafDisposable = nextAnimationFrame.subscribe(() => { - if (this._wrapper == null) { - return; - } - const {offsetHeight} = this._wrapper; - const {displayableRecord, onHeightChange} = this.props; - if (offsetHeight !== displayableRecord.height) { - onHeightChange(displayableRecord.id, offsetHeight); - } - }); - }; - - _handleRecordWrapper = (wrapper: HTMLElement) => { - this._wrapper = wrapper; - }; } -function getComponent(type: ?string): React.ComponentType { +exports.default = RecordView; +function getComponent(type) { switch (type) { case 'text': - return props => TextRenderer(props.evaluationResult); + return props => (0, (_TextRenderer || _load_TextRenderer()).TextRenderer)(props.evaluationResult); case 'boolean': case 'string': case 'number': case 'object': default: - return SimpleValueComponent; + return (_SimpleValueComponent || _load_SimpleValueComponent()).default; } } -function getHighlightClassName(level: Level): string { +function getHighlightClassName(level) { switch (level) { case 'info': return 'highlight-info'; @@ -219,7 +259,7 @@ function getHighlightClassName(level: Level): string { } } -function getIconName(record: Record): ?string { +function getIconName(record) { switch (record.kind) { case 'request': return 'chevron-right'; @@ -236,4 +276,4 @@ function getIconName(record: Record): ?string { case 'error': return 'stop'; } -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/spec/Epics-spec.js b/modules/atom-ide-ui/pkg/atom-ide-console/spec/Epics-spec.js index 2a6f1143..bea024db 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/spec/Epics-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/spec/Epics-spec.js @@ -1,59 +1,74 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {AppState} from '../lib/types'; - -import {ActionsObservable} from 'nuclide-commons/redux-observable'; -import * as Actions from '../lib/redux/Actions'; -import * as Epics from '../lib/redux/Epics'; -import invariant from 'assert'; -import {Observable} from 'rxjs'; +'use strict'; + +var _reduxObservable; + +function _load_reduxObservable() { + return _reduxObservable = require('nuclide-commons/redux-observable'); +} + +var _Actions; + +function _load_Actions() { + return _Actions = _interopRequireWildcard(require('../lib/redux/Actions')); +} + +var _Epics; + +function _load_Epics() { + return _Epics = _interopRequireWildcard(require('../lib/redux/Epics')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } describe('Epics', () => { describe('registerOutputProviderEpic', () => { it('observes the status', () => { const mockStore = { dispatch: () => {}, - getState: () => (({}: any): AppState), + getState: () => ({}) }; let setStatus; const provider = { id: 'test', - messages: Observable.never(), + messages: _rxjsBundlesRxMinJs.Observable.never(), observeStatus: cb => { setStatus = cb; }, start: () => {}, - stop: () => {}, + stop: () => {} }; - const actions = new ActionsObservable( - Observable.of(Actions.registerOutputProvider(provider)), - ); + const actions = new (_reduxObservable || _load_reduxObservable()).ActionsObservable(_rxjsBundlesRxMinJs.Observable.of((_Actions || _load_Actions()).registerOutputProvider(provider))); let results = []; - Epics.registerRecordProviderEpic(actions, mockStore).subscribe( - results.push.bind(results), - ); - invariant(setStatus != null); + (_Epics || _load_Epics()).registerRecordProviderEpic(actions, mockStore).subscribe(results.push.bind(results)); + + if (!(setStatus != null)) { + throw new Error('Invariant violation: "setStatus != null"'); + } + setStatus('running'); setStatus('stopped'); setStatus('running'); - results = results.filter(action => action.type === Actions.UPDATE_STATUS); + results = results.filter(action => action.type === (_Actions || _load_Actions()).UPDATE_STATUS); expect(results.length).toBe(3); - expect( - results.map(action => { - invariant(action.type === Actions.UPDATE_STATUS); - return action.payload.status; - }), - ).toEqual(['running', 'stopped', 'running']); + expect(results.map(action => { + if (!(action.type === (_Actions || _load_Actions()).UPDATE_STATUS)) { + throw new Error('Invariant violation: "action.type === Actions.UPDATE_STATUS"'); + } + + return action.payload.status; + })).toEqual(['running', 'stopped', 'running']); }); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/spec/Reducers-spec.js b/modules/atom-ide-ui/pkg/atom-ide-console/spec/Reducers-spec.js index febf34f8..6781dd50 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/spec/Reducers-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/spec/Reducers-spec.js @@ -1,21 +1,33 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Action, Executor} from '../lib/types'; - -import * as Actions from '../lib/redux/Actions'; -import Reducers from '../lib/redux/Reducers'; -import * as Immutable from 'immutable'; -import {Observable} from 'rxjs'; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.createDummyExecutor = createDummyExecutor; + +var _Actions; + +function _load_Actions() { + return _Actions = _interopRequireWildcard(require('../lib/redux/Actions')); +} + +var _Reducers; + +function _load_Reducers() { + return _Reducers = _interopRequireDefault(require('../lib/redux/Reducers')); +} + +var _immutable; + +function _load_immutable() { + return _immutable = _interopRequireWildcard(require('immutable')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } const emptyAppState = { createPasteFunction: null, @@ -25,9 +37,19 @@ const emptyAppState = { providers: new Map(), providerStatuses: new Map(), providerSubscriptions: new Map(), - records: Immutable.List(), - history: [], -}; + records: (_immutable || _load_immutable()).List(), + history: [] +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('createStateStream', () => { describe('RECORD_RECEIVED', () => { @@ -35,28 +57,24 @@ describe('createStateStream', () => { let initialRecords; beforeEach(() => { - initialRecords = Immutable.List(); - const initialState = { - ...emptyAppState, + initialRecords = (_immutable || _load_immutable()).List(); + const initialState = Object.assign({}, emptyAppState, { maxMessageCount: 2, - records: initialRecords, - }; + records: initialRecords + }); const actions = []; for (let i = 0; i < 5; i++) { actions.push({ - type: Actions.RECORD_RECEIVED, + type: (_Actions || _load_Actions()).RECORD_RECEIVED, payload: { record: { level: 'info', - text: i.toString(), - }, - }, + text: i.toString() + } + } }); } - finalState = ((actions: any): Array).reduce( - Reducers, - initialState, - ); + finalState = actions.reduce((_Reducers || _load_Reducers()).default, initialState); }); it('adds records', () => { @@ -68,10 +86,7 @@ describe('createStateStream', () => { }); it('truncates the least recent records', () => { - expect(finalState.records.map(record => record.text).toArray()).toEqual([ - '3', - '4', - ]); + expect(finalState.records.map(record => record.text).toArray()).toEqual(['3', '4']); }); it("doesn't mutate the original records list", () => { @@ -85,25 +100,19 @@ describe('createStateStream', () => { beforeEach(() => { initialProviders = new Map(); - const initialState = { - ...emptyAppState, - providers: initialProviders, - }; - const actions = [ - { - type: Actions.REGISTER_SOURCE, - payload: { - source: { - id: 'test', - records: Observable.empty(), - }, - }, - }, - ]; - finalState = ((actions: any): Array).reduce( - Reducers, - initialState, - ); + const initialState = Object.assign({}, emptyAppState, { + providers: initialProviders + }); + const actions = [{ + type: (_Actions || _load_Actions()).REGISTER_SOURCE, + payload: { + source: { + id: 'test', + records: _rxjsBundlesRxMinJs.Observable.empty() + } + } + }]; + finalState = actions.reduce((_Reducers || _load_Reducers()).default, initialState); }); it('adds providers to the registry', () => { @@ -120,24 +129,21 @@ describe('createStateStream', () => { let finalState; beforeEach(() => { - initialRecords = Immutable.List([ - { - kind: 'message', - sourceId: 'Test', - level: 'info', - text: 'test', - scopeName: null, - timestamp: new Date('2017-01-01T12:34:56.789Z'), - data: null, - repeatCount: 1, - }, - ]); - const initialState = { - ...emptyAppState, - records: initialRecords, - }; - const actions = [{type: Actions.CLEAR_RECORDS}]; - finalState = actions.reduce(Reducers, initialState); + initialRecords = (_immutable || _load_immutable()).List([{ + kind: 'message', + sourceId: 'Test', + level: 'info', + text: 'test', + scopeName: null, + timestamp: new Date('2017-01-01T12:34:56.789Z'), + data: null, + repeatCount: 1 + }]); + const initialState = Object.assign({}, emptyAppState, { + records: initialRecords + }); + const actions = [{ type: (_Actions || _load_Actions()).CLEAR_RECORDS }]; + finalState = actions.reduce((_Reducers || _load_Reducers()).default, initialState); }); it('clears the records', () => { @@ -158,23 +164,20 @@ describe('createStateStream', () => { beforeEach(() => { dummyExecutor = createDummyExecutor('a'); initialExecutors = new Map([['a', dummyExecutor]]); - initialState = { - ...emptyAppState, - executors: initialExecutors, - }; + initialState = Object.assign({}, emptyAppState, { + executors: initialExecutors + }); }); describe('REGISTER_EXECUTOR', () => { beforeEach(() => { - const actions = [ - { - type: Actions.REGISTER_EXECUTOR, - payload: { - executor: createDummyExecutor('b'), - }, - }, - ]; - finalState = actions.reduce(Reducers, initialState); + const actions = [{ + type: (_Actions || _load_Actions()).REGISTER_EXECUTOR, + payload: { + executor: createDummyExecutor('b') + } + }]; + finalState = actions.reduce((_Reducers || _load_Reducers()).default, initialState); }); it('adds an executor', () => { @@ -188,8 +191,8 @@ describe('createStateStream', () => { describe('unregisterExecutor', () => { beforeEach(() => { - const actions = [Actions.unregisterExecutor(dummyExecutor)]; - finalState = actions.reduce(Reducers, initialState); + const actions = [(_Actions || _load_Actions()).unregisterExecutor(dummyExecutor)]; + finalState = actions.reduce((_Reducers || _load_Reducers()).default, initialState); }); it('removes an executor', () => { @@ -203,12 +206,12 @@ describe('createStateStream', () => { }); }); -export function createDummyExecutor(id: string): Executor { +function createDummyExecutor(id) { return { id, name: id, scopeName: 'text.plain', - send: (code: string) => {}, - output: Observable.create(observer => {}), + send: code => {}, + output: _rxjsBundlesRxMinJs.Observable.create(observer => {}) }; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/spec/getCurrentExecutorId-spec.js b/modules/atom-ide-ui/pkg/atom-ide-console/spec/getCurrentExecutorId-spec.js index fb406fad..c31e3fad 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/spec/getCurrentExecutorId-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/spec/getCurrentExecutorId-spec.js @@ -1,40 +1,57 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import getCurrentExecutorId from '../lib/getCurrentExecutorId'; -import * as Immutable from 'immutable'; -import {createDummyExecutor} from './Reducers-spec'; +'use strict'; + +var _getCurrentExecutorId; + +function _load_getCurrentExecutorId() { + return _getCurrentExecutorId = _interopRequireDefault(require('../lib/getCurrentExecutorId')); +} + +var _immutable; + +function _load_immutable() { + return _immutable = _interopRequireWildcard(require('immutable')); +} + +var _ReducersSpec; + +function _load_ReducersSpec() { + return _ReducersSpec = require('./Reducers-spec'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const baseAppState = { createPasteFunction: null, currentExecutorId: 'a', maxMessageCount: Number.POSITIVE_INFINITY, - executors: new Map([['a', createDummyExecutor('a')]]), + executors: new Map([['a', (0, (_ReducersSpec || _load_ReducersSpec()).createDummyExecutor)('a')]]), providers: new Map(), providerStatuses: new Map(), - records: Immutable.List(), - history: [], -}; + records: (_immutable || _load_immutable()).List(), + history: [] +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('getCurrentExecutorId', () => { it('gets the current executor', () => { - expect(getCurrentExecutorId(baseAppState)).toBe('a'); + expect((0, (_getCurrentExecutorId || _load_getCurrentExecutorId()).default)(baseAppState)).toBe('a'); }); it('returns an executor even if the current id is null', () => { - const appState = { - ...baseAppState, - currentExecutorId: null, - }; - expect(getCurrentExecutorId(appState)).toBe('a'); + const appState = Object.assign({}, baseAppState, { + currentExecutorId: null + }); + expect((0, (_getCurrentExecutorId || _load_getCurrentExecutorId()).default)(appState)).toBe('a'); }); -}); +}); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-console/spec/parseText-spec.js b/modules/atom-ide-ui/pkg/atom-ide-console/spec/parseText-spec.js index 9a878e7b..e6d39908 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-console/spec/parseText-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-console/spec/parseText-spec.js @@ -1,20 +1,16 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import parseText from '../lib/parseText'; +'use strict'; + +var _parseText; + +function _load_parseText() { + return _parseText = _interopRequireDefault(require('../lib/parseText')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('parseText', () => { it('parses url pattern', () => { - const chunks = parseText('Message: https://facebook.com'); + const chunks = (0, (_parseText || _load_parseText()).default)('Message: https://facebook.com'); expect(chunks.length).toBe(3); expect(chunks[0]).toBe('Message: '); expect(chunks[2]).toBe(''); @@ -30,9 +26,7 @@ describe('parseText', () => { }); it('parses absolute file path', () => { - const chunks = parseText( - 'Message: /absolute/file/path/file.js should be parsed.', - ); + const chunks = (0, (_parseText || _load_parseText()).default)('Message: /absolute/file/path/file.js should be parsed.'); expect(chunks.length).toBe(3); expect(chunks[0]).toBe('Message: '); expect(chunks[2]).toBe(' should be parsed.'); @@ -48,9 +42,7 @@ describe('parseText', () => { }); it('parses absolute file path with line number', () => { - const chunks = parseText( - 'Message: /absolute/file/path/file.js:10 should be parsed.', - ); + const chunks = (0, (_parseText || _load_parseText()).default)('Message: /absolute/file/path/file.js:10 should be parsed.'); expect(chunks.length).toBe(3); expect(chunks[0]).toBe('Message: '); expect(chunks[2]).toBe(' should be parsed.'); @@ -61,16 +53,12 @@ describe('parseText', () => { if (typeof reactElement === 'object') { expect(reactElement.type).toBe('a'); expect(reactElement.props.onClick).toBeDefined(); - expect(reactElement.props.children).toBe( - '/absolute/file/path/file.js:10', - ); + expect(reactElement.props.children).toBe('/absolute/file/path/file.js:10'); } }); it('parses absolute file path with line number and column number', () => { - const chunks = parseText( - 'Message: /absolute/file/path/file.js:1:17 should be parsed.', - ); + const chunks = (0, (_parseText || _load_parseText()).default)('Message: /absolute/file/path/file.js:1:17 should be parsed.'); expect(chunks.length).toBe(3); expect(chunks[0]).toBe('Message: '); expect(chunks[2]).toBe(' should be parsed.'); @@ -81,14 +69,12 @@ describe('parseText', () => { if (typeof reactElement === 'object') { expect(reactElement.type).toBe('a'); expect(reactElement.props.onClick).toBeDefined(); - expect(reactElement.props.children).toBe( - '/absolute/file/path/file.js:1:17', - ); + expect(reactElement.props.children).toBe('/absolute/file/path/file.js:1:17'); } }); it('parses relative file path', () => { - const chunks = parseText('relative/path/file.js:1:17 should be parsed.'); + const chunks = (0, (_parseText || _load_parseText()).default)('relative/path/file.js:1:17 should be parsed.'); expect(chunks.length).toBe(3); expect(chunks[0]).toBe(''); expect(chunks[2]).toBe(' should be parsed.'); @@ -104,9 +90,7 @@ describe('parseText', () => { }); it('parses mutliple file paths', () => { - const chunks = parseText( - 'Message: relative/path/file.js:1:17 and /Absolute/path/file.file.js should be parsed.', - ); + const chunks = (0, (_parseText || _load_parseText()).default)('Message: relative/path/file.js:1:17 and /Absolute/path/file.file.js should be parsed.'); expect(chunks.length).toBe(5); expect(chunks[0]).toBe('Message: '); expect(chunks[2]).toBe(' and '); @@ -117,21 +101,24 @@ describe('parseText', () => { expect(typeof reactElementRelative).toBe('object'); expect(typeof reactElementAbsolute).toBe('object'); - if ( - typeof reactElementRelative === 'object' && - typeof reactElementAbsolute === 'object' - ) { + if (typeof reactElementRelative === 'object' && typeof reactElementAbsolute === 'object') { expect(reactElementRelative.type).toBe('a'); expect(reactElementRelative.props.onClick).toBeDefined(); - expect(reactElementRelative.props.children).toBe( - 'relative/path/file.js:1:17', - ); + expect(reactElementRelative.props.children).toBe('relative/path/file.js:1:17'); expect(reactElementAbsolute.type).toBe('a'); expect(reactElementAbsolute.props.onClick).toBeDefined(); - expect(reactElementAbsolute.props.children).toBe( - '/Absolute/path/file.file.js', - ); + expect(reactElementAbsolute.props.children).toBe('/Absolute/path/file.file.js'); } }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipComponent.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipComponent.js index 2d420476..81d7a3b8 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipComponent.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipComponent.js @@ -1,81 +1,99 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Datatip} from './types'; - -import * as React from 'react'; - -import {maybeToString} from 'nuclide-commons/string'; -import MarkedStringDatatip from './MarkedStringDatatip'; - -export const DATATIP_ACTIONS = Object.freeze({ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DatatipComponent = exports.DATATIP_ACTIONS = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _string; + +function _load_string() { + return _string = require('nuclide-commons/string'); +} + +var _MarkedStringDatatip; + +function _load_MarkedStringDatatip() { + return _MarkedStringDatatip = _interopRequireDefault(require('./MarkedStringDatatip')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const DATATIP_ACTIONS = exports.DATATIP_ACTIONS = Object.freeze({ PIN: 'PIN', - CLOSE: 'CLOSE', + CLOSE: 'CLOSE' }); const IconsForAction = { [DATATIP_ACTIONS.PIN]: 'pin', - [DATATIP_ACTIONS.CLOSE]: 'x', + [DATATIP_ACTIONS.CLOSE]: 'x' }; -type DatatipComponentProps = { - action: string, - actionTitle: string, - className?: string, - datatip: Datatip, - onActionClick: Function, -}; +class DatatipComponent extends _react.Component { + constructor(...args) { + var _temp; -export class DatatipComponent extends React.Component { - handleActionClick = (event: SyntheticEvent<>) => { - this.props.onActionClick(); - }; + return _temp = super(...args), this.handleActionClick = event => { + this.props.onActionClick(); + }, _temp; + } - render(): React.Node { - const { + render() { + const _props = this.props, + { className, action, actionTitle, datatip, - onActionClick, - ...props - } = this.props; + onActionClick + } = _props, + props = _objectWithoutProperties(_props, ['className', 'action', 'actionTitle', 'datatip', 'onActionClick']); let content; if (datatip.component != null) { - content = ; + content = _react.createElement(datatip.component, null); } else if (datatip.markedStrings != null) { - content = ; + content = _react.createElement((_MarkedStringDatatip || _load_MarkedStringDatatip()).default, { markedStrings: datatip.markedStrings }); } let actionButton = null; if (action != null && IconsForAction[action] != null) { const actionIcon = IconsForAction[action]; - actionButton = ( -
- ); + actionButton = _react.createElement('div', { + className: `datatip-pin-button icon-${actionIcon}`, + onClick: this.handleActionClick, + title: actionTitle + }); } - return ( -
-
{content}
- {actionButton} -
+ return _react.createElement( + 'div', + Object.assign({ + className: `${(0, (_string || _load_string()).maybeToString)(className)} datatip-container` + }, props), + _react.createElement( + 'div', + { className: 'datatip-content' }, + content + ), + actionButton ); } } +exports.DatatipComponent = DatatipComponent; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipManager.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipManager.js index c31ccd79..f195ef52 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipManager.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/DatatipManager.js @@ -1,72 +1,183 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -/* global performance */ +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DatatipManager = undefined; -import type { - AnyDatatipProvider, - Datatip, - DatatipProvider, - ModifierDatatipProvider, - ModifierKey, - PinnedDatatipOptions, -} from './types'; - -import {Range} from 'atom'; -import {asyncFind} from 'nuclide-commons/promise'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import analytics from 'nuclide-commons-atom/analytics'; -import debounce from 'nuclide-commons/debounce'; -import featureConfig from 'nuclide-commons-atom/feature-config'; -import idx from 'idx'; -import performanceNow from 'nuclide-commons/performanceNow'; -import {Observable} from 'rxjs'; -import {getLogger} from 'log4js'; -import ProviderRegistry from 'nuclide-commons-atom/ProviderRegistry'; -import {observeTextEditors} from 'nuclide-commons-atom/text-editor'; -import { - getModifierKeysFromMouseEvent, - getModifierKeyFromKeyboardEvent, -} from './getModifierKeys'; - -import {DatatipComponent, DATATIP_ACTIONS} from './DatatipComponent'; -import isScrollable from './isScrollable'; -import {PinnedDatatip} from './PinnedDatatip'; - -const DEFAULT_DATATIP_DEBOUNCE_DELAY = 1000; -const DEFAULT_DATATIP_INTERACTED_DEBOUNCE_DELAY = 1000; +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); -type PinClickHandler = (editor: atom$TextEditor, datatip: Datatip) => void; +let getDatatipResults = (() => { + var _ref5 = (0, _asyncToGenerator.default)(function* (providers, editor, position, invoke) { + const filteredDatatipProviders = Array.from(providers.getAllProvidersForEditor(editor)); + if (filteredDatatipProviders.length === 0) { + return []; + } -type DatatipResult = { - datatip: Datatip, - provider: AnyDatatipProvider, -}; + const promises = filteredDatatipProviders.map((() => { + var _ref6 = (0, _asyncToGenerator.default)(function* (provider) { + const name = getProviderName(provider); + const timingTracker = new (_analytics || _load_analytics()).default.TimingTracker(name + '.datatip'); + try { + const datatip = yield invoke(provider); + if (!datatip) { + return null; + } + + timingTracker.onSuccess(); + + const result = { + datatip, + provider + }; + return result; + } catch (e) { + timingTracker.onError(e); + (0, (_log4js || _load_log4js()).getLogger)('datatip').error(`Error getting datatip from provider ${name}`, e); + return null; + } + }); + + return function (_x5) { + return _ref6.apply(this, arguments); + }; + })()); + if ((_featureConfig || _load_featureConfig()).default.get('atom-ide-datatip.onlyTopDatatip')) { + const result = yield (0, (_promise || _load_promise()).asyncFind)(promises, function (x) { + return x; + }); + return result != null ? [result] : []; + } else { + return (yield Promise.all(promises)).filter(Boolean); + } + }); + + return function getDatatipResults(_x, _x2, _x3, _x4) { + return _ref5.apply(this, arguments); + }; +})(); + +var _atom = require('atom'); + +var _promise; + +function _load_promise() { + return _promise = require('nuclide-commons/promise'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _debounce; + +function _load_debounce() { + return _debounce = _interopRequireDefault(require('nuclide-commons/debounce')); +} + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _idx; + +function _load_idx() { + return _idx = _interopRequireDefault(require('idx')); +} + +var _performanceNow; + +function _load_performanceNow() { + return _performanceNow = _interopRequireDefault(require('nuclide-commons/performanceNow')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +var _ProviderRegistry; + +function _load_ProviderRegistry() { + return _ProviderRegistry = _interopRequireDefault(require('nuclide-commons-atom/ProviderRegistry')); +} + +var _textEditor; + +function _load_textEditor() { + return _textEditor = require('nuclide-commons-atom/text-editor'); +} -function getProviderName(provider: AnyDatatipProvider): string { +var _getModifierKeys; + +function _load_getModifierKeys() { + return _getModifierKeys = require('./getModifierKeys'); +} + +var _DatatipComponent; + +function _load_DatatipComponent() { + return _DatatipComponent = require('./DatatipComponent'); +} + +var _isScrollable; + +function _load_isScrollable() { + return _isScrollable = _interopRequireDefault(require('./isScrollable')); +} + +var _PinnedDatatip; + +function _load_PinnedDatatip() { + return _PinnedDatatip = require('./PinnedDatatip'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const DEFAULT_DATATIP_DEBOUNCE_DELAY = 1000; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +/* global performance */ + +const DEFAULT_DATATIP_INTERACTED_DEBOUNCE_DELAY = 1000; + +function getProviderName(provider) { if (provider.providerName == null) { - getLogger('datatip').error('Datatip provider has no name', provider); + (0, (_log4js || _load_log4js()).getLogger)('datatip').error('Datatip provider has no name', provider); return 'unknown'; } return provider.providerName; } -function getBufferPosition( - editor: TextEditor, - editorView: atom$TextEditorElement, - event: ?MouseEvent, -): null | atom$Point { +function getBufferPosition(editor, editorView, event) { if (!event) { return null; } @@ -78,152 +189,81 @@ function getBufferPosition( const screenPosition = text.screenPositionForMouseEvent(event); const pixelPosition = text.pixelPositionForMouseEvent(event); - const pixelPositionFromScreenPosition = text.pixelPositionForScreenPosition( - screenPosition, - ); + const pixelPositionFromScreenPosition = text.pixelPositionForScreenPosition(screenPosition); // Distance (in pixels) between screenPosition and the cursor. - const horizontalDistance = - pixelPosition.left - pixelPositionFromScreenPosition.left; + const horizontalDistance = pixelPosition.left - pixelPositionFromScreenPosition.left; // `screenPositionForMouseEvent.column` cannot exceed the current line length. // This is essentially a heuristic for "mouse cursor is to the left or right // of text content". - if ( - pixelPosition.left <= 0 || - horizontalDistance > editor.getDefaultCharWidth() - ) { + if (pixelPosition.left <= 0 || horizontalDistance > editor.getDefaultCharWidth()) { return null; } return editor.bufferPositionForScreenPosition(screenPosition); } -async function getDatatipResults( - providers: ProviderRegistry, - editor: atom$TextEditor, - position: atom$Point, - invoke: TProvider => Promise, -): Promise> { - const filteredDatatipProviders = Array.from( - providers.getAllProvidersForEditor(editor), - ); - if (filteredDatatipProviders.length === 0) { - return []; - } - - const promises = filteredDatatipProviders.map( - async (provider: TProvider): Promise => { - const name = getProviderName(provider); - const timingTracker = new analytics.TimingTracker(name + '.datatip'); - try { - const datatip: ?Datatip = await invoke(provider); - if (!datatip) { - return null; - } - - timingTracker.onSuccess(); - - const result: DatatipResult = { - datatip, - provider, - }; - return result; - } catch (e) { - timingTracker.onError(e); - getLogger('datatip').error( - `Error getting datatip from provider ${name}`, - e, - ); - return null; - } - }, - ); - if (featureConfig.get('atom-ide-datatip.onlyTopDatatip')) { - const result = await asyncFind(promises, x => x); - return result != null ? [result] : []; - } else { - return (await Promise.all(promises)).filter(Boolean); - } -} - -type PinnableDatatipProps = { - datatip: Datatip, - editor: atom$TextEditor, - onPinClick: PinClickHandler, -}; - function PinnableDatatip({ datatip, editor, - onPinClick, -}: PinnableDatatipProps): React.Element { + onPinClick +}) { let action; let actionTitle; // Datatips are pinnable by default, unless explicitly specified // otherwise. if (datatip.pinnable !== false) { - action = DATATIP_ACTIONS.PIN; + action = (_DatatipComponent || _load_DatatipComponent()).DATATIP_ACTIONS.PIN; actionTitle = 'Pin this Datatip'; } return ( // $FlowFixMe(>=0.53.0) Flow suppress - onPinClick(editor, datatip)} - /> + _react.createElement((_DatatipComponent || _load_DatatipComponent()).DatatipComponent, { + action: action, + actionTitle: actionTitle, + datatip: datatip, + onActionClick: () => onPinClick(editor, datatip) + }) ); } -function mountDatatipWithMarker( - editor: atom$TextEditor, - element: HTMLElement, - range: atom$Range, - renderedProviders: React.Element, - position: atom$Point, -): IDisposable { +function mountDatatipWithMarker(editor, element, range, renderedProviders, position) { // Highlight the text indicated by the datatip's range. const highlightMarker = editor.markBufferRange(range, { - invalidate: 'never', + invalidate: 'never' }); editor.decorateMarker(highlightMarker, { type: 'highlight', - class: 'datatip-highlight-region', + class: 'datatip-highlight-region' }); // The actual datatip should appear at the trigger position. - const overlayMarker = editor.markBufferRange(new Range(position, position), { - invalidate: 'never', + const overlayMarker = editor.markBufferRange(new _atom.Range(position, position), { + invalidate: 'never' }); editor.decorateMarker(overlayMarker, { type: 'overlay', position: 'tail', - item: element, + item: element }); - return new UniversalDisposable( - () => highlightMarker.destroy(), - () => overlayMarker.destroy(), - // The editor may not mount the marker until the next update. - // It's not safe to render anything until that point, as datatips - // often need to measure their size in the DOM. - Observable.from(editor.getElement().getNextUpdatePromise()).subscribe( - () => { - element.style.display = 'block'; - ReactDOM.render(renderedProviders, element); - }, - ), - ); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => highlightMarker.destroy(), () => overlayMarker.destroy(), + // The editor may not mount the marker until the next update. + // It's not safe to render anything until that point, as datatips + // often need to measure their size in the DOM. + _rxjsBundlesRxMinJs.Observable.from(editor.getElement().getNextUpdatePromise()).subscribe(() => { + element.style.display = 'block'; + _reactDom.default.render(renderedProviders, element); + })); } const DatatipState = Object.freeze({ HIDDEN: 'HIDDEN', FETCHING: 'FETCHING', - VISIBLE: 'VISIBLE', + VISIBLE: 'VISIBLE' }); -type State = $Keys; -function ensurePositiveNumber(value: any, defaultValue: number): number { + +function ensurePositiveNumber(value, defaultValue) { if (typeof value !== 'number' || value < 0) { return defaultValue; } @@ -231,40 +271,14 @@ function ensurePositiveNumber(value: any, defaultValue: number): number { } class DatatipManagerForEditor { - _blacklistedPosition: ?atom$Point; - _datatipElement: HTMLElement; - _datatipProviders: ProviderRegistry; - _modifierDatatipProviders: ProviderRegistry; - _datatipState: State; - _editor: atom$TextEditor; - _editorView: atom$TextEditorElement; - _insideDatatip: boolean; - _lastHiddenTime: number; - _lastFetchedFromCursorPosition: boolean; - _lastMoveEvent: ?MouseEvent; - _lastPosition: ?atom$Point; - _lastResultsPromise: ?Promise>; - _heldKeys: Set; - _markerDisposable: ?IDisposable; - _pinnedDatatips: Set; - _range: ?atom$Range; - _shouldDropNextMouseMoveAfterFocus: boolean; - _startFetchingDebounce: () => void; - _hideIfOutsideDebounce: () => void; - _subscriptions: UniversalDisposable; - _interactedWith: boolean; - _checkedScrollable: boolean; - _isScrollable: boolean; - - constructor( - editor: atom$TextEditor, - datatipProviders: ProviderRegistry, - modifierDatatipProviders: ProviderRegistry, - ) { + + constructor(editor, datatipProviders, modifierDatatipProviders) { + _initialiseProps.call(this); + this._editor = editor; this._editorView = atom.views.getView(editor); this._pinnedDatatips = new Set(); - this._subscriptions = new UniversalDisposable(); + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(); this._datatipProviders = datatipProviders; this._modifierDatatipProviders = modifierDatatipProviders; this._datatipElement = document.createElement('div'); @@ -278,179 +292,126 @@ class DatatipManagerForEditor { this._lastFetchedFromCursorPosition = false; this._shouldDropNextMouseMoveAfterFocus = false; - this._subscriptions.add( - featureConfig.observe('atom-ide-datatip.datatipDebounceDelay', () => - this._setStartFetchingDebounce(), - ), - featureConfig.observe( - 'atom-ide-datatip.datatipInteractedWithDebounceDelay', - () => this._setHideIfOutsideDebounce(), - ), - Observable.fromEvent(this._editorView, 'focus').subscribe(e => { - this._shouldDropNextMouseMoveAfterFocus = true; - if (!this._insideDatatip) { - this._setState(DatatipState.HIDDEN); - } - }), - Observable.fromEvent(this._editorView, 'blur').subscribe(e => { - if (!this._insideDatatip) { - this._setState(DatatipState.HIDDEN); - } - }), - Observable.fromEvent(this._editorView, 'mousemove').subscribe(e => { - this._lastFetchedFromCursorPosition = false; - if (this._shouldDropNextMouseMoveAfterFocus) { - this._shouldDropNextMouseMoveAfterFocus = false; - return; - } + this._subscriptions.add((_featureConfig || _load_featureConfig()).default.observe('atom-ide-datatip.datatipDebounceDelay', () => this._setStartFetchingDebounce()), (_featureConfig || _load_featureConfig()).default.observe('atom-ide-datatip.datatipInteractedWithDebounceDelay', () => this._setHideIfOutsideDebounce()), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'focus').subscribe(e => { + this._shouldDropNextMouseMoveAfterFocus = true; + if (!this._insideDatatip) { + this._setState(DatatipState.HIDDEN); + } + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'blur').subscribe(e => { + if (!this._insideDatatip) { + this._setState(DatatipState.HIDDEN); + } + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'mousemove').subscribe(e => { + this._lastFetchedFromCursorPosition = false; + if (this._shouldDropNextMouseMoveAfterFocus) { + this._shouldDropNextMouseMoveAfterFocus = false; + return; + } - this._lastMoveEvent = e; - this._heldKeys = getModifierKeysFromMouseEvent(e); - if (this._datatipState === DatatipState.HIDDEN) { - this._startFetchingDebounce(); - } else { - this._hideIfOutside(); - } - }), - Observable.fromEvent(this._editorView, 'mouseleave').subscribe(() => { - this._lastMoveEvent = null; + this._lastMoveEvent = e; + this._heldKeys = (0, (_getModifierKeys || _load_getModifierKeys()).getModifierKeysFromMouseEvent)(e); + if (this._datatipState === DatatipState.HIDDEN) { + this._startFetchingDebounce(); + } else { this._hideIfOutside(); - }), - Observable.fromEvent(this._editorView, 'mousedown').subscribe(e => { - let node = e.target; - while (node != null) { - if (node === this._datatipElement) { - return; - } - node = node.parentNode; + } + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'mouseleave').subscribe(() => { + this._lastMoveEvent = null; + this._hideIfOutside(); + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'mousedown').subscribe(e => { + let node = e.target; + while (node != null) { + if (node === this._datatipElement) { + return; } + node = node.parentNode; + } - this._hideOrCancel(); - }), - Observable.fromEvent(this._editorView, 'keydown').subscribe(e => { - const modifierKey = getModifierKeyFromKeyboardEvent(e); - if (modifierKey) { - // On Windows, key repeat applies to modifier keys too! - // So it's quite possible that we hit this twice without hitting keyup. - if (this._heldKeys.has(modifierKey)) { - return; - } - this._heldKeys.add(modifierKey); - if (this._datatipState !== DatatipState.HIDDEN) { - this._fetchInResponseToKeyPress(); - } - } else { - this._hideOrCancel(); - } - }), - Observable.fromEvent(this._editorView, 'keyup').subscribe(e => { - const modifierKey = getModifierKeyFromKeyboardEvent(e); - if (modifierKey) { - this._heldKeys.delete(modifierKey); - if (this._datatipState !== DatatipState.HIDDEN) { - this._fetchInResponseToKeyPress(); - } + this._hideOrCancel(); + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'keydown').subscribe(e => { + const modifierKey = (0, (_getModifierKeys || _load_getModifierKeys()).getModifierKeyFromKeyboardEvent)(e); + if (modifierKey) { + // On Windows, key repeat applies to modifier keys too! + // So it's quite possible that we hit this twice without hitting keyup. + if (this._heldKeys.has(modifierKey)) { + return; } - }), - Observable.fromEvent(this._datatipElement, 'wheel').subscribe(e => { - // We'll mark this as an 'interaction' only if the scroll target was scrollable. - // This requires going over the ancestors, so only check this once. - // If it comes back as false, we won't bother checking again. - if (!this._checkedScrollable) { - this._isScrollable = isScrollable(this._datatipElement, e); - this._checkedScrollable = true; + this._heldKeys.add(modifierKey); + if (this._datatipState !== DatatipState.HIDDEN) { + this._fetchInResponseToKeyPress(); } - if (this._isScrollable) { - this._interactedWith = true; - e.stopPropagation(); + } else { + this._hideOrCancel(); + } + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._editorView, 'keyup').subscribe(e => { + const modifierKey = (0, (_getModifierKeys || _load_getModifierKeys()).getModifierKeyFromKeyboardEvent)(e); + if (modifierKey) { + this._heldKeys.delete(modifierKey); + if (this._datatipState !== DatatipState.HIDDEN) { + this._fetchInResponseToKeyPress(); } - }), - Observable.fromEvent(this._datatipElement, 'mousedown').subscribe(() => { + } + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._datatipElement, 'wheel').subscribe(e => { + // We'll mark this as an 'interaction' only if the scroll target was scrollable. + // This requires going over the ancestors, so only check this once. + // If it comes back as false, we won't bother checking again. + if (!this._checkedScrollable) { + this._isScrollable = (0, (_isScrollable || _load_isScrollable()).default)(this._datatipElement, e); + this._checkedScrollable = true; + } + if (this._isScrollable) { this._interactedWith = true; - }), - Observable.fromEvent(this._datatipElement, 'mouseenter').subscribe(() => { - this._insideDatatip = true; - this._hideIfOutside(); - }), - Observable.fromEvent(this._datatipElement, 'mouseleave').subscribe(() => { - this._insideDatatip = false; - this._hideIfOutside(); - }), - this._editorView.onDidChangeScrollTop(() => { - this._lastMoveEvent = null; - if (this._datatipState === DatatipState.VISIBLE) { - this._setState(DatatipState.HIDDEN); - } - }), - this._editor.getBuffer().onDidChangeText(() => { - if (this._datatipState === DatatipState.VISIBLE) { - this._setState(DatatipState.HIDDEN); - } - }), - atom.commands.add( - 'atom-text-editor', - 'datatip:toggle', - this._toggleDatatip, - ), - atom.commands.add( - 'atom-text-editor', - 'datatip:copy-to-clipboard', - this._copyDatatipToClipboard, - ), - ); + e.stopPropagation(); + } + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._datatipElement, 'mousedown').subscribe(() => { + this._interactedWith = true; + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._datatipElement, 'mouseenter').subscribe(() => { + this._insideDatatip = true; + this._hideIfOutside(); + }), _rxjsBundlesRxMinJs.Observable.fromEvent(this._datatipElement, 'mouseleave').subscribe(() => { + this._insideDatatip = false; + this._hideIfOutside(); + }), this._editorView.onDidChangeScrollTop(() => { + this._lastMoveEvent = null; + if (this._datatipState === DatatipState.VISIBLE) { + this._setState(DatatipState.HIDDEN); + } + }), this._editor.getBuffer().onDidChangeText(() => { + if (this._datatipState === DatatipState.VISIBLE) { + this._setState(DatatipState.HIDDEN); + } + }), atom.commands.add('atom-text-editor', 'datatip:toggle', this._toggleDatatip), atom.commands.add('atom-text-editor', 'datatip:copy-to-clipboard', this._copyDatatipToClipboard)); } _fetchInResponseToKeyPress() { if (this._lastFetchedFromCursorPosition) { this._startFetching(() => this._editor.getCursorBufferPosition()); } else { - this._startFetching(() => - getBufferPosition(this._editor, this._editorView, this._lastMoveEvent), - ); + this._startFetching(() => getBufferPosition(this._editor, this._editorView, this._lastMoveEvent)); } } - _setStartFetchingDebounce(): void { - this._startFetchingDebounce = debounce( - () => { - this._startFetching(() => - getBufferPosition( - this._editor, - this._editorView, - this._lastMoveEvent, - ), - ); - }, - ensurePositiveNumber( - (featureConfig.get('atom-ide-datatip.datatipDebounceDelay'): any), - DEFAULT_DATATIP_DEBOUNCE_DELAY, - ), - /* immediate */ false, - ); + _setStartFetchingDebounce() { + this._startFetchingDebounce = (0, (_debounce || _load_debounce()).default)(() => { + this._startFetching(() => getBufferPosition(this._editor, this._editorView, this._lastMoveEvent)); + }, ensurePositiveNumber((_featureConfig || _load_featureConfig()).default.get('atom-ide-datatip.datatipDebounceDelay'), DEFAULT_DATATIP_DEBOUNCE_DELAY), + /* immediate */false); } - _setHideIfOutsideDebounce(): void { - this._hideIfOutsideDebounce = debounce( - () => { - this._hideIfOutsideImmediate(); - }, - ensurePositiveNumber( - (featureConfig.get( - 'atom-ide-datatip.datatipInteractedWithDebounceDelay', - ): any), - DEFAULT_DATATIP_INTERACTED_DEBOUNCE_DELAY, - ), - /* immediate */ false, - ); + _setHideIfOutsideDebounce() { + this._hideIfOutsideDebounce = (0, (_debounce || _load_debounce()).default)(() => { + this._hideIfOutsideImmediate(); + }, ensurePositiveNumber((_featureConfig || _load_featureConfig()).default.get('atom-ide-datatip.datatipInteractedWithDebounceDelay'), DEFAULT_DATATIP_INTERACTED_DEBOUNCE_DELAY), + /* immediate */false); } - dispose(): void { + dispose() { this._setState(DatatipState.HIDDEN); this._subscriptions.dispose(); this._datatipElement.remove(); } - _setState(newState: State): void { + _setState(newState) { const oldState = this._datatipState; this._datatipState = newState; @@ -462,162 +423,135 @@ class DatatipManagerForEditor { } } - async _startFetching(getPosition: () => ?atom$Point): Promise { - const position = getPosition(); - if (!position) { - return; - } + _startFetching(getPosition) { + var _this = this; - const data = await this._fetchAndRender(position); - if (data == null) { - this._setState(DatatipState.HIDDEN); - return; - } - if (this._datatipState !== DatatipState.FETCHING) { - this._setState(DatatipState.HIDDEN); - } + return (0, _asyncToGenerator.default)(function* () { + const position = getPosition(); + if (!position) { + return; + } - if ( - this._blacklistedPosition && - data.range && - data.range.containsPoint(this._blacklistedPosition) - ) { - this._setState(DatatipState.HIDDEN); - return; - } + const data = yield _this._fetchAndRender(position); + if (data == null) { + _this._setState(DatatipState.HIDDEN); + return; + } + if (_this._datatipState !== DatatipState.FETCHING) { + _this._setState(DatatipState.HIDDEN); + } - const currentPosition = getPosition(); - if ( - !currentPosition || - !data.range || - !data.range.containsPoint(currentPosition) - ) { - this._setState(DatatipState.HIDDEN); - return; - } + if (_this._blacklistedPosition && data.range && data.range.containsPoint(_this._blacklistedPosition)) { + _this._setState(DatatipState.HIDDEN); + return; + } - if (this._isHoveringOverPinnedTip()) { - this._setState(DatatipState.HIDDEN); - return; - } + const currentPosition = getPosition(); + if (!currentPosition || !data.range || !data.range.containsPoint(currentPosition)) { + _this._setState(DatatipState.HIDDEN); + return; + } - this._setState(DatatipState.VISIBLE); - this._interactedWith = false; - this._checkedScrollable = false; - this._range = data.range; + if (_this._isHoveringOverPinnedTip()) { + _this._setState(DatatipState.HIDDEN); + return; + } - if (this._markerDisposable) { - this._markerDisposable.dispose(); - } - this._markerDisposable = mountDatatipWithMarker( - this._editor, - this._datatipElement, - data.range, - data.renderedProviders, - currentPosition, - ); + _this._setState(DatatipState.VISIBLE); + _this._interactedWith = false; + _this._checkedScrollable = false; + _this._range = data.range; + + if (_this._markerDisposable) { + _this._markerDisposable.dispose(); + } + _this._markerDisposable = mountDatatipWithMarker(_this._editor, _this._datatipElement, data.range, data.renderedProviders, currentPosition); + })(); } - async _fetch(position: atom$Point): Promise> { - this._setState(DatatipState.FETCHING); + _fetch(position) { + var _this2 = this; - let results: Promise>; - if ( - this._lastPosition != null && - position.isEqual(this._lastPosition) && - this._lastResultsPromise != null - ) { - results = this._lastResultsPromise; - } else { - this._lastResultsPromise = getDatatipResults( - this._datatipProviders, - this._editor, - position, - provider => provider.datatip(this._editor, position), - ); - results = this._lastResultsPromise; - this._lastPosition = position; - } + return (0, _asyncToGenerator.default)(function* () { + _this2._setState(DatatipState.FETCHING); + + let results; + if (_this2._lastPosition != null && position.isEqual(_this2._lastPosition) && _this2._lastResultsPromise != null) { + results = _this2._lastResultsPromise; + } else { + _this2._lastResultsPromise = getDatatipResults(_this2._datatipProviders, _this2._editor, position, function (provider) { + return provider.datatip(_this2._editor, position); + }); + results = _this2._lastResultsPromise; + _this2._lastPosition = position; + } - return (await results).concat( - await getDatatipResults( - this._modifierDatatipProviders, - this._editor, - position, - provider => - provider.modifierDatatip(this._editor, position, this._heldKeys), - ), - ); + return (yield results).concat((yield getDatatipResults(_this2._modifierDatatipProviders, _this2._editor, position, function (provider) { + return provider.modifierDatatip(_this2._editor, position, _this2._heldKeys); + }))); + })(); } - async _fetchAndRender( - position: atom$Point, - ): Promise, - }> { - const datatipsAndProviders = await this._fetch(position); - if (datatipsAndProviders.length === 0) { - return null; - } + _fetchAndRender(position) { + var _this3 = this; - const range = datatipsAndProviders[0].datatip.range; - analytics.track('datatip-popup', { - scope: this._editor.getGrammar().scopeName, - providerName: getProviderName(datatipsAndProviders[0].provider), - rangeStartRow: String(range.start.row), - rangeStartColumn: String(range.start.column), - rangeEndRow: String(range.end.row), - rangeEndColumn: String(range.end.column), - }); + return (0, _asyncToGenerator.default)(function* () { + const datatipsAndProviders = yield _this3._fetch(position); + if (datatipsAndProviders.length === 0) { + return null; + } + + const range = datatipsAndProviders[0].datatip.range; + (_analytics || _load_analytics()).default.track('datatip-popup', { + scope: _this3._editor.getGrammar().scopeName, + providerName: getProviderName(datatipsAndProviders[0].provider), + rangeStartRow: String(range.start.row), + rangeStartColumn: String(range.start.column), + rangeEndRow: String(range.end.row), + rangeEndColumn: String(range.end.column) + }); + + const renderedProviders = _react.createElement( + 'div', + null, + datatipsAndProviders.map(function ({ datatip, provider }) { + return _react.createElement(PinnableDatatip, { + datatip: datatip, + editor: _this3._editor, + key: getProviderName(provider), + onPinClick: _this3._handlePinClicked + }); + }) + ); - const renderedProviders = ( -
- {datatipsAndProviders.map(({datatip, provider}) => ( - - ))} -
- ); - - return { - range, - renderedProviders, - }; + return { + range, + renderedProviders + }; + })(); } - _isHoveringOverPinnedTip(): boolean { + _isHoveringOverPinnedTip() { const pinnedDataTips = Array.from(this._pinnedDatatips.values()); const hoveringTips = pinnedDataTips.filter(dt => dt.isHovering()); return hoveringTips != null && hoveringTips.length > 0; } - _hideDatatip(): void { + _hideDatatip() { this._lastHiddenTime = performance.now(); if (this._markerDisposable) { this._markerDisposable.dispose(); this._markerDisposable = null; } this._range = null; - ReactDOM.unmountComponentAtNode(this._datatipElement); + _reactDom.default.unmountComponentAtNode(this._datatipElement); this._datatipElement.style.display = 'none'; } - _hideOrCancel(): void { - if ( - this._datatipState === DatatipState.HIDDEN || - this._datatipState === DatatipState.FETCHING - ) { + _hideOrCancel() { + if (this._datatipState === DatatipState.HIDDEN || this._datatipState === DatatipState.FETCHING) { if (this._blacklistedPosition == null) { - this._blacklistedPosition = getBufferPosition( - this._editor, - this._editorView, - this._lastMoveEvent, - ); + this._blacklistedPosition = getBufferPosition(this._editor, this._editorView, this._lastMoveEvent); } return; } @@ -625,7 +559,7 @@ class DatatipManagerForEditor { this._setState(DatatipState.HIDDEN); } - _hideIfOutside(): void { + _hideIfOutside() { if (this._datatipState !== DatatipState.VISIBLE) { return; } @@ -637,7 +571,7 @@ class DatatipManagerForEditor { } } - _hideIfOutsideImmediate(): void { + _hideIfOutsideImmediate() { if (this._datatipState !== DatatipState.VISIBLE) { return; } @@ -650,60 +584,52 @@ class DatatipManagerForEditor { return; } - const currentPosition = getBufferPosition( - this._editor, - this._editorView, - this._lastMoveEvent, - ); - if ( - currentPosition && - this._range && - this._range.containsPoint(currentPosition) - ) { + const currentPosition = getBufferPosition(this._editor, this._editorView, this._lastMoveEvent); + if (currentPosition && this._range && this._range.containsPoint(currentPosition)) { return; } this._setState(DatatipState.HIDDEN); } - createPinnedDataTip( - datatip: Datatip, - editor: TextEditor, - options?: PinnedDatatipOptions, - ): PinnedDatatip { - const pinnedDatatip = new PinnedDatatip(datatip, editor, { - ...options, + createPinnedDataTip(datatip, editor, options) { + const pinnedDatatip = new (_PinnedDatatip || _load_PinnedDatatip()).PinnedDatatip(datatip, editor, Object.assign({}, options, { onDispose: () => { this._pinnedDatatips.delete(pinnedDatatip); }, hideDataTips: () => { this._hideDatatip(); - }, - }); + } + })); return pinnedDatatip; } - _handlePinClicked = (editor: TextEditor, datatip: Datatip) => { - analytics.track('datatip-pinned-open'); - const startTime = performanceNow(); +} + +var _initialiseProps = function () { + var _this4 = this; + + this._handlePinClicked = (editor, datatip) => { + (_analytics || _load_analytics()).default.track('datatip-pinned-open'); + const startTime = (0, (_performanceNow || _load_performanceNow()).default)(); this._setState(DatatipState.HIDDEN); - this._pinnedDatatips.add( - new PinnedDatatip(datatip, editor, { - onDispose: pinnedDatatip => { - this._pinnedDatatips.delete(pinnedDatatip); - analytics.track('datatip-pinned-close', { - duration: performanceNow() - startTime, - }); - }, - hideDataTips: () => { - this._hideDatatip(); - }, - position: 'end-of-line', - }), - ); + this._pinnedDatatips.add(new (_PinnedDatatip || _load_PinnedDatatip()).PinnedDatatip(datatip, editor, { + onDispose: pinnedDatatip => { + this._pinnedDatatips.delete(pinnedDatatip); + (_analytics || _load_analytics()).default.track('datatip-pinned-close', { + duration: (0, (_performanceNow || _load_performanceNow()).default)() - startTime + }); + }, + hideDataTips: () => { + this._hideDatatip(); + }, + position: 'end-of-line' + })); }; - _toggleDatatip = (e?: atom$CustomEvent) => { + this._toggleDatatip = e => { + var _ref, _ref2; + if (atom.workspace.getActiveTextEditor() !== this._editor) { return; } @@ -712,24 +638,19 @@ class DatatipManagerForEditor { // keydown, which is going to be triggered before the key binding which is // evaluated on keyup. // $FlowFixMe (v0.54.1 <) - const maybeEventType = idx(e, _ => _.originalEvent.type); + const maybeEventType = (_ref = e) != null ? (_ref2 = _ref.originalEvent) != null ? _ref2.type : _ref2 : _ref; // Unfortunately, when you do keydown of the shortcut, it's going to // hide it, we need to make sure that when we do keyup, it doesn't show // it up right away. We assume that a keypress is done within 100ms // and don't show it again if it was hidden so soon. - const forceShow = - maybeEventType === 'keydown' && - performance.now() - this._lastHiddenTime > 100; + const forceShow = maybeEventType === 'keydown' && performance.now() - this._lastHiddenTime > 100; const forceHide = maybeEventType === 'keyup'; - const forceToggle = - maybeEventType !== 'keydown' && maybeEventType !== 'keyup'; + const forceToggle = maybeEventType !== 'keydown' && maybeEventType !== 'keyup'; if ( - // if we have event information, prefer that for determining show/hide - forceShow || - (forceToggle && this._datatipState === DatatipState.HIDDEN) - ) { + // if we have event information, prefer that for determining show/hide + forceShow || forceToggle && this._datatipState === DatatipState.HIDDEN) { this._lastFetchedFromCursorPosition = true; this._startFetching(() => this._editor.getCursorScreenPosition()); } else if (forceHide || forceToggle) { @@ -737,19 +658,21 @@ class DatatipManagerForEditor { } }; - _copyDatatipToClipboard = async () => { - if (atom.workspace.getActiveTextEditor() !== this._editor) { + this._copyDatatipToClipboard = (0, _asyncToGenerator.default)(function* () { + var _ref3, _ref4; + + if (atom.workspace.getActiveTextEditor() !== _this4._editor) { return; } - const pos = this._editor.getCursorScreenPosition(); + const pos = _this4._editor.getCursorScreenPosition(); if (pos == null) { return; } - const results: Array = await this._fetch(pos); - this._setState(DatatipState.HIDDEN); + const results = yield _this4._fetch(pos); + _this4._setState(DatatipState.HIDDEN); - const tip = idx(results, _ => _[0].datatip); + const tip = (_ref3 = results) != null ? (_ref4 = _ref3[0]) != null ? _ref4.datatip : _ref4 : _ref3; if (tip == null || tip.markedStrings == null) { return; } @@ -759,72 +682,55 @@ class DatatipManagerForEditor { return; } - const value = markedStrings.map(string => string.value).join(); + const value = markedStrings.map(function (string) { + return string.value; + }).join(); if (value === '') { return; } atom.clipboard.write(value); - atom.notifications.addInfo( - `Copied data tip to clipboard: \`\`\`${value}\`\`\``, - ); - }; -} + atom.notifications.addInfo(`Copied data tip to clipboard: \`\`\`${value}\`\`\``); + }); +}; -export class DatatipManager { - _datatipProviders: ProviderRegistry; - _modifierDatatipProviders: ProviderRegistry; - _editorManagers: Map; - _subscriptions: UniversalDisposable; +class DatatipManager { constructor() { - this._subscriptions = new UniversalDisposable(); + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(); this._editorManagers = new Map(); - this._datatipProviders = new ProviderRegistry(); - this._modifierDatatipProviders = new ProviderRegistry(); - - this._subscriptions.add( - observeTextEditors(editor => { - const manager = new DatatipManagerForEditor( - editor, - this._datatipProviders, - this._modifierDatatipProviders, - ); - this._editorManagers.set(editor, manager); - const disposable = new UniversalDisposable(() => { - manager.dispose(); - this._editorManagers.delete(editor); - }); - this._subscriptions.add(disposable); - editor.onDidDestroy(() => disposable.dispose()); - }), - ); + this._datatipProviders = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + this._modifierDatatipProviders = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + + this._subscriptions.add((0, (_textEditor || _load_textEditor()).observeTextEditors)(editor => { + const manager = new DatatipManagerForEditor(editor, this._datatipProviders, this._modifierDatatipProviders); + this._editorManagers.set(editor, manager); + const disposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { + manager.dispose(); + this._editorManagers.delete(editor); + }); + this._subscriptions.add(disposable); + editor.onDidDestroy(() => disposable.dispose()); + })); } - addProvider(provider: DatatipProvider): IDisposable { + addProvider(provider) { return this._datatipProviders.addProvider(provider); } - addModifierProvider(provider: ModifierDatatipProvider): IDisposable { + addModifierProvider(provider) { return this._modifierDatatipProviders.addProvider(provider); } - createPinnedDataTip( - datatip: Datatip, - editor: TextEditor, - options?: PinnedDatatipOptions, - ): PinnedDatatip { + createPinnedDataTip(datatip, editor, options) { const manager = this._editorManagers.get(editor); if (!manager) { - throw new Error( - 'Trying to create a pinned data tip on an editor that has ' + - 'no datatip manager', - ); + throw new Error('Trying to create a pinned data tip on an editor that has ' + 'no datatip manager'); } return manager.createPinnedDataTip(datatip, editor, options); } - dispose(): void { + dispose() { this._subscriptions.dispose(); this._editorManagers.forEach(manager => { manager.dispose(); @@ -832,3 +738,4 @@ export class DatatipManager { this._editorManagers = new Map(); } } +exports.DatatipManager = DatatipManager; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringDatatip.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringDatatip.js index 315ecd90..655a3735 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringDatatip.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringDatatip.js @@ -1,3 +1,27 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _marked; + +function _load_marked() { + return _marked = _interopRequireDefault(require('marked')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _MarkedStringSnippet; + +function _load_MarkedStringSnippet() { + return _MarkedStringSnippet = _interopRequireDefault(require('./MarkedStringSnippet')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,39 +30,31 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {MarkedString} from './types'; - -import marked from 'marked'; -import * as React from 'react'; - -import MarkedStringSnippet from './MarkedStringSnippet'; - -type Props = { - markedStrings: Array, -}; - -export default class MarkedStringDatatip extends React.PureComponent { - render(): React.Node { +class MarkedStringDatatip extends _react.PureComponent { + render() { const elements = this.props.markedStrings.map((chunk, i) => { if (chunk.type === 'markdown') { - return ( -
- ); + return _react.createElement('div', { + className: 'datatip-marked-container', + dangerouslySetInnerHTML: { + __html: (0, (_marked || _load_marked()).default)(chunk.value, { sanitize: true }) + }, + key: i + }); } else { - return ; + return _react.createElement((_MarkedStringSnippet || _load_MarkedStringSnippet()).default, Object.assign({ key: i }, chunk)); } }); - return
{elements}
; + return _react.createElement( + 'div', + { className: 'datatip-marked' }, + elements + ); } } +exports.default = MarkedStringDatatip; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringSnippet.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringSnippet.js index 4337d8e3..778f615c 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringSnippet.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/MarkedStringSnippet.js @@ -1,59 +1,65 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import {TextBuffer} from 'atom'; -import * as React from 'react'; -import {AtomTextEditor} from 'nuclide-commons-ui/AtomTextEditor'; +'use strict'; -// Complex types can end up being super long. Truncate them. -const MAX_LENGTH = 100; +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _atom = require('atom'); + +var _react = _interopRequireWildcard(require('react')); + +var _AtomTextEditor; + +function _load_AtomTextEditor() { + return _AtomTextEditor = require('nuclide-commons-ui/AtomTextEditor'); +} -type Props = { - value: string, - grammar: atom$Grammar, -}; +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } -type State = { - isExpanded: boolean, -}; +// Complex types can end up being super long. Truncate them. +const MAX_LENGTH = 100; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -export default class MarkedStringSnippet extends React.Component { - state = { - isExpanded: false, - }; +class MarkedStringSnippet extends _react.Component { + constructor(...args) { + var _temp; - render(): React.Node { - const {grammar, value} = this.props; + return _temp = super(...args), this.state = { + isExpanded: false + }, _temp; + } + + render() { + const { grammar, value } = this.props; const shouldTruncate = value.length > MAX_LENGTH && !this.state.isExpanded; - const buffer = new TextBuffer( - shouldTruncate ? value.substr(0, MAX_LENGTH) + '...' : value, - ); - return ( -
) => { - this.setState({isExpanded: !this.state.isExpanded}); + const buffer = new _atom.TextBuffer(shouldTruncate ? value.substr(0, MAX_LENGTH) + '...' : value); + return _react.createElement( + 'div', + { + className: 'datatip-marked-text-editor-container', + onClick: e => { + this.setState({ isExpanded: !this.state.isExpanded }); e.stopPropagation(); - }}> - -
+ } }, + _react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { + className: 'datatip-marked-text-editor', + gutterHidden: true, + readOnly: true, + syncTextContents: false, + autoGrow: true, + grammar: grammar, + textBuffer: buffer + }) ); } } +exports.default = MarkedStringSnippet; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/PinnedDatatip.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/PinnedDatatip.js index a0681ba0..9158861a 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/PinnedDatatip.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/PinnedDatatip.js @@ -1,94 +1,79 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Datatip, PinnedDatatipPosition} from './types'; - -type Position = { - x: number, - y: number, -}; - -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import {Observable} from 'rxjs'; -import invariant from 'assert'; -import classnames from 'classnames'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; - -import {DatatipComponent, DATATIP_ACTIONS} from './DatatipComponent'; -import isScrollable from './isScrollable'; - -const LINE_END_MARGIN = 20; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.PinnedDatatip = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _DatatipComponent; + +function _load_DatatipComponent() { + return _DatatipComponent = require('./DatatipComponent'); +} + +var _isScrollable; + +function _load_isScrollable() { + return _isScrollable = _interopRequireDefault(require('./isScrollable')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const LINE_END_MARGIN = 20; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ let _mouseMove$; -function documentMouseMove$(): Observable { +function documentMouseMove$() { if (_mouseMove$ == null) { - _mouseMove$ = Observable.fromEvent(document, 'mousemove'); + _mouseMove$ = _rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mousemove'); } return _mouseMove$; } let _mouseUp$; -function documentMouseUp$(): Observable { +function documentMouseUp$() { if (_mouseUp$ == null) { - _mouseUp$ = Observable.fromEvent(document, 'mouseup'); + _mouseUp$ = _rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mouseup'); } return _mouseUp$; } -export type PinnedDatatipParams = { - onDispose: (pinnedDatatip: PinnedDatatip) => void, - hideDataTips: () => void, - // Defaults to 'end-of-line'. - position?: PinnedDatatipPosition, - // Defaults to true. - showRangeHighlight?: boolean, -}; - -export class PinnedDatatip { - _boundDispose: Function; - _boundHandleMouseDown: Function; - _boundHandleMouseEnter: Function; - _boundHandleMouseLeave: Function; - _boundHandleCapturedClick: Function; - _mouseUpTimeout: ?TimeoutID; - _hostElement: HTMLElement; - _marker: ?atom$Marker; - _rangeDecoration: ?atom$Decoration; - _mouseSubscription: ?rxjs$ISubscription; - _subscriptions: UniversalDisposable; - _datatip: Datatip; - _editor: TextEditor; - _hostElement: HTMLElement; - _boundDispose: Function; - _dragOrigin: ?Position; - _isDragging: boolean; - _offset: Position; - _isHovering: boolean; - _checkedScrollable: boolean; - _isScrollable: boolean; - _hideDataTips: () => void; - _position: PinnedDatatipPosition; - _showRangeHighlight: boolean; - - constructor( - datatip: Datatip, - editor: TextEditor, - params: PinnedDatatipParams, - ) { - this._subscriptions = new UniversalDisposable(); - this._subscriptions.add( - new UniversalDisposable(() => params.onDispose(this)), - ); +class PinnedDatatip { + + constructor(datatip, editor, params) { + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(); + this._subscriptions.add(new (_UniversalDisposable || _load_UniversalDisposable()).default(() => params.onDispose(this))); this._datatip = datatip; this._editor = editor; this._marker = null; @@ -103,75 +88,62 @@ export class PinnedDatatip { this._checkedScrollable = false; this._isScrollable = false; - this._subscriptions.add( - Observable.fromEvent(this._hostElement, 'wheel').subscribe(e => { - if (!this._checkedScrollable) { - this._isScrollable = isScrollable(this._hostElement, e); - this._checkedScrollable = true; - } - if (this._isScrollable) { - e.stopPropagation(); - } - }), - ); - this._hostElement.addEventListener( - 'mouseenter', - this._boundHandleMouseEnter, - ); - this._hostElement.addEventListener( - 'mouseleave', - this._boundHandleMouseLeave, - ); - this._subscriptions.add( - new UniversalDisposable(() => { - this._hostElement.removeEventListener( - 'mouseenter', - this._boundHandleMouseEnter, - ); - this._hostElement.removeEventListener( - 'mouseleave', - this._boundHandleMouseLeave, - ); - }), - ); + this._subscriptions.add(_rxjsBundlesRxMinJs.Observable.fromEvent(this._hostElement, 'wheel').subscribe(e => { + if (!this._checkedScrollable) { + this._isScrollable = (0, (_isScrollable || _load_isScrollable()).default)(this._hostElement, e); + this._checkedScrollable = true; + } + if (this._isScrollable) { + e.stopPropagation(); + } + })); + this._hostElement.addEventListener('mouseenter', this._boundHandleMouseEnter); + this._hostElement.addEventListener('mouseleave', this._boundHandleMouseLeave); + this._subscriptions.add(new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { + this._hostElement.removeEventListener('mouseenter', this._boundHandleMouseEnter); + this._hostElement.removeEventListener('mouseleave', this._boundHandleMouseLeave); + })); this._mouseUpTimeout = null; - this._offset = {x: 0, y: 0}; + this._offset = { x: 0, y: 0 }; this._isDragging = false; this._dragOrigin = null; this._isHovering = false; this._hideDataTips = params.hideDataTips; this._position = params.position == null ? 'end-of-line' : params.position; - this._showRangeHighlight = - params.showRangeHighlight == null ? true : params.showRangeHighlight; + this._showRangeHighlight = params.showRangeHighlight == null ? true : params.showRangeHighlight; this.render(); } - handleMouseEnter(event: MouseEvent): void { + handleMouseEnter(event) { this._isHovering = true; this._hideDataTips(); } - handleMouseLeave(event: MouseEvent): void { + handleMouseLeave(event) { this._isHovering = false; } - isHovering(): boolean { + isHovering() { return this._isHovering; } - handleGlobalMouseMove(event: Event): void { - const evt: MouseEvent = (event: any); - const {_dragOrigin} = this; - invariant(_dragOrigin); + handleGlobalMouseMove(event) { + const evt = event; + const { _dragOrigin } = this; + + if (!_dragOrigin) { + throw new Error('Invariant violation: "_dragOrigin"'); + } + this._isDragging = true; this._offset = { x: evt.clientX - _dragOrigin.x, - y: evt.clientY - _dragOrigin.y, + y: evt.clientY - _dragOrigin.y }; this.render(); } - handleGlobalMouseUp(): void { + handleGlobalMouseUp() { // If the datatip was moved, push the effects of mouseUp to the next tick, // in order to allow cancellation of captured events (e.g. clicks on child components). this._mouseUpTimeout = setTimeout(() => { @@ -183,34 +155,28 @@ export class PinnedDatatip { }, 0); } - _ensureMouseSubscriptionDisposed(): void { + _ensureMouseSubscriptionDisposed() { if (this._mouseSubscription != null) { this._mouseSubscription.unsubscribe(); this._mouseSubscription = null; } } - handleMouseDown(event: Event): void { - const evt: MouseEvent = (event: any); + handleMouseDown(event) { + const evt = event; this._dragOrigin = { x: evt.clientX - this._offset.x, - y: evt.clientY - this._offset.y, + y: evt.clientY - this._offset.y }; this._ensureMouseSubscriptionDisposed(); - this._mouseSubscription = documentMouseMove$() - .takeUntil(documentMouseUp$()) - .subscribe( - (e: MouseEvent) => { - this.handleGlobalMouseMove(e); - }, - (error: any) => {}, - () => { - this.handleGlobalMouseUp(); - }, - ); + this._mouseSubscription = documentMouseMove$().takeUntil(documentMouseUp$()).subscribe(e => { + this.handleGlobalMouseMove(e); + }, error => {}, () => { + this.handleGlobalMouseUp(); + }); } - handleCapturedClick(event: SyntheticEvent<>): void { + handleCapturedClick(event) { if (this._isDragging) { event.stopPropagation(); } else { @@ -220,92 +186,80 @@ export class PinnedDatatip { } // Update the position of the pinned datatip. - _updateHostElementPosition(): void { - const {_editor, _datatip, _hostElement, _offset, _position} = this; - const {range} = _datatip; + _updateHostElementPosition() { + const { _editor, _datatip, _hostElement, _offset, _position } = this; + const { range } = _datatip; _hostElement.style.display = 'block'; switch (_position) { case 'end-of-line': const charWidth = _editor.getDefaultCharWidth(); - const lineLength = _editor.getBuffer().getLines()[range.start.row] - .length; - _hostElement.style.top = - -_editor.getLineHeightInPixels() + _offset.y + 'px'; - _hostElement.style.left = - (lineLength - range.end.column) * charWidth + - LINE_END_MARGIN + - _offset.x + - 'px'; + const lineLength = _editor.getBuffer().getLines()[range.start.row].length; + _hostElement.style.top = -_editor.getLineHeightInPixels() + _offset.y + 'px'; + _hostElement.style.left = (lineLength - range.end.column) * charWidth + LINE_END_MARGIN + _offset.x + 'px'; break; case 'above-range': - _hostElement.style.bottom = - _editor.getLineHeightInPixels() + - _hostElement.clientHeight - - _offset.y + - 'px'; + _hostElement.style.bottom = _editor.getLineHeightInPixels() + _hostElement.clientHeight - _offset.y + 'px'; _hostElement.style.left = _offset.x + 'px'; break; default: - (_position: empty); + _position; throw Error(`Unexpected PinnedDatatip position: ${this._position}`); } } - async render(): Promise { - const {_editor, _datatip, _hostElement, _isDragging, _isHovering} = this; + render() { + var _this = this; - let rangeClassname = 'datatip-highlight-region'; - if (_isHovering) { - rangeClassname += ' datatip-highlight-region-active'; - } + return (0, _asyncToGenerator.default)(function* () { + const { _editor, _datatip, _hostElement, _isDragging, _isHovering } = _this; + + let rangeClassname = 'datatip-highlight-region'; + if (_isHovering) { + rangeClassname += ' datatip-highlight-region-active'; + } - if (this._marker == null) { - const marker: atom$Marker = _editor.markBufferRange(_datatip.range, { - invalidate: 'never', - }); - this._marker = marker; - _editor.decorateMarker(marker, { - type: 'overlay', - position: 'head', - item: this._hostElement, - }); - if (this._showRangeHighlight) { - this._rangeDecoration = _editor.decorateMarker(marker, { + if (_this._marker == null) { + const marker = _editor.markBufferRange(_datatip.range, { + invalidate: 'never' + }); + _this._marker = marker; + _editor.decorateMarker(marker, { + type: 'overlay', + position: 'head', + item: _this._hostElement + }); + if (_this._showRangeHighlight) { + _this._rangeDecoration = _editor.decorateMarker(marker, { + type: 'highlight', + class: rangeClassname + }); + } + yield _editor.getElement().getNextUpdatePromise(); + // Guard against disposals during the await. + if (marker.isDestroyed() || _editor.isDestroyed()) { + return; + } + } else if (_this._rangeDecoration != null) { + _this._rangeDecoration.setProperties({ type: 'highlight', - class: rangeClassname, + class: rangeClassname }); } - await _editor.getElement().getNextUpdatePromise(); - // Guard against disposals during the await. - if (marker.isDestroyed() || _editor.isDestroyed()) { - return; - } - } else if (this._rangeDecoration != null) { - this._rangeDecoration.setProperties({ - type: 'highlight', - class: rangeClassname, - }); - } - ReactDOM.render( - , - _hostElement, - ); - this._updateHostElementPosition(); + _reactDom.default.render(_react.createElement((_DatatipComponent || _load_DatatipComponent()).DatatipComponent, { + action: (_DatatipComponent || _load_DatatipComponent()).DATATIP_ACTIONS.CLOSE, + actionTitle: 'Close this datatip', + className: (0, (_classnames || _load_classnames()).default)(_isDragging ? 'datatip-dragging' : '', 'datatip-pinned'), + datatip: _datatip, + onActionClick: _this._boundDispose, + onMouseDown: _this._boundHandleMouseDown, + onClickCapture: _this._boundHandleCapturedClick + }), _hostElement); + _this._updateHostElementPosition(); + })(); } - dispose(): void { + dispose() { if (this._mouseUpTimeout != null) { clearTimeout(this._mouseUpTimeout); } @@ -315,8 +269,9 @@ export class PinnedDatatip { if (this._mouseSubscription != null) { this._mouseSubscription.unsubscribe(); } - ReactDOM.unmountComponentAtNode(this._hostElement); + _reactDom.default.unmountComponentAtNode(this._hostElement); this._hostElement.remove(); this._subscriptions.dispose(); } } +exports.PinnedDatatip = PinnedDatatip; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/getModifierKeys.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/getModifierKeys.js index 0ec9fd8d..a0806027 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/getModifierKeys.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/getModifierKeys.js @@ -1,3 +1,17 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getModifierKeysFromMouseEvent = getModifierKeysFromMouseEvent; +exports.getModifierKeyFromKeyboardEvent = getModifierKeyFromKeyboardEvent; + +var _types; + +function _load_types() { + return _types = require('./types'); +} + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,40 +20,35 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {ModifierKey} from './types'; -import {ModifierKeys} from './types'; - const KEYNAME_TO_PROPERTY = { - Meta: ModifierKeys.META, - Shift: ModifierKeys.SHIFT, - Alt: ModifierKeys.ALT, - Control: ModifierKeys.CTRL, + Meta: (_types || _load_types()).ModifierKeys.META, + Shift: (_types || _load_types()).ModifierKeys.SHIFT, + Alt: (_types || _load_types()).ModifierKeys.ALT, + Control: (_types || _load_types()).ModifierKeys.CTRL }; -export function getModifierKeysFromMouseEvent(e: MouseEvent): Set { - const keys: Set = new Set(); +function getModifierKeysFromMouseEvent(e) { + const keys = new Set(); if (e.metaKey) { - keys.add(ModifierKeys.META); + keys.add((_types || _load_types()).ModifierKeys.META); } if (e.shiftKey) { - keys.add(ModifierKeys.SHIFT); + keys.add((_types || _load_types()).ModifierKeys.SHIFT); } if (e.altKey) { - keys.add(ModifierKeys.ALT); + keys.add((_types || _load_types()).ModifierKeys.ALT); } if (e.ctrlKey) { - keys.add(ModifierKeys.CTRL); + keys.add((_types || _load_types()).ModifierKeys.CTRL); } return keys; } -export function getModifierKeyFromKeyboardEvent( - e: KeyboardEvent, -): ?ModifierKey { +function getModifierKeyFromKeyboardEvent(e) { return KEYNAME_TO_PROPERTY[e.key]; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/isScrollable.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/isScrollable.js index 2e3fcf0a..adc72e09 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/isScrollable.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/isScrollable.js @@ -1,3 +1,9 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = isScrollable; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,23 +12,17 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -export default function isScrollable( - element: Element, - wheelEvent: WheelEvent, -): boolean { - let node: ?Element = ((wheelEvent.target: any): Element); +function isScrollable(element, wheelEvent) { + let node = wheelEvent.target; while (node != null && node !== element) { - if ( - node.scrollHeight > node.clientHeight || - node.scrollWidth > node.clientWidth - ) { + if (node.scrollHeight > node.clientHeight || node.scrollWidth > node.clientWidth) { return true; } - node = ((node.parentNode: any): Element); + node = node.parentNode; } return false; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/main.js index 3b4b9434..c4bdb806 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/main.js @@ -1,34 +1,42 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {DatatipService} from './types'; - -import createPackage from 'nuclide-commons-atom/createPackage'; -import {DatatipManager} from './DatatipManager'; +'use strict'; + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _DatatipManager; + +function _load_DatatipManager() { + return _DatatipManager = require('./DatatipManager'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class Activation { - _datatipManager: DatatipManager; constructor() { - this._datatipManager = new DatatipManager(); + this._datatipManager = new (_DatatipManager || _load_DatatipManager()).DatatipManager(); } - provideDatatipService(): DatatipService { + provideDatatipService() { return this._datatipManager; } dispose() { this._datatipManager.dispose(); } -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/types.js index aad7d4f8..8f8cebc6 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-datatip/lib/types.js @@ -1,3 +1,8 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +11,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -15,79 +20,11 @@ * You can register providers (which will be triggered on mouseover) or manually * create pinned datatips on-demand. */ -export type DatatipService = { - addProvider(provider: DatatipProvider): IDisposable, - addModifierProvider(provider: ModifierDatatipProvider): IDisposable, - createPinnedDataTip( - datatip: Datatip, - editor: TextEditor, - options?: PinnedDatatipOptions, - ): IDisposable, -}; - -export type PinnedDatatipOptions = {| - // Defaults to 'end-of-line'. - position?: PinnedDatatipPosition, - // Defaults to true. - showRangeHighlight?: boolean, -|}; - -export type PinnedDatatipPosition = 'end-of-line' | 'above-range'; - -export type DatatipProvider = { - priority: number, - grammarScopes?: Array, - // A unique name for the provider to be used for analytics. - // It is recommended that it be the name of the provider's package. - providerName: string, - datatip( - editor: atom$TextEditor, - bufferPosition: atom$Point, - ): Promise, -}; - -export type ModifierDatatipProvider = { - priority: number, - grammarScopes?: Array, - providerName: string, - modifierDatatip( - editor: atom$TextEditor, - bufferPosition: atom$Point, - heldKeys: Set, - ): Promise, -}; - -export type AnyDatatipProvider = DatatipProvider | ModifierDatatipProvider; - -export type Datatip = - | {| - component: React$ComponentType, - range: atom$Range, - pinnable?: boolean, - |} - | {| - markedStrings: Array, - range: atom$Range, - pinnable?: boolean, - |}; - -// Borrowed from the LSP API. -export type MarkedString = - | { - type: 'markdown', - value: string, - } - | { - type: 'snippet', - grammar: atom$Grammar, - value: string, - }; - -export const ModifierKeys = Object.freeze({ +const ModifierKeys = exports.ModifierKeys = Object.freeze({ META: 'metaKey', SHIFT: 'shiftKey', ALT: 'altKey', - CTRL: 'ctrlKey', + CTRL: 'ctrlKey' }); -export type ModifierKey = 'metaKey' | 'shiftKey' | 'altKey' | 'ctrlKey'; +// Borrowed from the LSP API. \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/DefinitionCache.js b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/DefinitionCache.js index 57e6958f..5f05ba7a 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/DefinitionCache.js +++ b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/DefinitionCache.js @@ -1,3 +1,34 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _range; + +function _load_range() { + return _range = require('nuclide-commons-atom/range'); +} + +var _range2; + +function _load_range2() { + return _range2 = require('nuclide-commons/range'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// An atom$Range-aware, single-item cache for the common case of requerying +// a definition (such as previewing hyperclick and then jumping to the +// destination). It invalidates whenever the originating editor changes. /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,63 +37,47 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {DefinitionQueryResult} from './types'; -import {wordAtPosition} from 'nuclide-commons-atom/range'; -import {isPositionInRange} from 'nuclide-commons/range'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; - -// An atom$Range-aware, single-item cache for the common case of requerying -// a definition (such as previewing hyperclick and then jumping to the -// destination). It invalidates whenever the originating editor changes. class DefinitionCache { - _cachedResultEditor: ?atom$TextEditor; - _cachedResultPromise: ?Promise; - _cachedResultRange: ?atom$Range; - _disposables: UniversalDisposable = new UniversalDisposable(); + constructor() { + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(); + } dispose() { this._disposables.dispose(); } - async get( - editor: atom$TextEditor, - position: atom$Point, - getImpl: () => Promise, - ): Promise { - // queryRange is often a list of one range - if ( - this._cachedResultRange != null && - this._cachedResultEditor === editor && - isPositionInRange(position, this._cachedResultRange) - ) { - return this._cachedResultPromise; - } - - // invalidate whenever the buffer changes - const invalidateAndStopListening = () => { - this._cachedResultEditor = null; - this._cachedResultRange = null; - this._cachedResultRange = null; - this._disposables.remove(editorDisposables); - editorDisposables.dispose(); - }; - const editorDisposables = new UniversalDisposable( - editor.getBuffer().onDidChangeText(invalidateAndStopListening), - editor.onDidDestroy(invalidateAndStopListening), - ); - this._disposables.add(editorDisposables); - - const wordGuess = wordAtPosition(editor, position); - this._cachedResultRange = wordGuess && wordGuess.range; - this._cachedResultEditor = editor; - this._cachedResultPromise = getImpl(); - - return this._cachedResultPromise; + get(editor, position, getImpl) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + // queryRange is often a list of one range + if (_this._cachedResultRange != null && _this._cachedResultEditor === editor && (0, (_range2 || _load_range2()).isPositionInRange)(position, _this._cachedResultRange)) { + return _this._cachedResultPromise; + } + + // invalidate whenever the buffer changes + const invalidateAndStopListening = function () { + _this._cachedResultEditor = null; + _this._cachedResultRange = null; + _this._cachedResultRange = null; + _this._disposables.remove(editorDisposables); + editorDisposables.dispose(); + }; + const editorDisposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(editor.getBuffer().onDidChangeText(invalidateAndStopListening), editor.onDidDestroy(invalidateAndStopListening)); + _this._disposables.add(editorDisposables); + + const wordGuess = (0, (_range || _load_range()).wordAtPosition)(editor, position); + _this._cachedResultRange = wordGuess && wordGuess.range; + _this._cachedResultEditor = editor; + _this._cachedResultPromise = getImpl(); + + return _this._cachedResultPromise; + })(); } } -export default DefinitionCache; +exports.default = DefinitionCache; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/getPreviewDatatipFromDefinitionResult.js b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/getPreviewDatatipFromDefinitionResult.js index 807171ef..c60a210e 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/getPreviewDatatipFromDefinitionResult.js +++ b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/getPreviewDatatipFromDefinitionResult.js @@ -1,97 +1,106 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import analytics from 'nuclide-commons-atom/analytics'; -import {getDefinitionPreview as getLocalFileDefinitionPreview} from 'nuclide-commons/symbol-definition-preview'; - -import React from 'react'; -import type {Datatip} from '../../atom-ide-datatip/lib/types'; - -import type {Definition, DefinitionPreviewProvider} from './types'; - -export default (async function getPreviewDatatipFromDefinition( - range: atom$Range, - definitions: Array, - definitionPreviewProvider: ?DefinitionPreviewProvider, - grammar: atom$Grammar, -): Promise { - if (definitions.length === 1) { - const definition = definitions[0]; - // Some providers (e.g. Flow) return negative positions. - if (definition.position.row < 0) { - return null; - } +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); - const definitionPreview = await getPreview( - definition, - definitionPreviewProvider, - ); +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); - if (definitionPreview == null) { - return null; +let getPreview = (() => { + var _ref2 = (0, _asyncToGenerator.default)(function* (definition, definitionPreviewProvider) { + let getDefinitionPreviewFn; + if (definitionPreviewProvider == null) { + getDefinitionPreviewFn = (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview; + } else { + getDefinitionPreviewFn = definitionPreviewProvider.getDefinitionPreview.bind(definitionPreviewProvider); } - // if mimetype is image return image component with base-64 encoded - // image contents, otherwise use markedStrings - if (definitionPreview.mime.startsWith('image/')) { + return (_analytics || _load_analytics()).default.trackTiming('hyperclickPreview.getDefinitionPreview', function () { + return getDefinitionPreviewFn(definition); + }); + }); + + return function getPreview(_x5, _x6) { + return _ref2.apply(this, arguments); + }; +})(); + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _symbolDefinitionPreview; + +function _load_symbolDefinitionPreview() { + return _symbolDefinitionPreview = require('nuclide-commons/symbol-definition-preview'); +} + +var _react = _interopRequireDefault(require('react')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (range, definitions, definitionPreviewProvider, grammar) { + if (definitions.length === 1) { + const definition = definitions[0]; + // Some providers (e.g. Flow) return negative positions. + if (definition.position.row < 0) { + return null; + } + + const definitionPreview = yield getPreview(definition, definitionPreviewProvider); + + if (definitionPreview == null) { + return null; + } + + // if mimetype is image return image component with base-64 encoded + // image contents, otherwise use markedStrings + if (definitionPreview.mime.startsWith('image/')) { + return { + component: function () { + return _react.default.createElement('img', { + src: `data:${definitionPreview.mime};${definitionPreview.encoding},${definitionPreview.contents}` + }); + }, + range + }; + } return { - component: () => ( - - ), - range, - }; - } - return { - markedStrings: [ - { + markedStrings: [{ type: 'snippet', value: definitionPreview.contents, - grammar, - }, - ], - range, - }; - } + grammar + }], + range + }; + } - return { - markedStrings: [ - { + return { + markedStrings: [{ type: 'markdown', value: `${definitions.length} definitions found. Click to jump.`, - grammar, - }, - ], - range, - }; -}); + grammar + }], + range + }; + }); -async function getPreview( - definition: Definition, - definitionPreviewProvider: ?DefinitionPreviewProvider, -) { - let getDefinitionPreviewFn; - if (definitionPreviewProvider == null) { - getDefinitionPreviewFn = getLocalFileDefinitionPreview; - } else { - getDefinitionPreviewFn = definitionPreviewProvider.getDefinitionPreview.bind( - definitionPreviewProvider, - ); + function getPreviewDatatipFromDefinition(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); } - return analytics.trackTiming('hyperclickPreview.getDefinitionPreview', () => - getDefinitionPreviewFn(definition), - ); -} + return getPreviewDatatipFromDefinition; +})(); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/main.js index 022b8bc2..480a1a2b 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/main.js @@ -1,3 +1,77 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +var _atom = require('atom'); + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _range; + +function _load_range() { + return _range = require('nuclide-commons-atom/range'); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _ProviderRegistry; + +function _load_ProviderRegistry() { + return _ProviderRegistry = _interopRequireDefault(require('nuclide-commons-atom/ProviderRegistry')); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _DefinitionCache; + +function _load_DefinitionCache() { + return _DefinitionCache = _interopRequireDefault(require('./DefinitionCache')); +} + +var _getPreviewDatatipFromDefinitionResult; + +function _load_getPreviewDatatipFromDefinitionResult() { + return _getPreviewDatatipFromDefinitionResult = _interopRequireDefault(require('./getPreviewDatatipFromDefinitionResult')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,228 +80,178 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ // This package provides Hyperclick results for any language which provides a // DefinitionProvider. -import type { - HyperclickProvider, - HyperclickSuggestion, -} from '../../hyperclick/lib/types'; - -import type { - Datatip, - DatatipService, - ModifierDatatipProvider, - ModifierKey, -} from '../../atom-ide-datatip/lib/types'; - -import type { - DefinitionQueryResult, - DefinitionProvider, - DefinitionPreviewProvider, -} from './types'; - -import invariant from 'assert'; -import {getLogger} from 'log4js'; -import {Range} from 'atom'; - -import analytics from 'nuclide-commons-atom/analytics'; -import createPackage from 'nuclide-commons-atom/createPackage'; -import FeatureConfig from 'nuclide-commons-atom/feature-config'; -import {wordAtPosition} from 'nuclide-commons-atom/range'; -import nuclideUri from 'nuclide-commons/nuclideUri'; -import ProviderRegistry from 'nuclide-commons-atom/ProviderRegistry'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; - -import DefinitionCache from './DefinitionCache'; -import getPreviewDatatipFromDefinitionResult from './getPreviewDatatipFromDefinitionResult'; - class Activation { - _providers: ProviderRegistry; - _definitionPreviewProvider: ?DefinitionPreviewProvider; - _definitionCache: DefinitionCache; - _disposables: UniversalDisposable; - _triggerKeys: Set; constructor() { - this._providers = new ProviderRegistry(); - this._definitionCache = new DefinitionCache(); + this._providers = new (_ProviderRegistry || _load_ProviderRegistry()).default(); + this._definitionCache = new (_DefinitionCache || _load_DefinitionCache()).default(); this._triggerKeys = new Set(); - this._disposables = new UniversalDisposable( - FeatureConfig.observe( - getPlatformKeys(process.platform), - (newValue: ?string) => { - this._triggerKeys = (new Set( - // flowlint-next-line sketchy-null-string:off - newValue ? newValue.split(',') : null, - ): Set); - }, - ), - ); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default((_featureConfig || _load_featureConfig()).default.observe(getPlatformKeys(process.platform), newValue => { + this._triggerKeys = new Set( + // flowlint-next-line sketchy-null-string:off + newValue ? newValue.split(',') : null); + })); } dispose() { this._disposables.dispose(); } - async _getDefinition( - editor: atom$TextEditor, - position: atom$Point, - ): Promise { - for (const provider of this._providers.getAllProvidersForEditor(editor)) { - try { - // eslint-disable-next-line no-await-in-loop - const result = await provider.getDefinition(editor, position); - if (result != null) { - if (result.queryRange == null) { - const match = wordAtPosition(editor, position, { - includeNonWordCharacters: false, - }); - result.queryRange = [ - match != null ? match.range : new Range(position, position), - ]; + _getDefinition(editor, position) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + for (const provider of _this._providers.getAllProvidersForEditor(editor)) { + try { + // eslint-disable-next-line no-await-in-loop + const result = yield provider.getDefinition(editor, position); + if (result != null) { + if (result.queryRange == null) { + const match = (0, (_range || _load_range()).wordAtPosition)(editor, position, { + includeNonWordCharacters: false + }); + result.queryRange = [match != null ? match.range : new _atom.Range(position, position)]; + } + return result; } - return result; + } catch (err) { + (0, (_log4js || _load_log4js()).getLogger)('atom-ide-definitions').error(`Error getting definition for ${String(editor.getPath())}`, err); } - } catch (err) { - getLogger('atom-ide-definitions').error( - `Error getting definition for ${String(editor.getPath())}`, - err, - ); } - } - return null; + return null; + })(); } - async getSuggestion( - editor: atom$TextEditor, - position: atom$Point, - ): Promise { - const result = await this._definitionCache.get(editor, position, () => - this._getDefinition(editor, position), - ); + getSuggestion(editor, position) { + var _this2 = this; - if (result == null) { - return null; - } - - const {queryRange, definitions} = result; - invariant(definitions.length > 0); - // queryRange might be null coming out of the provider, but the output - // of _getDefinition has ensured it's not null. - invariant(queryRange != null); - - function createCallback(definition) { - return () => { - goToLocation(definition.path, { - line: definition.position.row, - column: definition.position.column, - }); - analytics.track('go-to-definition', { - path: definition.path, - line: definition.position.row, - column: definition.position.column, - from: editor.getPath(), - }); - }; - } - - function createTitle(definition) { - const filePath = - definition.projectRoot == null - ? definition.path - : nuclideUri.relative(definition.projectRoot, definition.path); - if (definition.name == null) { - // Fall back to just displaying the path:line. - return `${filePath}:${definition.position.row + 1}`; + return (0, _asyncToGenerator.default)(function* () { + const result = yield _this2._definitionCache.get(editor, position, function () { + return _this2._getDefinition(editor, position); + }); + + if (result == null) { + return null; + } + + const { queryRange, definitions } = result; + + if (!(definitions.length > 0)) { + throw new Error('Invariant violation: "definitions.length > 0"'); + } + // queryRange might be null coming out of the provider, but the output + // of _getDefinition has ensured it's not null. + + + if (!(queryRange != null)) { + throw new Error('Invariant violation: "queryRange != null"'); + } + + function createCallback(definition) { + return () => { + (0, (_goToLocation || _load_goToLocation()).goToLocation)(definition.path, { + line: definition.position.row, + column: definition.position.column + }); + (_analytics || _load_analytics()).default.track('go-to-definition', { + path: definition.path, + line: definition.position.row, + column: definition.position.column, + from: editor.getPath() + }); + }; } - return `${definition.name} (${filePath})`; - } - - if (definitions.length === 1) { - return { - range: queryRange, - callback: createCallback(definitions[0]), - }; - } else { - return { - range: queryRange, - callback: definitions.map(definition => { - return { - title: createTitle(definition), - callback: createCallback(definition), - }; - }), - }; - } + + function createTitle(definition) { + const filePath = definition.projectRoot == null ? definition.path : (_nuclideUri || _load_nuclideUri()).default.relative(definition.projectRoot, definition.path); + if (definition.name == null) { + // Fall back to just displaying the path:line. + return `${filePath}:${definition.position.row + 1}`; + } + return `${definition.name} (${filePath})`; + } + + if (definitions.length === 1) { + return { + range: queryRange, + callback: createCallback(definitions[0]) + }; + } else { + return { + range: queryRange, + callback: definitions.map(function (definition) { + return { + title: createTitle(definition), + callback: createCallback(definition) + }; + }) + }; + } + })(); } - async getPreview( - editor: atom$TextEditor, - position: atom$Point, - heldKeys: Set, - ): Promise { - if ( - !this._triggerKeys || + getPreview(editor, position, heldKeys) { + var _this3 = this; + + return (0, _asyncToGenerator.default)(function* () { + if (!_this3._triggerKeys || // are the required keys held down? - !Array.from(this._triggerKeys).every(key => heldKeys.has(key)) - ) { - return; - } + !Array.from(_this3._triggerKeys).every(function (key) { + return heldKeys.has(key); + })) { + return; + } - const result = await this._getDefinition(editor, position); - if (result == null) { - return null; - } - const queryRange = result.queryRange; - // queryRange might be null coming out of the provider, but the output - // of _getDefinition has ensured it's not null. - invariant(queryRange != null); - - const grammar = editor.getGrammar(); - const previewDatatip = getPreviewDatatipFromDefinitionResult( - queryRange[0], - result.definitions, - this._definitionPreviewProvider, - grammar, - ); - - // flowlint-next-line sketchy-null-mixed:off - if (previewDatatip != null && previewDatatip.markedStrings) { - analytics.track('hyperclick-preview-popup', { - grammar: grammar.name, - definitionCount: result.definitions.length, - }); - } + const result = yield _this3._getDefinition(editor, position); + if (result == null) { + return null; + } + const queryRange = result.queryRange; + // queryRange might be null coming out of the provider, but the output + // of _getDefinition has ensured it's not null. + + if (!(queryRange != null)) { + throw new Error('Invariant violation: "queryRange != null"'); + } + + const grammar = editor.getGrammar(); + const previewDatatip = (0, (_getPreviewDatatipFromDefinitionResult || _load_getPreviewDatatipFromDefinitionResult()).default)(queryRange[0], result.definitions, _this3._definitionPreviewProvider, grammar); + + // flowlint-next-line sketchy-null-mixed:off + if (previewDatatip != null && previewDatatip.markedStrings) { + (_analytics || _load_analytics()).default.track('hyperclick-preview-popup', { + grammar: grammar.name, + definitionCount: result.definitions.length + }); + } - return previewDatatip; + return previewDatatip; + })(); } - consumeDefinitionProvider(provider: DefinitionProvider): IDisposable { + consumeDefinitionProvider(provider) { const disposable = this._providers.addProvider(provider); this._disposables.add(disposable); return disposable; } - consumeDefinitionPreviewProvider(provider: DefinitionPreviewProvider) { + consumeDefinitionPreviewProvider(provider) { this._definitionPreviewProvider = provider; } - consumeDatatipService(service: DatatipService): IDisposable { - const datatipProvider: ModifierDatatipProvider = { + consumeDatatipService(service) { + const datatipProvider = { providerName: 'hyperclick-preview', priority: 1, - modifierDatatip: ( - editor: atom$TextEditor, - bufferPosition: atom$Point, - heldKeys: Set, - ) => this.getPreview(editor, bufferPosition, heldKeys), + modifierDatatip: (editor, bufferPosition, heldKeys) => this.getPreview(editor, bufferPosition, heldKeys) }; const disposable = service.addModifierProvider(datatipProvider); @@ -235,11 +259,11 @@ class Activation { return disposable; } - getHyperclickProvider(): HyperclickProvider { + getHyperclickProvider() { return { priority: 20, providerName: 'atom-ide-definitions', - getSuggestion: (editor, position) => this.getSuggestion(editor, position), + getSuggestion: (editor, position) => this.getSuggestion(editor, position) }; } } @@ -253,4 +277,4 @@ function getPlatformKeys(platform) { return 'hyperclick.linuxTriggerKeys'; } -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/types.js index bc79cea7..a726efc4 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-definitions/lib/types.js @@ -1,61 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; - -export type Definition = { - // Path of the file in which the definition is located. - path: NuclideUri, - // First character of the definition's identifier. - // e.g. "F" in `class Foo {}` - position: atom$Point, - // Optional: the range of the entire definition. - // e.g. "c" to "}" in `class Foo {}` - range?: atom$Range, - // Optional: `name` and `projectRoot` can be provided to display a more human-readable title - // inside of Hyperclick when there are multiple definitions. - name?: string, - // If provided, `projectRoot` will be used to display a relativized version of `path`. - projectRoot?: NuclideUri, - // `language` may be used by consumers to identify the source of definitions. - language: string, -}; - -// Definition queries supply a point. -// The returned queryRange is the range within which the returned definition is valid. -// Typically queryRange spans the containing identifier around the query point. -export type DefinitionQueryResult = { - queryRange: ?Array, - definitions: Array, -}; - -// Provides definitions for a set of language grammars. -export type DefinitionProvider = { - // If there are multiple providers for a given grammar, - // the one with the highest priority will be used. - priority: number, - grammarScopes: Array, - getDefinition: ( - editor: TextEditor, - position: atom$Point, - ) => Promise, -}; - -export type DefinitionPreviewProvider = { - getDefinitionPreview( - definition: Definition, - ): Promise, -}; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-definitions/spec/DefinitionHyperclick-spec.js b/modules/atom-ide-ui/pkg/atom-ide-definitions/spec/DefinitionHyperclick-spec.js index 86116593..cd99cb4b 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-definitions/spec/DefinitionHyperclick-spec.js +++ b/modules/atom-ide-ui/pkg/atom-ide-definitions/spec/DefinitionHyperclick-spec.js @@ -1,3 +1,17 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _atom = require('atom'); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,52 +20,32 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type { - HyperclickProvider, - HyperclickSuggestion, -} from '../../hyperclick/lib/types'; -import type {DefinitionProvider} from '../lib/types'; - -import {Point, Range, TextEditor} from 'atom'; -import invariant from 'assert'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; - describe('DefinitionHyperclick', () => { - let provider: ?HyperclickProvider; - const definitionProvider: DefinitionProvider = { + let provider; + const definitionProvider = { priority: 20, name: '', grammarScopes: ['text.plain.null-grammar'], - getDefinition: () => Promise.resolve(null), + getDefinition: () => Promise.resolve(null) }; - let editor: TextEditor; - const position = new Point(0, 0); + let editor; + const position = new _atom.Point(0, 0); let goToLocation; let disposables; beforeEach(() => { atom.packages.activatePackage('atom-ide-definitions'); - editor = new TextEditor(); - - goToLocation = spyOn( - require('nuclide-commons-atom/go-to-location'), - 'goToLocation', - ); - - disposables = new UniversalDisposable( - atom.packages.serviceHub.provide( - 'definitions', - '0.1.0', - definitionProvider, - ), - atom.packages.serviceHub.consume('hyperclick', '0.1.0', x => { - provider = x; - }), - ); + editor = new _atom.TextEditor(); + + goToLocation = spyOn(require('nuclide-commons-atom/go-to-location'), 'goToLocation'); + + disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.packages.serviceHub.provide('definitions', '0.1.0', definitionProvider), atom.packages.serviceHub.consume('hyperclick', '0.1.0', x => { + provider = x; + })); }); afterEach(() => { @@ -59,112 +53,137 @@ describe('DefinitionHyperclick', () => { }); it('no definition service', () => { - waitsForPromise(async () => { - spyOn(editor, 'getGrammar').andReturn({scopeName: 'blah'}); - invariant(provider != null); - invariant(provider.getSuggestion != null); - const result = await provider.getSuggestion(editor, position); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + spyOn(editor, 'getGrammar').andReturn({ scopeName: 'blah' }); + + if (!(provider != null)) { + throw new Error('Invariant violation: "provider != null"'); + } + + if (!(provider.getSuggestion != null)) { + throw new Error('Invariant violation: "provider.getSuggestion != null"'); + } + + const result = yield provider.getSuggestion(editor, position); expect(result).toBe(null); - }); + })); }); it('no definition', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const spy = spyOn(definitionProvider, 'getDefinition').andReturn(null); - invariant(provider != null); - invariant(provider.getSuggestion != null); - const result = await provider.getSuggestion(editor, position); + + if (!(provider != null)) { + throw new Error('Invariant violation: "provider != null"'); + } + + if (!(provider.getSuggestion != null)) { + throw new Error('Invariant violation: "provider.getSuggestion != null"'); + } + + const result = yield provider.getSuggestion(editor, position); expect(result).toBe(null); expect(spy).toHaveBeenCalledWith(editor, position); - }); + })); }); it('definition - single', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const definition = { - queryRange: [new Range(new Point(1, 1), new Point(1, 5))], - definitions: [ - { - path: 'path1', - position: new Point(1, 2), - range: null, - id: 'symbol-name', - name: null, - projectRoot: null, - }, - ], + queryRange: [new _atom.Range(new _atom.Point(1, 1), new _atom.Point(1, 5))], + definitions: [{ + path: 'path1', + position: new _atom.Point(1, 2), + range: null, + id: 'symbol-name', + name: null, + projectRoot: null + }] }; - const spy = spyOn(definitionProvider, 'getDefinition').andReturn( - Promise.resolve(definition), - ); + const spy = spyOn(definitionProvider, 'getDefinition').andReturn(Promise.resolve(definition)); - invariant(provider != null); - invariant(provider.getSuggestion != null); - const result = await provider.getSuggestion(editor, position); + if (!(provider != null)) { + throw new Error('Invariant violation: "provider != null"'); + } + + if (!(provider.getSuggestion != null)) { + throw new Error('Invariant violation: "provider.getSuggestion != null"'); + } + + const result = yield provider.getSuggestion(editor, position); + + if (!(result != null)) { + throw new Error('Invariant violation: "result != null"'); + } - invariant(result != null); expect(result.range).toEqual(definition.queryRange); expect(spy).toHaveBeenCalledWith(editor, position); expect(goToLocation).not.toHaveBeenCalled(); - invariant(result != null); - invariant(result.callback != null); - invariant(typeof result.callback === 'function'); + if (!(result != null)) { + throw new Error('Invariant violation: "result != null"'); + } + + if (!(result.callback != null)) { + throw new Error('Invariant violation: "result.callback != null"'); + } + + if (!(typeof result.callback === 'function')) { + throw new Error('Invariant violation: "typeof result.callback === \'function\'"'); + } + result.callback(); - expect(goToLocation).toHaveBeenCalledWith('path1', {line: 1, column: 2}); - }); + expect(goToLocation).toHaveBeenCalledWith('path1', { line: 1, column: 2 }); + })); }); it('definition - multiple', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const defs = { - queryRange: [new Range(new Point(1, 1), new Point(1, 5))], - definitions: [ - { - path: '/a/b/path1', - position: new Point(1, 2), - range: null, - id: 'symbol-name', - name: 'd1', - projectRoot: '/a', - }, - { - path: '/a/b/path2', - position: new Point(3, 4), - range: null, - id: 'symbol-name2', - name: 'd2', - projectRoot: '/a', - }, - { - path: '/a/b/path3', - position: new Point(3, 4), - range: null, - id: 'symbol-without-name', - projectRoot: '/a', - }, - ], + queryRange: [new _atom.Range(new _atom.Point(1, 1), new _atom.Point(1, 5))], + definitions: [{ + path: '/a/b/path1', + position: new _atom.Point(1, 2), + range: null, + id: 'symbol-name', + name: 'd1', + projectRoot: '/a' + }, { + path: '/a/b/path2', + position: new _atom.Point(3, 4), + range: null, + id: 'symbol-name2', + name: 'd2', + projectRoot: '/a' + }, { + path: '/a/b/path3', + position: new _atom.Point(3, 4), + range: null, + id: 'symbol-without-name', + projectRoot: '/a' + }] }; - const spy = spyOn(definitionProvider, 'getDefinition').andReturn( - Promise.resolve(defs), - ); - - invariant(provider != null); - invariant(provider.getSuggestion != null); - const result: ?HyperclickSuggestion = await provider.getSuggestion( - editor, - position, - ); - - invariant(result != null); + const spy = spyOn(definitionProvider, 'getDefinition').andReturn(Promise.resolve(defs)); + + if (!(provider != null)) { + throw new Error('Invariant violation: "provider != null"'); + } + + if (!(provider.getSuggestion != null)) { + throw new Error('Invariant violation: "provider.getSuggestion != null"'); + } + + const result = yield provider.getSuggestion(editor, position); + + if (!(result != null)) { + throw new Error('Invariant violation: "result != null"'); + } + expect(result.range).toEqual(defs.queryRange); expect(spy).toHaveBeenCalledWith(editor, position); expect(goToLocation).not.toHaveBeenCalled(); - const callbacks: Array<{ - title: string, - callback: () => mixed, - }> = (result.callback: any); + const callbacks = result.callback; expect(callbacks.length).toBe(3); expect(callbacks[0].title).toBe('d1 (b/path1)'); @@ -177,39 +196,50 @@ describe('DefinitionHyperclick', () => { callbacks[1].callback(); expect(goToLocation).toHaveBeenCalledWith('/a/b/path2', { line: 3, - column: 4, + column: 4 }); - }); + })); }); it('falls back to lower-priority providers', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const def = { - queryRange: [new Range(new Point(1, 1), new Point(1, 5))], - definitions: [ - { - path: 'path1', - position: new Point(1, 2), - range: null, - id: 'symbol-name', - name: null, - projectRoot: null, - }, - ], + queryRange: [new _atom.Range(new _atom.Point(1, 1), new _atom.Point(1, 5))], + definitions: [{ + path: 'path1', + position: new _atom.Point(1, 2), + range: null, + id: 'symbol-name', + name: null, + projectRoot: null + }] }; const newProvider = { priority: 10, name: '', grammarScopes: ['text.plain.null-grammar'], - getDefinition: () => Promise.resolve(def), + getDefinition: function () { + return Promise.resolve(def); + } }; atom.packages.serviceHub.provide('definitions', '0.1.0', newProvider); - invariant(provider != null); - invariant(provider.getSuggestion != null); - const result = await provider.getSuggestion(editor, position); + + if (!(provider != null)) { + throw new Error('Invariant violation: "provider != null"'); + } + + if (!(provider.getSuggestion != null)) { + throw new Error('Invariant violation: "provider.getSuggestion != null"'); + } + + const result = yield provider.getSuggestion(editor, position); expect(result).not.toBe(null); - invariant(result != null); + + if (!(result != null)) { + throw new Error('Invariant violation: "result != null"'); + } + expect(result.range).toEqual(def.queryRange); - }); + })); }); -}); +}); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/DiagnosticsViewModel.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/DiagnosticsViewModel.js index 8a7d23cf..616dcd17 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/DiagnosticsViewModel.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/DiagnosticsViewModel.js @@ -1,3 +1,108 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DiagnosticsViewModel = exports.WORKSPACE_VIEW_URI = undefined; + +var _dockForLocation; + +function _load_dockForLocation() { + return _dockForLocation = _interopRequireDefault(require('nuclide-commons-atom/dock-for-location')); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _memoizeUntilChanged; + +function _load_memoizeUntilChanged() { + return _memoizeUntilChanged = _interopRequireDefault(require('nuclide-commons/memoizeUntilChanged')); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _observePaneItemVisibility; + +function _load_observePaneItemVisibility() { + return _observePaneItemVisibility = _interopRequireDefault(require('nuclide-commons-atom/observePaneItemVisibility')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _react = _interopRequireDefault(require('react')); + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _Model; + +function _load_Model() { + return _Model = _interopRequireDefault(require('nuclide-commons/Model')); +} + +var _renderReactRoot; + +function _load_renderReactRoot() { + return _renderReactRoot = require('nuclide-commons-ui/renderReactRoot'); +} + +var _bindObservableAsProps; + +function _load_bindObservableAsProps() { + return _bindObservableAsProps = require('nuclide-commons-ui/bindObservableAsProps'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _RegExpFilter; + +function _load_RegExpFilter() { + return _RegExpFilter = require('nuclide-commons-ui/RegExpFilter'); +} + +var _GroupUtils; + +function _load_GroupUtils() { + return _GroupUtils = _interopRequireWildcard(require('./GroupUtils')); +} + +var _DiagnosticsView; + +function _load_DiagnosticsView() { + return _DiagnosticsView = _interopRequireDefault(require('./ui/DiagnosticsView')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,136 +111,57 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {IconName} from 'nuclide-commons-ui/Icon'; -import type {Props} from './ui/DiagnosticsView'; -import type {DiagnosticGroup, GlobalViewState} from './types'; -import type {DiagnosticMessage} from '../../atom-ide-diagnostics/lib/types'; -import type {RegExpFilterChange} from 'nuclide-commons-ui/RegExpFilter'; - -import dockForLocation from 'nuclide-commons-atom/dock-for-location'; -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; -import memoizeUntilChanged from 'nuclide-commons/memoizeUntilChanged'; -import nuclideUri from 'nuclide-commons/nuclideUri'; -import observePaneItemVisibility from 'nuclide-commons-atom/observePaneItemVisibility'; -import {arrayEqual, areSetsEqual} from 'nuclide-commons/collection'; -import {fastDebounce} from 'nuclide-commons/observable'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import React from 'react'; -import analytics from 'nuclide-commons-atom/analytics'; -import Model from 'nuclide-commons/Model'; -import {renderReactRoot} from 'nuclide-commons-ui/renderReactRoot'; -import {bindObservableAsProps} from 'nuclide-commons-ui/bindObservableAsProps'; -import {Observable} from 'rxjs'; -import {getFilterPattern} from 'nuclide-commons-ui/RegExpFilter'; -import * as GroupUtils from './GroupUtils'; -import DiagnosticsView from './ui/DiagnosticsView'; - -type SerializedDiagnosticsViewModel = { - deserializer: 'atom-ide-ui.DiagnosticsViewModel', - state: { - hiddenGroups: Array, - }, -}; +const WORKSPACE_VIEW_URI = exports.WORKSPACE_VIEW_URI = 'atom://nuclide/diagnostics'; + +class DiagnosticsViewModel { + + constructor(globalStates) { + _initialiseProps.call(this); -type State = {| - hiddenGroups: Set, - selectedMessage: ?DiagnosticMessage, - textFilter: {| - text: string, - isRegExp: boolean, - invalid: boolean, - pattern: ?RegExp, - |}, -|}; - -export const WORKSPACE_VIEW_URI = 'atom://nuclide/diagnostics'; - -export class DiagnosticsViewModel { - _element: ?HTMLElement; - _model: Model; - _props: Observable; - _disposables: IDisposable; - - constructor(globalStates: Observable) { // Memoize `_filterDiagnostics()` - (this: any)._filterDiagnostics = memoizeUntilChanged( - this._filterDiagnostics, - (diagnostics, pattern, hiddenGroups, filterPath) => ({ - diagnostics, - pattern, - hiddenGroups, - filterPath, - }), - (a, b) => - patternsAreEqual(a.pattern, b.pattern) && - areSetsEqual(a.hiddenGroups, b.hiddenGroups) && - arrayEqual(a.diagnostics, b.diagnostics) && - a.filterPath === b.filterPath, - ); - - const {pattern, invalid} = getFilterPattern('', false); - this._model = new Model({ + this._filterDiagnostics = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(this._filterDiagnostics, (diagnostics, pattern, hiddenGroups, filterPath) => ({ + diagnostics, + pattern, + hiddenGroups, + filterPath + }), (a, b) => patternsAreEqual(a.pattern, b.pattern) && (0, (_collection || _load_collection()).areSetsEqual)(a.hiddenGroups, b.hiddenGroups) && (0, (_collection || _load_collection()).arrayEqual)(a.diagnostics, b.diagnostics) && a.filterPath === b.filterPath); + + const { pattern, invalid } = (0, (_RegExpFilter || _load_RegExpFilter()).getFilterPattern)('', false); + this._model = new (_Model || _load_Model()).default({ // TODO: Get this from constructor/serialization. hiddenGroups: new Set(), - textFilter: {text: '', isRegExp: false, pattern, invalid}, - selectedMessage: null, + textFilter: { text: '', isRegExp: false, pattern, invalid }, + selectedMessage: null }); - const visibility = observePaneItemVisibility(this).distinctUntilChanged(); - this._disposables = new UniversalDisposable( - visibility - .let(fastDebounce(1000)) - .distinctUntilChanged() - .filter(Boolean) - .subscribe(() => { - analytics.track('diagnostics-show-table'); - }), - ); + const visibility = (0, (_observePaneItemVisibility || _load_observePaneItemVisibility()).default)(this).distinctUntilChanged(); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(visibility.let((0, (_observable || _load_observable()).fastDebounce)(1000)).distinctUntilChanged().filter(Boolean).subscribe(() => { + (_analytics || _load_analytics()).default.track('diagnostics-show-table'); + })); // Combine the state that's shared between instances, the state that's unique to this instance, // and unchanging callbacks, to get the props for our component. - const props = Observable.combineLatest( - globalStates, - this._model.toObservable(), - visibility, - (globalState, instanceState, isVisible) => ({ - ...globalState, - ...instanceState, - isVisible, - diagnostics: this._filterDiagnostics( - globalState.diagnostics, - instanceState.textFilter.pattern, - instanceState.hiddenGroups, - globalState.filterByActiveTextEditor - ? globalState.pathToActiveTextEditor - : null, - ), - onTypeFilterChange: this._handleTypeFilterChange, - onTextFilterChange: this._handleTextFilterChange, - selectMessage: this._selectMessage, - gotoMessageLocation: goToDiagnosticLocation, - supportedMessageKinds: globalState.supportedMessageKinds, - }), - ); + const props = _rxjsBundlesRxMinJs.Observable.combineLatest(globalStates, this._model.toObservable(), visibility, (globalState, instanceState, isVisible) => Object.assign({}, globalState, instanceState, { + isVisible, + diagnostics: this._filterDiagnostics(globalState.diagnostics, instanceState.textFilter.pattern, instanceState.hiddenGroups, globalState.filterByActiveTextEditor ? globalState.pathToActiveTextEditor : null), + onTypeFilterChange: this._handleTypeFilterChange, + onTextFilterChange: this._handleTextFilterChange, + selectMessage: this._selectMessage, + gotoMessageLocation: goToDiagnosticLocation, + supportedMessageKinds: globalState.supportedMessageKinds + })); this._props = this._trackVisibility(props); } // If autoVisibility setting is on, then automatically show/hide on changes. - _trackVisibility(props: Observable): Observable { + _trackVisibility(props) { let lastDiagnostics = []; return props.do(newProps => { - if ( - newProps.autoVisibility && - !arrayEqual( - newProps.diagnostics, - lastDiagnostics, - (a, b) => a.text === b.text, - ) - ) { + if (newProps.autoVisibility && !(0, (_collection || _load_collection()).arrayEqual)(newProps.diagnostics, lastDiagnostics, (a, b) => a.text === b.text)) { const pane = atom.workspace.paneForItem(this); if (newProps.diagnostics.length > 0 && !newProps.isVisible) { // We want to call workspace.open but it has no option to @@ -144,7 +170,7 @@ export class DiagnosticsViewModel { // https://github.com/atom/atom/issues/16007 if (pane != null) { pane.activateItem(this); - const dock = dockForLocation(pane.getContainer().getLocation()); + const dock = (0, (_dockForLocation || _load_dockForLocation()).default)(pane.getContainer().getLocation()); if (dock != null) { dock.show(); } @@ -153,10 +179,7 @@ export class DiagnosticsViewModel { // Only hide the diagnostics if it's the only item in its pane. if (pane != null) { const items = pane.getItems(); - if ( - items.length === 1 && - items[0] instanceof DiagnosticsViewModel - ) { + if (items.length === 1 && items[0] instanceof DiagnosticsViewModel) { atom.workspace.hide(this); } } @@ -166,40 +189,40 @@ export class DiagnosticsViewModel { }); } - destroy(): void { + destroy() { this._disposables.dispose(); } - getTitle(): string { + getTitle() { return 'Diagnostics'; } - getIconName(): IconName { + getIconName() { return 'law'; } - getURI(): string { + getURI() { return WORKSPACE_VIEW_URI; } - getDefaultLocation(): string { + getDefaultLocation() { return 'bottom'; } - serialize(): SerializedDiagnosticsViewModel { - const {hiddenGroups} = this._model.state; + serialize() { + const { hiddenGroups } = this._model.state; return { deserializer: 'atom-ide-ui.DiagnosticsViewModel', state: { - hiddenGroups: [...hiddenGroups], - }, + hiddenGroups: [...hiddenGroups] + } }; } - getElement(): HTMLElement { + getElement() { if (this._element == null) { - const Component = bindObservableAsProps(this._props, DiagnosticsView); - const element = renderReactRoot(); + const Component = (0, (_bindObservableAsProps || _load_bindObservableAsProps()).bindObservableAsProps)(this._props, (_DiagnosticsView || _load_DiagnosticsView()).default); + const element = (0, (_renderReactRoot || _load_renderReactRoot()).renderReactRoot)(_react.default.createElement(Component, null)); element.classList.add('diagnostics-ui'); this._element = element; } @@ -209,37 +232,11 @@ export class DiagnosticsViewModel { /** * Toggle the filter. */ - _handleTypeFilterChange = (type: DiagnosticGroup): void => { - const {hiddenGroups} = this._model.state; - const hidden = hiddenGroups.has(type); - const nextHiddenTypes = new Set(hiddenGroups); - if (hidden) { - nextHiddenTypes.delete(type); - } else { - nextHiddenTypes.add(type); - } - this._model.setState({hiddenGroups: nextHiddenTypes}); - analytics.track('diagnostics-panel-change-filter'); - }; - _handleTextFilterChange = (value: RegExpFilterChange): void => { - const {text, isRegExp} = value; - // TODO: Fuzzy if !isRegExp? - const {invalid, pattern} = getFilterPattern(text, isRegExp); - this._model.setState({ - textFilter: {text, isRegExp, invalid, pattern}, - }); - analytics.track('diagnostics-panel-change-filter'); - }; - _filterDiagnostics( - diagnostics: Array, - pattern: ?RegExp, - hiddenGroups: Set, - filterByPath: ?string, - ): Array { + _filterDiagnostics(diagnostics, pattern, hiddenGroups, filterByPath) { return diagnostics.filter(message => { - if (hiddenGroups.has(GroupUtils.getGroup(message))) { + if (hiddenGroups.has((_GroupUtils || _load_GroupUtils()).getGroup(message))) { return false; } if (filterByPath != null && message.filePath !== filterByPath) { @@ -248,45 +245,65 @@ export class DiagnosticsViewModel { if (pattern == null) { return true; } - return ( - (message.text != null && pattern.test(message.text)) || - (message.html != null && pattern.test(message.html)) || - pattern.test(message.providerName) || - pattern.test(message.filePath) - ); + return message.text != null && pattern.test(message.text) || message.html != null && pattern.test(message.html) || pattern.test(message.providerName) || pattern.test(message.filePath); }); } - _selectMessage = (message: DiagnosticMessage): void => { - this._model.setState({selectedMessage: message}); - }; } -function goToDiagnosticLocation( - message: DiagnosticMessage, - options: {|focusEditor: boolean|}, -): void { +exports.DiagnosticsViewModel = DiagnosticsViewModel; + +var _initialiseProps = function () { + this._handleTypeFilterChange = type => { + const { hiddenGroups } = this._model.state; + const hidden = hiddenGroups.has(type); + const nextHiddenTypes = new Set(hiddenGroups); + if (hidden) { + nextHiddenTypes.delete(type); + } else { + nextHiddenTypes.add(type); + } + this._model.setState({ hiddenGroups: nextHiddenTypes }); + (_analytics || _load_analytics()).default.track('diagnostics-panel-change-filter'); + }; + + this._handleTextFilterChange = value => { + const { text, isRegExp } = value; + // TODO: Fuzzy if !isRegExp? + const { invalid, pattern } = (0, (_RegExpFilter || _load_RegExpFilter()).getFilterPattern)(text, isRegExp); + this._model.setState({ + textFilter: { text, isRegExp, invalid, pattern } + }); + (_analytics || _load_analytics()).default.track('diagnostics-panel-change-filter'); + }; + + this._selectMessage = message => { + this._model.setState({ selectedMessage: message }); + }; +}; + +function goToDiagnosticLocation(message, options) { // TODO: what should we do for project-path diagnostics? - if (nuclideUri.endsWithSeparator(message.filePath)) { + if ((_nuclideUri || _load_nuclideUri()).default.endsWithSeparator(message.filePath)) { return; } - analytics.track('diagnostics-panel-goto-location'); + (_analytics || _load_analytics()).default.track('diagnostics-panel-goto-location'); const uri = message.filePath; // If initialLine is N, Atom will navigate to line N+1. // Flow sometimes reports a row of -1, so this ensures the line is at least one. const line = Math.max(message.range ? message.range.start.row : 0, 0); const column = 0; - goToLocation(uri, { + (0, (_goToLocation || _load_goToLocation()).goToLocation)(uri, { line, column, activatePane: options.focusEditor, - pending: true, + pending: true }); } -function patternsAreEqual(a: ?RegExp, b: ?RegExp) { +function patternsAreEqual(a, b) { if (a === b) { return true; } @@ -296,10 +313,5 @@ function patternsAreEqual(a: ?RegExp, b: ?RegExp) { if (a == null || b == null) { return false; } - return ( - a.source === b.source && - a.global === b.global && - a.multiline === b.multiline && - a.ignoreCase === b.ignoreCase - ); -} + return a.source === b.source && a.global === b.global && a.multiline === b.multiline && a.ignoreCase === b.ignoreCase; +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/GroupUtils.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/GroupUtils.js index 29757cc7..d1c29cc0 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/GroupUtils.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/GroupUtils.js @@ -1,3 +1,12 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getGroup = getGroup; +exports.getDisplayName = getDisplayName; +exports.getIcon = getIcon; +exports.getHighestPriorityGroup = getHighestPriorityGroup; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,32 +15,24 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {IconName} from 'nuclide-commons-ui/Icon'; -import type {DiagnosticMessage} from '../../atom-ide-diagnostics/lib/types'; -import type {DiagnosticGroup} from './types'; - -import invariant from 'assert'; +const PRIORITIZED_GROUPS = ['review', 'errors', 'warnings', 'info', 'action']; -const PRIORITIZED_GROUPS: Array = [ - 'review', - 'errors', - 'warnings', - 'info', - 'action', -]; - -export function getGroup(message: DiagnosticMessage): DiagnosticGroup { - const {kind} = message; +function getGroup(message) { + const { kind } = message; switch (kind) { case 'lint': case null: case undefined: - invariant(message.type !== 'Hint'); + if (!(message.type !== 'Hint')) { + throw new Error('Invariant violation: "message.type !== \'Hint\'"'); + } // We have a separate button for each severity. + + switch (message.type) { case 'Error': return 'errors'; @@ -40,7 +41,7 @@ export function getGroup(message: DiagnosticMessage): DiagnosticGroup { case 'Info': return 'info'; default: - (message.type: empty); + message.type; throw new Error(`Invalid message severity: ${message.type}`); } case 'review': @@ -48,12 +49,12 @@ export function getGroup(message: DiagnosticMessage): DiagnosticGroup { case 'action': return 'action'; default: - (kind: empty); + kind; throw new Error(`Invalid message kind: ${kind}`); } } -export function getDisplayName(group: DiagnosticGroup): string { +function getDisplayName(group) { switch (group) { case 'errors': return 'Errors'; @@ -66,12 +67,12 @@ export function getDisplayName(group: DiagnosticGroup): string { case 'action': return 'Actions'; default: - (group: empty); + group; throw new Error(`Invalid group: ${group}`); } } -export function getIcon(group: DiagnosticGroup): IconName { +function getIcon(group) { switch (group) { case 'errors': return 'nuclicon-error'; @@ -84,18 +85,16 @@ export function getIcon(group: DiagnosticGroup): IconName { case 'action': return 'light-bulb'; default: - (group: empty); + group; throw new Error(`Invalid filter type: ${group}`); } } -export function getHighestPriorityGroup( - groups: Set, -): DiagnosticGroup { +function getHighestPriorityGroup(groups) { for (const group of PRIORITIZED_GROUPS) { if (groups.has(group)) { return group; } } throw new Error(`Invalid group set: ${[...groups].toString()}`); -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/KeyboardShortcuts.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/KeyboardShortcuts.js index 60875b93..77a02f41 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/KeyboardShortcuts.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/KeyboardShortcuts.js @@ -1,91 +1,56 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type { - DiagnosticTrace, - DiagnosticMessage, - DiagnosticUpdater, -} from '../../atom-ide-diagnostics/lib/types'; - -import invariant from 'assert'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // TODO(peterhal): The current index should really live in the DiagnosticStore. -export default class KeyboardShortcuts { - _subscriptions: UniversalDisposable; - _diagnostics: Array; - _index: ?number; - _traceIndex: ?number; +class KeyboardShortcuts { - constructor(diagnosticUpdater: DiagnosticUpdater) { + constructor(diagnosticUpdater) { this._index = null; this._diagnostics = []; - this._subscriptions = new UniversalDisposable(); + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(); const first = () => this.setIndex(0); const last = () => this.setIndex(this._diagnostics.length - 1); - this._subscriptions.add( - observableFromSubscribeFunction( - diagnosticUpdater.observeMessages, - ).subscribe(diagnostics => { - this._index = null; - this._traceIndex = null; - this._diagnostics = diagnostics; - }), - atom.commands.add( - 'atom-workspace', - 'diagnostics:go-to-first-diagnostic', - first, - ), - atom.commands.add( - 'atom-workspace', - 'diagnostics:go-to-last-diagnostic', - last, - ), - atom.commands.add( - 'atom-workspace', - 'diagnostics:go-to-next-diagnostic', - () => { - this._index == null ? first() : this.setIndex(this._index + 1); - }, - ), - atom.commands.add( - 'atom-workspace', - 'diagnostics:go-to-previous-diagnostic', - () => { - this._index == null ? last() : this.setIndex(this._index - 1); - }, - ), - atom.commands.add( - 'atom-workspace', - 'diagnostics:go-to-next-diagnostic-trace', - () => { - this.nextTrace(); - }, - ), - atom.commands.add( - 'atom-workspace', - 'diagnostics:go-to-previous-diagnostic-trace', - () => { - this.previousTrace(); - }, - ), - ); + this._subscriptions.add((0, (_event || _load_event()).observableFromSubscribeFunction)(diagnosticUpdater.observeMessages).subscribe(diagnostics => { + this._index = null; + this._traceIndex = null; + this._diagnostics = diagnostics; + }), atom.commands.add('atom-workspace', 'diagnostics:go-to-first-diagnostic', first), atom.commands.add('atom-workspace', 'diagnostics:go-to-last-diagnostic', last), atom.commands.add('atom-workspace', 'diagnostics:go-to-next-diagnostic', () => { + this._index == null ? first() : this.setIndex(this._index + 1); + }), atom.commands.add('atom-workspace', 'diagnostics:go-to-previous-diagnostic', () => { + this._index == null ? last() : this.setIndex(this._index - 1); + }), atom.commands.add('atom-workspace', 'diagnostics:go-to-next-diagnostic-trace', () => { + this.nextTrace(); + }), atom.commands.add('atom-workspace', 'diagnostics:go-to-previous-diagnostic-trace', () => { + this.previousTrace(); + })); } - setIndex(index: number): void { + setIndex(index) { this._traceIndex = null; if (this._diagnostics.length === 0) { this._index = null; @@ -95,22 +60,28 @@ export default class KeyboardShortcuts { this.gotoCurrentIndex(); } - gotoCurrentIndex(): void { - invariant(this._index != null); - invariant(this._traceIndex == null); + gotoCurrentIndex() { + if (!(this._index != null)) { + throw new Error('Invariant violation: "this._index != null"'); + } + + if (!(this._traceIndex == null)) { + throw new Error('Invariant violation: "this._traceIndex == null"'); + } + const diagnostic = this._diagnostics[this._index]; const range = diagnostic.range; if (range == null) { - goToLocation(diagnostic.filePath); + (0, (_goToLocation || _load_goToLocation()).goToLocation)(diagnostic.filePath); } else { - goToLocation(diagnostic.filePath, { + (0, (_goToLocation || _load_goToLocation()).goToLocation)(diagnostic.filePath, { line: range.start.row, - column: range.start.column, + column: range.start.column }); } } - nextTrace(): void { + nextTrace() { const traces = this.currentTraces(); if (traces == null) { return; @@ -126,13 +97,12 @@ export default class KeyboardShortcuts { this.gotoCurrentIndex(); } - previousTrace(): void { + previousTrace() { const traces = this.currentTraces(); if (traces == null) { return; } - let candidateTrace = - this._traceIndex == null ? traces.length - 1 : this._traceIndex - 1; + let candidateTrace = this._traceIndex == null ? traces.length - 1 : this._traceIndex - 1; while (candidateTrace >= 0) { if (this.trySetCurrentTrace(traces, candidateTrace)) { return; @@ -143,7 +113,7 @@ export default class KeyboardShortcuts { this.gotoCurrentIndex(); } - currentTraces(): ?Array { + currentTraces() { if (this._index == null) { return null; } @@ -152,23 +122,31 @@ export default class KeyboardShortcuts { } // TODO: Should filter out traces whose location matches the main diagnostic's location? - trySetCurrentTrace( - traces: Array, - traceIndex: number, - ): boolean { + trySetCurrentTrace(traces, traceIndex) { const trace = traces[traceIndex]; if (trace.filePath != null && trace.range != null) { this._traceIndex = traceIndex; - goToLocation(trace.filePath, { + (0, (_goToLocation || _load_goToLocation()).goToLocation)(trace.filePath, { line: trace.range.start.row, - column: trace.range.start.column, + column: trace.range.start.column }); return true; } return false; } - dispose(): void { + dispose() { this._subscriptions.dispose(); } } +exports.default = KeyboardShortcuts; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/aim.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/aim.js index 567e663d..73609476 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/aim.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/aim.js @@ -1,83 +1,60 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import {Observable} from 'rxjs'; - -type Point = {x: number, y: number}; - -const VECTOR_DURATION = 100; - -const distance = (a: Point, b: Point): number => { +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.hoveringOrAiming = hoveringOrAiming; + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +const VECTOR_DURATION = 100; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const distance = (a, b) => { return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2)); }; -const eventToPoint = (e: MouseEvent): Point => ({ +const eventToPoint = e => ({ x: e.clientX, - y: e.clientY, + y: e.clientY }); // Combine mouseenter and mouseleave to create an observable of hovering state. -function areHovering(element: HTMLElement): Observable { - return Observable.merge( - Observable.fromEvent(element, 'mouseenter').mapTo(true), - Observable.fromEvent(element, 'mouseleave').mapTo(false), - ); +function areHovering(element) { + return _rxjsBundlesRxMinJs.Observable.merge(_rxjsBundlesRxMinJs.Observable.fromEvent(element, 'mouseenter').mapTo(true), _rxjsBundlesRxMinJs.Observable.fromEvent(element, 'mouseleave').mapTo(false)); } -function findCorners(node: HTMLElement): [Point, Point, Point, Point] { - const {left, width, top, height} = node.getBoundingClientRect(); - return [ - {x: left, y: top}, // Top left - {x: left + width, y: top}, // Top right - {x: left, y: top + height}, // Bottom left - {x: left + width, y: top + height}, // Bottom right - ]; +function findCorners(node) { + const { left, width, top, height } = node.getBoundingClientRect(); + return [{ x: left, y: top }, // Top left + { x: left + width, y: top }, // Top right + { x: left, y: top + height }, // Bottom left + { x: left + width, y: top + height }]; } -function areAiming(from: HTMLElement, to: HTMLElement): Observable { +function areAiming(from, to) { const [topLeft, topRight, bottomLeft, bottomRight] = findCorners(to); - const toBelowFrom = - to.getBoundingClientRect().top >= from.getBoundingClientRect().bottom; + const toBelowFrom = to.getBoundingClientRect().top >= from.getBoundingClientRect().bottom; // For now we assume that `to` is always to the right of `from` and that // `from` is always strictly above or below `to`. A more robust solution would // be to find the two corner of `to` that form the largest angle from the // center of `from` - const [cornerA, cornerB] = toBelowFrom - ? [topRight, bottomLeft] - : [topLeft, bottomRight]; + const [cornerA, cornerB] = toBelowFrom ? [topRight, bottomLeft] : [topLeft, bottomRight]; - return Observable.fromEvent(document, 'mousemove') - .map(eventToPoint) - .auditTime(VECTOR_DURATION) - .map(mouse => distance(mouse, cornerA) + distance(mouse, cornerB)) - .pairwise() - .map(([prevDist, currentDist]) => prevDist > currentDist) - .distinctUntilChanged(); + return _rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mousemove').map(eventToPoint).auditTime(VECTOR_DURATION).map(mouse => distance(mouse, cornerA) + distance(mouse, cornerB)).pairwise().map(([prevDist, currentDist]) => prevDist > currentDist).distinctUntilChanged(); } -export function hoveringOrAiming( - from: HTMLElement, - to: HTMLElement, -): Observable { - return Observable.concat( - areHovering(from) - .startWith(true) - .takeWhile(Boolean), - Observable.combineLatest( - areAiming(from, to).startWith(true), - areHovering(to).startWith(false), - (aiming, hovering) => aiming || hovering, - ), - ).distinctUntilChanged(); -} +function hoveringOrAiming(from, to) { + return _rxjsBundlesRxMinJs.Observable.concat(areHovering(from).startWith(true).takeWhile(Boolean), _rxjsBundlesRxMinJs.Observable.combineLatest(areAiming(from, to).startWith(true), areHovering(to).startWith(false), (aiming, hovering) => aiming || hovering)).distinctUntilChanged(); +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/getDiagnosticDatatip.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/getDiagnosticDatatip.js index edb1e6bc..158a6ff2 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/getDiagnosticDatatip.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/getDiagnosticDatatip.js @@ -1,65 +1,87 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Datatip} from '../../atom-ide-datatip/lib/types'; -import type { - DiagnosticUpdater, - DiagnosticMessage, -} from '../../atom-ide-diagnostics/lib/types'; - -import invariant from 'assert'; -import * as React from 'react'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; -import {bindObservableAsProps} from 'nuclide-commons-ui/bindObservableAsProps'; -import {DiagnosticsPopup} from './ui/DiagnosticsPopup'; - -const gotoLine = (file: string, line: number) => goToLocation(file, {line}); - -function makeDatatipComponent( - messages: Array, - diagnosticUpdater: DiagnosticUpdater, -): React.ComponentType<*> { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _react = _interopRequireWildcard(require('react')); + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _bindObservableAsProps; + +function _load_bindObservableAsProps() { + return _bindObservableAsProps = require('nuclide-commons-ui/bindObservableAsProps'); +} + +var _DiagnosticsPopup; + +function _load_DiagnosticsPopup() { + return _DiagnosticsPopup = require('./ui/DiagnosticsPopup'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const gotoLine = (file, line) => (0, (_goToLocation || _load_goToLocation()).goToLocation)(file, { line }); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function makeDatatipComponent(messages, diagnosticUpdater) { const fixer = message => diagnosticUpdater.applyFix(message); - return bindObservableAsProps( - observableFromSubscribeFunction(cb => - diagnosticUpdater.observeCodeActionsForMessage(cb), - ).map(codeActionsForMessage => ({ - messages, - fixer, - goToLocation: gotoLine, - codeActionsForMessage, - })), - DiagnosticsPopup, - ); + return (0, (_bindObservableAsProps || _load_bindObservableAsProps()).bindObservableAsProps)((0, (_event || _load_event()).observableFromSubscribeFunction)(cb => diagnosticUpdater.observeCodeActionsForMessage(cb)).map(codeActionsForMessage => ({ + messages, + fixer, + goToLocation: gotoLine, + codeActionsForMessage + })), (_DiagnosticsPopup || _load_DiagnosticsPopup()).DiagnosticsPopup); } -export default (async function getDiagnosticDatatip( - editor: TextEditor, - position: atom$Point, - messagesAtPosition: Array, - diagnosticUpdater: DiagnosticUpdater, -): Promise { - let range = null; - for (const message of messagesAtPosition) { - if (message.range != null) { - range = range == null ? message.range : message.range.union(range); +exports.default = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (editor, position, messagesAtPosition, diagnosticUpdater) { + let range = null; + for (const message of messagesAtPosition) { + if (message.range != null) { + range = range == null ? message.range : message.range.union(range); + } } + diagnosticUpdater.fetchCodeActions(editor, messagesAtPosition); + + if (!(range != null)) { + throw new Error('Invariant violation: "range != null"'); + } + + return { + component: makeDatatipComponent(messagesAtPosition, diagnosticUpdater), + pinnable: false, + range + }; + }); + + function getDiagnosticDatatip(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); } - diagnosticUpdater.fetchCodeActions(editor, messagesAtPosition); - invariant(range != null); - return { - component: makeDatatipComponent(messagesAtPosition, diagnosticUpdater), - pinnable: false, - range, - }; -}); + + return getDiagnosticDatatip; +})(); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/gutter.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/gutter.js index 81db16f1..3ff399fb 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/gutter.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/gutter.js @@ -1,3 +1,82 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.applyUpdateToEditor = applyUpdateToEditor; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _atom = require('atom'); + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _range; + +function _load_range() { + return _range = require('nuclide-commons-atom/range'); +} + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _bindObservableAsProps; + +function _load_bindObservableAsProps() { + return _bindObservableAsProps = require('nuclide-commons-ui/bindObservableAsProps'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _DiagnosticsPopup; + +function _load_DiagnosticsPopup() { + return _DiagnosticsPopup = require('./ui/DiagnosticsPopup'); +} + +var _GroupUtils; + +function _load_GroupUtils() { + return _GroupUtils = _interopRequireWildcard(require('./GroupUtils')); +} + +var _aim; + +function _load_aim() { + return _aim = require('./aim'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,33 +85,10 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type { - DiagnosticUpdater, - DiagnosticMessage, - DiagnosticMessages, -} from '../../atom-ide-diagnostics/lib/types'; -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; - -import classnames from 'classnames'; -import {Range} from 'atom'; -import invariant from 'assert'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import {completingSwitchMap} from 'nuclide-commons/observable'; -import {goToLocation as atomGoToLocation} from 'nuclide-commons-atom/go-to-location'; -import {wordAtPosition} from 'nuclide-commons-atom/range'; -import analytics from 'nuclide-commons-atom/analytics'; -import {bindObservableAsProps} from 'nuclide-commons-ui/bindObservableAsProps'; -import {Observable} from 'rxjs'; -import {DiagnosticsPopup} from './ui/DiagnosticsPopup'; -import * as GroupUtils from './GroupUtils'; -import {hoveringOrAiming} from './aim'; - const GUTTER_ID = 'diagnostics-gutter'; // TODO(mbolin): Make it so that when mousing over an element with this CSS class (or specifically, @@ -51,7 +107,7 @@ const HIGHLIGHT_CSS_LEVELS = { Error: 'diagnostics-gutter-ui-highlight-error', Warning: 'diagnostics-gutter-ui-highlight-warning', Info: 'diagnostics-gutter-ui-highlight-info', - Hint: '', + Hint: '' }; const GUTTER_CSS_GROUPS = { @@ -60,17 +116,13 @@ const GUTTER_CSS_GROUPS = { warnings: 'diagnostics-gutter-ui-gutter-warning', info: 'diagnostics-gutter-ui-gutter-info', action: 'diagnostics-gutter-ui-gutter-action', - hidden: '', + hidden: '' }; -const editorToMarkers: WeakMap> = new WeakMap(); -const itemToEditor: WeakMap = new WeakMap(); +const editorToMarkers = new WeakMap(); +const itemToEditor = new WeakMap(); -export function applyUpdateToEditor( - editor: TextEditor, - update: DiagnosticMessages, - diagnosticUpdater: DiagnosticUpdater, -): void { +function applyUpdateToEditor(editor, update, diagnosticUpdater) { let gutter = editor.gutterWithName(GUTTER_ID); if (!gutter) { // TODO(jessicalin): Determine an appropriate priority so that the gutter: @@ -84,7 +136,7 @@ export function applyUpdateToEditor( name: GUTTER_ID, visible: false, // Priority is -200 by default and 0 is the line number - priority: -1000, + priority: -1000 }); } @@ -102,8 +154,8 @@ export function applyUpdateToEditor( markers = new Set(); } - const rowToMessage: Map> = new Map(); - function addMessageForRow(message: DiagnosticMessage, row: number) { + const rowToMessage = new Map(); + function addMessageForRow(message, row) { let messages = rowToMessage.get(row); if (!messages) { messages = []; @@ -113,16 +165,10 @@ export function applyUpdateToEditor( } for (const message of update.messages) { - const wordRange = - message.range != null && message.range.isEmpty() - ? wordAtPosition(editor, message.range.start) - : null; + const wordRange = message.range != null && message.range.isEmpty() ? (0, (_range || _load_range()).wordAtPosition)(editor, message.range.start) : null; const range = wordRange != null ? wordRange.range : message.range; - const highlightCssClass = classnames( - HIGHLIGHT_CSS, - HIGHLIGHT_CSS_LEVELS[message.type], - ); + const highlightCssClass = (0, (_classnames || _load_classnames()).default)(HIGHLIGHT_CSS, HIGHLIGHT_CSS_LEVELS[message.type]); let highlightMarker; if (range) { @@ -141,9 +187,7 @@ export function applyUpdateToEditor( for (let line = range.start.row; line <= range.end.row; line++) { let start; let end; - const lineText = editor.getTextInBufferRange( - new Range([line, 0], [line + 1, 0]), - ); + const lineText = editor.getTextInBufferRange(new _atom.Range([line, 0], [line + 1, 0])); if (line === range.start.row) { start = range.start.column; @@ -160,12 +204,10 @@ export function applyUpdateToEditor( end = lineText.length; } - highlightMarker = editor.markBufferRange( - new Range([line, start], [line, end]), - ); + highlightMarker = editor.markBufferRange(new _atom.Range([line, start], [line, end])); editor.decorateMarker(highlightMarker, { type: 'highlight', - class: highlightCssClass, + class: highlightCssClass }); markers.add(highlightMarker); } @@ -177,14 +219,10 @@ export function applyUpdateToEditor( // Find all of the gutter markers for the same row and combine them into one marker/popup. for (const [row, messages] of rowToMessage.entries()) { // This marker adds some UI to the gutter. - const {item, dispose} = createGutterItem( - messages, - diagnosticUpdater, - gutter, - ); + const { item, dispose } = createGutterItem(messages, diagnosticUpdater, gutter); itemToEditor.set(item, editor); const gutterMarker = editor.markBufferPosition([row, 0]); - gutter.decorateMarker(gutterMarker, {item}); + gutter.decorateMarker(gutterMarker, { item }); gutterMarker.onDidDestroy(dispose); markers.add(gutterMarker); } @@ -195,19 +233,15 @@ export function applyUpdateToEditor( // TextEditor. if (update.messages.length > 0) { gutter.show(); - analytics.track('diagnostics-show-editor-diagnostics'); + (_analytics || _load_analytics()).default.track('diagnostics-show-editor-diagnostics'); } } -function createGutterItem( - messages: Array, - diagnosticUpdater: DiagnosticUpdater, - gutter: atom$Gutter, -): {item: HTMLElement, dispose: () => void} { +function createGutterItem(messages, diagnosticUpdater, gutter) { // Determine which group to display. const messageGroups = new Set(); - messages.forEach(msg => messageGroups.add(GroupUtils.getGroup(msg))); - const group = GroupUtils.getHighestPriorityGroup(messageGroups); + messages.forEach(msg => messageGroups.add((_GroupUtils || _load_GroupUtils()).getGroup(msg))); + const group = (_GroupUtils || _load_GroupUtils()).getHighestPriorityGroup(messageGroups); const item = document.createElement('span'); const groupClassName = GUTTER_CSS_GROUPS[group]; @@ -215,74 +249,61 @@ function createGutterItem( // Add the icon const icon = document.createElement('span'); - icon.className = `icon icon-${GroupUtils.getIcon(group)}`; + icon.className = `icon icon-${(_GroupUtils || _load_GroupUtils()).getIcon(group)}`; item.appendChild(icon); - const spawnPopup = (): Observable => { - return Observable.create(observer => { - const goToLocation = (path: string, line: number) => { + const spawnPopup = () => { + return _rxjsBundlesRxMinJs.Observable.create(observer => { + const goToLocation = (path, line) => { // Before we jump to the location, we want to close the popup. const column = 0; - atomGoToLocation(path, {line, column}); + (0, (_goToLocation || _load_goToLocation()).goToLocation)(path, { line, column }); observer.complete(); }; - const popupElement = showPopupFor( - messages, - item, - goToLocation, - diagnosticUpdater, - gutter, - ); + const popupElement = showPopupFor(messages, item, goToLocation, diagnosticUpdater, gutter); observer.next(popupElement); return () => { - ReactDOM.unmountComponentAtNode(popupElement); - invariant(popupElement.parentNode != null); + _reactDom.default.unmountComponentAtNode(popupElement); + + if (!(popupElement.parentNode != null)) { + throw new Error('Invariant violation: "popupElement.parentNode != null"'); + } + popupElement.parentNode.removeChild(popupElement); }; }); }; - const hoverSubscription = Observable.fromEvent(item, 'mouseenter') - .exhaustMap((event: MouseEvent) => { - return spawnPopup() - .let( - completingSwitchMap((popupElement: HTMLElement) => { - const innerPopupElement = popupElement.firstChild; - invariant(innerPopupElement instanceof HTMLElement); - - // Events which should cause the popup to close. - return Observable.merge( - hoveringOrAiming(item, innerPopupElement), - // This makes sure that the popup disappears when you ctrl+tab to switch tabs. - observableFromSubscribeFunction(cb => - atom.workspace.onDidChangeActivePaneItem(cb), - ).mapTo(false), - ); - }), - ) - .takeWhile(Boolean); - }) - .subscribe(); + const hoverSubscription = _rxjsBundlesRxMinJs.Observable.fromEvent(item, 'mouseenter').exhaustMap(event => { + return spawnPopup().let((0, (_observable || _load_observable()).completingSwitchMap)(popupElement => { + const innerPopupElement = popupElement.firstChild; + + if (!(innerPopupElement instanceof HTMLElement)) { + throw new Error('Invariant violation: "innerPopupElement instanceof HTMLElement"'); + } + + // Events which should cause the popup to close. + + + return _rxjsBundlesRxMinJs.Observable.merge((0, (_aim || _load_aim()).hoveringOrAiming)(item, innerPopupElement), + // This makes sure that the popup disappears when you ctrl+tab to switch tabs. + (0, (_event || _load_event()).observableFromSubscribeFunction)(cb => atom.workspace.onDidChangeActivePaneItem(cb)).mapTo(false)); + })).takeWhile(Boolean); + }).subscribe(); const dispose = () => hoverSubscription.unsubscribe(); - return {item, dispose}; + return { item, dispose }; } /** * Shows a popup for the diagnostic just below the specified item. */ -function showPopupFor( - messages: Array, - item: HTMLElement, - goToLocation: (filePath: NuclideUri, line: number) => mixed, - diagnosticUpdater: DiagnosticUpdater, - gutter: atom$Gutter, -): HTMLElement { +function showPopupFor(messages, item, goToLocation, diagnosticUpdater, gutter) { // The popup will be an absolutely positioned child element of so that it appears // on top of everything. - const workspaceElement = atom.views.getView((atom.workspace: Object)); + const workspaceElement = atom.views.getView(atom.workspace); const hostElement = document.createElement('div'); hostElement.classList.add('diagnostics-gutter-popup'); // $FlowFixMe check parentNode for null @@ -291,50 +312,53 @@ function showPopupFor( const { bottom: itemBottom, top: itemTop, - height: itemHeight, + height: itemHeight } = item.getBoundingClientRect(); // $FlowFixMe atom$Gutter.getElement is not a documented API, but it beats using a query selector. const gutterContainer = gutter.getElement(); - const {right: gutterRight} = gutterContainer.getBoundingClientRect(); + const { right: gutterRight } = gutterContainer.getBoundingClientRect(); const trackedFixer = (...args) => { diagnosticUpdater.applyFix(...args); - analytics.track('diagnostics-gutter-autofix'); + (_analytics || _load_analytics()).default.track('diagnostics-gutter-autofix'); }; - const trackedGoToLocation = (filePath: NuclideUri, line: number) => { + const trackedGoToLocation = (filePath, line) => { goToLocation(filePath, line); - analytics.track('diagnostics-gutter-goto-location'); + (_analytics || _load_analytics()).default.track('diagnostics-gutter-goto-location'); }; const editor = itemToEditor.get(item); - invariant(editor != null); + + if (!(editor != null)) { + throw new Error('Invariant violation: "editor != null"'); + } + diagnosticUpdater.fetchCodeActions(editor, messages); const popupTop = itemBottom; - const BoundPopup = bindObservableAsProps( - observableFromSubscribeFunction(cb => - diagnosticUpdater.observeCodeActionsForMessage(cb), - ).map(codeActionsForMessage => ({ - style: {left: gutterRight, top: popupTop, position: 'absolute'}, - messages, - fixer: trackedFixer, - goToLocation: trackedGoToLocation, - codeActionsForMessage, - })), - DiagnosticsPopup, - ); - ReactDOM.render(, hostElement); + const BoundPopup = (0, (_bindObservableAsProps || _load_bindObservableAsProps()).bindObservableAsProps)((0, (_event || _load_event()).observableFromSubscribeFunction)(cb => diagnosticUpdater.observeCodeActionsForMessage(cb)).map(codeActionsForMessage => ({ + style: { left: gutterRight, top: popupTop, position: 'absolute' }, + messages, + fixer: trackedFixer, + goToLocation: trackedGoToLocation, + codeActionsForMessage + })), (_DiagnosticsPopup || _load_DiagnosticsPopup()).DiagnosticsPopup); + _reactDom.default.render(_react.createElement(BoundPopup, null), hostElement); // Check to see whether the popup is within the bounds of the TextEditor. If not, display it above // the glyph rather than below it. const editorElement = atom.views.getView(editor); const { top: editorTop, - height: editorHeight, + height: editorHeight } = editorElement.getBoundingClientRect(); const popupElement = hostElement.firstElementChild; - invariant(popupElement instanceof HTMLElement); + + if (!(popupElement instanceof HTMLElement)) { + throw new Error('Invariant violation: "popupElement instanceof HTMLElement"'); + } + const popupHeight = popupElement.clientHeight; if (itemTop + itemHeight + popupHeight > editorTop + editorHeight) { popupElement.style.top = `${popupTop - popupHeight - itemHeight}px`; @@ -344,11 +368,11 @@ function showPopupFor( return hostElement; } finally { messages.forEach(message => { - analytics.track('diagnostics-gutter-show-popup', { + (_analytics || _load_analytics()).default.track('diagnostics-gutter-show-popup', { 'diagnostics-provider': message.providerName, // flowlint-next-line sketchy-null-string:off - 'diagnostics-message': message.text || message.html || '', + 'diagnostics-message': message.text || message.html || '' }); }); } -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/main.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/main.js index abe3fc0c..e8a16672 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/main.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/main.js @@ -1,162 +1,220 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type { - DatatipProvider, - DatatipService, -} from '../../atom-ide-datatip/lib/types'; - -import type { - DiagnosticMessage, - DiagnosticMessages, - DiagnosticUpdater, -} from '../../atom-ide-diagnostics/lib/types'; -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; -import type {GlobalViewState} from './types'; - -import invariant from 'assert'; - -import analytics from 'nuclide-commons-atom/analytics'; - -import idx from 'idx'; -import {areSetsEqual} from 'nuclide-commons/collection'; -import nuclideUri from 'nuclide-commons/nuclideUri'; -import {fastDebounce} from 'nuclide-commons/observable'; -import KeyboardShortcuts from './KeyboardShortcuts'; -import Model from 'nuclide-commons/Model'; -import createPackage from 'nuclide-commons-atom/createPackage'; -import {observeTextEditors} from 'nuclide-commons-atom/text-editor'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import {DiagnosticsViewModel, WORKSPACE_VIEW_URI} from './DiagnosticsViewModel'; -import StatusBarTile from './ui/StatusBarTile'; -import {applyUpdateToEditor} from './gutter'; -import getDiagnosticDatatip from './getDiagnosticDatatip'; -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; -import featureConfig from 'nuclide-commons-atom/feature-config'; -import {destroyItemWhere} from 'nuclide-commons-atom/destroyItemWhere'; -import {isValidTextEditor} from 'nuclide-commons-atom/text-editor'; -import {Observable} from 'rxjs'; -import showActionsMenu from './showActionsMenu'; -import showAtomLinterWarning from './showAtomLinterWarning'; - -const MAX_OPEN_ALL_FILES = 20; -const SHOW_TRACES_SETTING = 'atom-ide-diagnostics-ui.showDiagnosticTraces'; +'use strict'; + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _idx; + +function _load_idx() { + return _idx = _interopRequireDefault(require('idx')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} + +var _KeyboardShortcuts; + +function _load_KeyboardShortcuts() { + return _KeyboardShortcuts = _interopRequireDefault(require('./KeyboardShortcuts')); +} + +var _Model; + +function _load_Model() { + return _Model = _interopRequireDefault(require('nuclide-commons/Model')); +} + +var _createPackage; + +function _load_createPackage() { + return _createPackage = _interopRequireDefault(require('nuclide-commons-atom/createPackage')); +} + +var _textEditor; + +function _load_textEditor() { + return _textEditor = require('nuclide-commons-atom/text-editor'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _event; -type ActivationState = {| - filterByActiveTextEditor: boolean, -|}; +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _DiagnosticsViewModel; + +function _load_DiagnosticsViewModel() { + return _DiagnosticsViewModel = require('./DiagnosticsViewModel'); +} + +var _StatusBarTile; + +function _load_StatusBarTile() { + return _StatusBarTile = _interopRequireDefault(require('./ui/StatusBarTile')); +} + +var _gutter; + +function _load_gutter() { + return _gutter = require('./gutter'); +} -type DiagnosticsState = {| - ...ActivationState, - diagnosticUpdater: ?DiagnosticUpdater, -|}; +var _getDiagnosticDatatip; + +function _load_getDiagnosticDatatip() { + return _getDiagnosticDatatip = _interopRequireDefault(require('./getDiagnosticDatatip')); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _destroyItemWhere; + +function _load_destroyItemWhere() { + return _destroyItemWhere = require('nuclide-commons-atom/destroyItemWhere'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _showActionsMenu; + +function _load_showActionsMenu() { + return _showActionsMenu = _interopRequireDefault(require('./showActionsMenu')); +} + +var _showAtomLinterWarning; + +function _load_showAtomLinterWarning() { + return _showAtomLinterWarning = _interopRequireDefault(require('./showAtomLinterWarning')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const MAX_OPEN_ALL_FILES = 20; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const SHOW_TRACES_SETTING = 'atom-ide-diagnostics-ui.showDiagnosticTraces'; class Activation { - _subscriptions: UniversalDisposable; - _model: Model; - _statusBarTile: ?StatusBarTile; - _fileDiagnostics: WeakMap>; - _globalViewStates: ?Observable; - - constructor(state: ?Object): void { - this._subscriptions = new UniversalDisposable( - this.registerOpenerAndCommand(), - this._registerActionsMenu(), - showAtomLinterWarning(), - ); - this._model = new Model({ - filterByActiveTextEditor: - idx(state, _ => _.filterByActiveTextEditor) === true, - diagnosticUpdater: null, + + constructor(state) { + var _ref; + + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(this.registerOpenerAndCommand(), this._registerActionsMenu(), (0, (_showAtomLinterWarning || _load_showAtomLinterWarning()).default)()); + this._model = new (_Model || _load_Model()).default({ + filterByActiveTextEditor: ((_ref = state) != null ? _ref.filterByActiveTextEditor : _ref) === true, + diagnosticUpdater: null }); this._fileDiagnostics = new WeakMap(); } - consumeDatatipService(service: DatatipService): IDisposable { - const datatipProvider: DatatipProvider = { + consumeDatatipService(service) { + const datatipProvider = { // show this datatip for every type of file providerName: 'diagnostics-datatip', // Diagnostic datatips should have higher priority than most other datatips. priority: 10, datatip: (editor, position) => { - const messagesAtPosition = this._getMessagesAtPosition( - editor, - position, - ); - const {diagnosticUpdater} = this._model.state; + const messagesAtPosition = this._getMessagesAtPosition(editor, position); + const { diagnosticUpdater } = this._model.state; if (messagesAtPosition.length === 0 || diagnosticUpdater == null) { return Promise.resolve(null); } - return getDiagnosticDatatip( - editor, - position, - messagesAtPosition, - diagnosticUpdater, - ); - }, + return (0, (_getDiagnosticDatatip || _load_getDiagnosticDatatip()).default)(editor, position, messagesAtPosition, diagnosticUpdater); + } }; const disposable = service.addProvider(datatipProvider); this._subscriptions.add(disposable); return disposable; } - consumeDiagnosticUpdates(diagnosticUpdater: DiagnosticUpdater): IDisposable { + consumeDiagnosticUpdates(diagnosticUpdater) { this._getStatusBarTile().consumeDiagnosticUpdates(diagnosticUpdater); this._subscriptions.add(gutterConsumeDiagnosticUpdates(diagnosticUpdater)); // Currently, the DiagnosticsView is designed to work with only one DiagnosticUpdater. if (this._model.state.diagnosticUpdater != null) { - return new UniversalDisposable(); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(); } - this._model.setState({diagnosticUpdater}); + this._model.setState({ diagnosticUpdater }); const atomCommandsDisposable = addAtomCommands(diagnosticUpdater); this._subscriptions.add(atomCommandsDisposable); this._subscriptions.add( - // Track diagnostics for all active editors. - observeTextEditors((editor: TextEditor) => { - this._fileDiagnostics.set(editor, []); - // TODO: this is actually inefficient - this filters all file events - // by their path, so this is actually O(N^2) in the number of editors. - // We should merge the store and UI packages to get direct access. - const subscription = getEditorDiagnosticUpdates( - editor, - diagnosticUpdater, - ) - .finally(() => { - this._subscriptions.remove(subscription); - this._fileDiagnostics.delete(editor); - }) - .subscribe(update => { - this._fileDiagnostics.set(editor, update.messages); - }); - this._subscriptions.add(subscription); - }), - ); - return new UniversalDisposable(atomCommandsDisposable, () => { - invariant(this._model.state.diagnosticUpdater === diagnosticUpdater); - this._model.setState({diagnosticUpdater: null}); + // Track diagnostics for all active editors. + (0, (_textEditor || _load_textEditor()).observeTextEditors)(editor => { + this._fileDiagnostics.set(editor, []); + // TODO: this is actually inefficient - this filters all file events + // by their path, so this is actually O(N^2) in the number of editors. + // We should merge the store and UI packages to get direct access. + const subscription = getEditorDiagnosticUpdates(editor, diagnosticUpdater).finally(() => { + this._subscriptions.remove(subscription); + this._fileDiagnostics.delete(editor); + }).subscribe(update => { + this._fileDiagnostics.set(editor, update.messages); + }); + this._subscriptions.add(subscription); + })); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(atomCommandsDisposable, () => { + if (!(this._model.state.diagnosticUpdater === diagnosticUpdater)) { + throw new Error('Invariant violation: "this._model.state.diagnosticUpdater === diagnosticUpdater"'); + } + + this._model.setState({ diagnosticUpdater: null }); }); } - consumeStatusBar(statusBar: atom$StatusBar): void { + consumeStatusBar(statusBar) { this._getStatusBarTile().consumeStatusBar(statusBar); } - deserializeDiagnosticsViewModel(): DiagnosticsViewModel { + deserializeDiagnosticsViewModel() { return this._createDiagnosticsViewModel(); } - dispose(): void { + dispose() { this._subscriptions.dispose(); if (this._statusBarTile) { this._statusBarTile.dispose(); @@ -164,15 +222,15 @@ class Activation { } } - serialize(): ActivationState { - const {filterByActiveTextEditor} = this._model.state; + serialize() { + const { filterByActiveTextEditor } = this._model.state; return { - filterByActiveTextEditor, + filterByActiveTextEditor }; } - _createDiagnosticsViewModel(): DiagnosticsViewModel { - return new DiagnosticsViewModel(this._getGlobalViewStates()); + _createDiagnosticsViewModel() { + return new (_DiagnosticsViewModel || _load_DiagnosticsViewModel()).DiagnosticsViewModel(this._getGlobalViewStates()); } /** @@ -181,203 +239,115 @@ class Activation { * only have one copy of the diagnostics panel so this is mostly a theoretical distinction, * however, each copy should have its own sorting, filtering, etc. */ - _getGlobalViewStates(): Observable { + _getGlobalViewStates() { if (this._globalViewStates == null) { const packageStates = this._model.toObservable(); - const updaters = packageStates - .map(state => state.diagnosticUpdater) - .distinctUntilChanged(); - - const diagnosticsStream = updaters - .switchMap( - updater => - updater == null - ? Observable.of([]) - : observableFromSubscribeFunction(updater.observeMessages), - ) - .map(diagnostics => diagnostics.filter(d => d.type !== 'Hint')) - .let(fastDebounce(100)) - .startWith([]); - - const showTracesStream: Observable< - boolean, - > = (featureConfig.observeAsStream(SHOW_TRACES_SETTING): any); + const updaters = packageStates.map(state => state.diagnosticUpdater).distinctUntilChanged(); + + const diagnosticsStream = updaters.switchMap(updater => updater == null ? _rxjsBundlesRxMinJs.Observable.of([]) : (0, (_event || _load_event()).observableFromSubscribeFunction)(updater.observeMessages)).map(diagnostics => diagnostics.filter(d => d.type !== 'Hint')).let((0, (_observable || _load_observable()).fastDebounce)(100)).startWith([]); + + const showTracesStream = (_featureConfig || _load_featureConfig()).default.observeAsStream(SHOW_TRACES_SETTING); const setShowTraces = showTraces => { - featureConfig.set(SHOW_TRACES_SETTING, showTraces); + (_featureConfig || _load_featureConfig()).default.set(SHOW_TRACES_SETTING, showTraces); }; - const showDirectoryColumnStream: Observable< - boolean, - > = (featureConfig.observeAsStream( - 'atom-ide-diagnostics-ui.showDirectoryColumn', - ): any); + const showDirectoryColumnStream = (_featureConfig || _load_featureConfig()).default.observeAsStream('atom-ide-diagnostics-ui.showDirectoryColumn'); - const autoVisibilityStream: Observable< - boolean, - > = (featureConfig.observeAsStream( - 'atom-ide-diagnostics-ui.autoVisibility', - ): any); + const autoVisibilityStream = (_featureConfig || _load_featureConfig()).default.observeAsStream('atom-ide-diagnostics-ui.autoVisibility'); const pathToActiveTextEditorStream = getActiveEditorPaths(); - const filterByActiveTextEditorStream = packageStates - .map(state => state.filterByActiveTextEditor) - .distinctUntilChanged(); + const filterByActiveTextEditorStream = packageStates.map(state => state.filterByActiveTextEditor).distinctUntilChanged(); const setFilterByActiveTextEditor = filterByActiveTextEditor => { - this._model.setState({filterByActiveTextEditor}); + this._model.setState({ filterByActiveTextEditor }); }; - const supportedMessageKindsStream = updaters - .switchMap( - updater => - updater == null - ? Observable.of(new Set(['lint'])) - : observableFromSubscribeFunction( - updater.observeSupportedMessageKinds.bind(updater), - ), - ) - .distinctUntilChanged(areSetsEqual); - - const uiConfigStream = updaters.switchMap( - updater => - updater == null - ? Observable.of([]) - : observableFromSubscribeFunction( - updater.observeUiConfig.bind(updater), - ), - ); - - this._globalViewStates = Observable.combineLatest( - diagnosticsStream, - filterByActiveTextEditorStream, - pathToActiveTextEditorStream, - showTracesStream, - showDirectoryColumnStream, - autoVisibilityStream, - supportedMessageKindsStream, - uiConfigStream, - // $FlowFixMe - ( - diagnostics, - filterByActiveTextEditor, - pathToActiveTextEditor, - showTraces, - showDirectoryColumn, - autoVisibility, - supportedMessageKinds, - uiConfig, - ) => ({ - diagnostics, - filterByActiveTextEditor, - pathToActiveTextEditor, - showTraces, - showDirectoryColumn, - autoVisibility, - onShowTracesChange: setShowTraces, - onFilterByActiveTextEditorChange: setFilterByActiveTextEditor, - supportedMessageKinds, - uiConfig, - }), - ); + const supportedMessageKindsStream = updaters.switchMap(updater => updater == null ? _rxjsBundlesRxMinJs.Observable.of(new Set(['lint'])) : (0, (_event || _load_event()).observableFromSubscribeFunction)(updater.observeSupportedMessageKinds.bind(updater))).distinctUntilChanged((_collection || _load_collection()).areSetsEqual); + + const uiConfigStream = updaters.switchMap(updater => updater == null ? _rxjsBundlesRxMinJs.Observable.of([]) : (0, (_event || _load_event()).observableFromSubscribeFunction)(updater.observeUiConfig.bind(updater))); + + this._globalViewStates = _rxjsBundlesRxMinJs.Observable.combineLatest(diagnosticsStream, filterByActiveTextEditorStream, pathToActiveTextEditorStream, showTracesStream, showDirectoryColumnStream, autoVisibilityStream, supportedMessageKindsStream, uiConfigStream, + // $FlowFixMe + (diagnostics, filterByActiveTextEditor, pathToActiveTextEditor, showTraces, showDirectoryColumn, autoVisibility, supportedMessageKinds, uiConfig) => ({ + diagnostics, + filterByActiveTextEditor, + pathToActiveTextEditor, + showTraces, + showDirectoryColumn, + autoVisibility, + onShowTracesChange: setShowTraces, + onFilterByActiveTextEditorChange: setFilterByActiveTextEditor, + supportedMessageKinds, + uiConfig + })); } return this._globalViewStates; } - registerOpenerAndCommand(): IDisposable { - const commandDisposable = atom.commands.add( - 'atom-workspace', - 'diagnostics:toggle-table', - () => { - atom.workspace.toggle(WORKSPACE_VIEW_URI); - }, - ); - return new UniversalDisposable( - atom.workspace.addOpener(uri => { - if (uri === WORKSPACE_VIEW_URI) { - return this._createDiagnosticsViewModel(); - } - }), - () => { - destroyItemWhere(item => item instanceof DiagnosticsViewModel); - }, - commandDisposable, - ); + registerOpenerAndCommand() { + const commandDisposable = atom.commands.add('atom-workspace', 'diagnostics:toggle-table', () => { + atom.workspace.toggle((_DiagnosticsViewModel || _load_DiagnosticsViewModel()).WORKSPACE_VIEW_URI); + }); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.workspace.addOpener(uri => { + if (uri === (_DiagnosticsViewModel || _load_DiagnosticsViewModel()).WORKSPACE_VIEW_URI) { + return this._createDiagnosticsViewModel(); + } + }), () => { + (0, (_destroyItemWhere || _load_destroyItemWhere()).destroyItemWhere)(item => item instanceof (_DiagnosticsViewModel || _load_DiagnosticsViewModel()).DiagnosticsViewModel); + }, commandDisposable); } - _registerActionsMenu(): IDisposable { - return atom.commands.add( - 'atom-text-editor', - 'diagnostics:show-actions-at-position', - () => { - const editor = atom.workspace.getActiveTextEditor(); - const {diagnosticUpdater} = this._model.state; - if (editor == null || diagnosticUpdater == null) { - return; - } - const position = editor.getCursorBufferPosition(); - const messagesAtPosition = this._getMessagesAtPosition( - editor, - position, - ); - if (messagesAtPosition.length === 0) { - return; - } - showActionsMenu( - editor, - position, - messagesAtPosition, - diagnosticUpdater, - ); - }, - ); + _registerActionsMenu() { + return atom.commands.add('atom-text-editor', 'diagnostics:show-actions-at-position', () => { + const editor = atom.workspace.getActiveTextEditor(); + const { diagnosticUpdater } = this._model.state; + if (editor == null || diagnosticUpdater == null) { + return; + } + const position = editor.getCursorBufferPosition(); + const messagesAtPosition = this._getMessagesAtPosition(editor, position); + if (messagesAtPosition.length === 0) { + return; + } + (0, (_showActionsMenu || _load_showActionsMenu()).default)(editor, position, messagesAtPosition, diagnosticUpdater); + }); } - _getStatusBarTile(): StatusBarTile { + _getStatusBarTile() { if (!this._statusBarTile) { - this._statusBarTile = new StatusBarTile(); + this._statusBarTile = new (_StatusBarTile || _load_StatusBarTile()).default(); } return this._statusBarTile; } - _getMessagesAtPosition( - editor: atom$TextEditor, - position: atom$Point, - ): Array { + _getMessagesAtPosition(editor, position) { const messagesForFile = this._fileDiagnostics.get(editor); if (messagesForFile == null) { return []; } - return messagesForFile.filter( - message => message.range != null && message.range.containsPoint(position), - ); + return messagesForFile.filter(message => message.range != null && message.range.containsPoint(position)); } } -function gutterConsumeDiagnosticUpdates( - diagnosticUpdater: DiagnosticUpdater, -): IDisposable { - const subscriptions = new UniversalDisposable(); - subscriptions.add( - observeTextEditors((editor: TextEditor) => { - const subscription = getEditorDiagnosticUpdates(editor, diagnosticUpdater) - .finally(() => { - subscriptions.remove(subscription); - }) - .subscribe(update => { - // Although the subscription should be cleaned up on editor destroy, - // the very act of destroying the editor can trigger diagnostic updates. - // Thus this callback can still be triggered after the editor is destroyed. - if (!editor.isDestroyed()) { - applyUpdateToEditor(editor, update, diagnosticUpdater); - } - }); - subscriptions.add(subscription); - }), - ); +function gutterConsumeDiagnosticUpdates(diagnosticUpdater) { + const subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(); + subscriptions.add((0, (_textEditor || _load_textEditor()).observeTextEditors)(editor => { + const subscription = getEditorDiagnosticUpdates(editor, diagnosticUpdater).finally(() => { + subscriptions.remove(subscription); + }).subscribe(update => { + // Although the subscription should be cleaned up on editor destroy, + // the very act of destroying the editor can trigger diagnostic updates. + // Thus this callback can still be triggered after the editor is destroyed. + if (!editor.isDestroyed()) { + (0, (_gutter || _load_gutter()).applyUpdateToEditor)(editor, update, diagnosticUpdater); + } + }); + subscriptions.add(subscription); + })); return subscriptions; } -function addAtomCommands(diagnosticUpdater: DiagnosticUpdater): IDisposable { +function addAtomCommands(diagnosticUpdater) { const fixAllInCurrentFile = () => { const editor = atom.workspace.getActiveTextEditor(); if (editor == null) { @@ -387,52 +357,34 @@ function addAtomCommands(diagnosticUpdater: DiagnosticUpdater): IDisposable { if (path == null) { return; } - analytics.track('diagnostics-autofix-all-in-file'); + (_analytics || _load_analytics()).default.track('diagnostics-autofix-all-in-file'); diagnosticUpdater.applyFixesForFile(path); }; const openAllFilesWithErrors = () => { - analytics.track('diagnostics-panel-open-all-files-with-errors'); - observableFromSubscribeFunction(diagnosticUpdater.observeMessages) - .first() - .subscribe((messages: Array) => { - const errorsToOpen = getTopMostErrorLocationsByFilePath(messages); - - if (errorsToOpen.size > MAX_OPEN_ALL_FILES) { - atom.notifications.addError( - `Diagnostics: Will not open more than ${MAX_OPEN_ALL_FILES} files`, - ); - return; - } + (_analytics || _load_analytics()).default.track('diagnostics-panel-open-all-files-with-errors'); + (0, (_event || _load_event()).observableFromSubscribeFunction)(diagnosticUpdater.observeMessages).first().subscribe(messages => { + const errorsToOpen = getTopMostErrorLocationsByFilePath(messages); - const column = 0; - errorsToOpen.forEach((line, uri) => goToLocation(uri, {line, column})); - }); + if (errorsToOpen.size > MAX_OPEN_ALL_FILES) { + atom.notifications.addError(`Diagnostics: Will not open more than ${MAX_OPEN_ALL_FILES} files`); + return; + } + + const column = 0; + errorsToOpen.forEach((line, uri) => (0, (_goToLocation || _load_goToLocation()).goToLocation)(uri, { line, column })); + }); }; - return new UniversalDisposable( - atom.commands.add( - 'atom-workspace', - 'diagnostics:fix-all-in-current-file', - fixAllInCurrentFile, - ), - atom.commands.add( - 'atom-workspace', - 'diagnostics:open-all-files-with-errors', - openAllFilesWithErrors, - ), - new KeyboardShortcuts(diagnosticUpdater), - ); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.commands.add('atom-workspace', 'diagnostics:fix-all-in-current-file', fixAllInCurrentFile), atom.commands.add('atom-workspace', 'diagnostics:open-all-files-with-errors', openAllFilesWithErrors), new (_KeyboardShortcuts || _load_KeyboardShortcuts()).default(diagnosticUpdater)); } -function getTopMostErrorLocationsByFilePath( - messages: Array, -): Map { - const errorLocations: Map = new Map(); +function getTopMostErrorLocationsByFilePath(messages) { + const errorLocations = new Map(); messages.forEach(message => { const filePath = message.filePath; - if (nuclideUri.endsWithSeparator(filePath)) { + if ((_nuclideUri || _load_nuclideUri()).default.endsWithSeparator(filePath)) { return; } @@ -451,58 +403,27 @@ function getTopMostErrorLocationsByFilePath( return errorLocations; } -function getActiveEditorPaths(): Observable { +function getActiveEditorPaths() { const center = atom.workspace.getCenter(); - return ( - observableFromSubscribeFunction(center.observeActivePaneItem.bind(center)) - .map(paneItem => (isValidTextEditor(paneItem) ? paneItem : null)) - // We want the stream to contain the last valid text editor. Normally that means just ignoring - // non-editors, except initially, when there hasn't been an active editor yet. - .filter((paneItem, index) => paneItem != null || index === 0) - .switchMap(textEditor_ => { - const textEditor: ?atom$TextEditor = (textEditor_: any); - if (textEditor == null) { - return Observable.of(null); - } - // An observable that emits the editor path and then, when the editor's destroyed, null. - return Observable.concat( - Observable.of(textEditor.getPath()), - observableFromSubscribeFunction( - textEditor.onDidDestroy.bind(textEditor), - ) - .take(1) - .mapTo(null), - ); - }) - .distinctUntilChanged() - ); + return (0, (_event || _load_event()).observableFromSubscribeFunction)(center.observeActivePaneItem.bind(center)).map(paneItem => (0, (_textEditor || _load_textEditor()).isValidTextEditor)(paneItem) ? paneItem : null) + // We want the stream to contain the last valid text editor. Normally that means just ignoring + // non-editors, except initially, when there hasn't been an active editor yet. + .filter((paneItem, index) => paneItem != null || index === 0).switchMap(textEditor_ => { + const textEditor = textEditor_; + if (textEditor == null) { + return _rxjsBundlesRxMinJs.Observable.of(null); + } + // An observable that emits the editor path and then, when the editor's destroyed, null. + return _rxjsBundlesRxMinJs.Observable.concat(_rxjsBundlesRxMinJs.Observable.of(textEditor.getPath()), (0, (_event || _load_event()).observableFromSubscribeFunction)(textEditor.onDidDestroy.bind(textEditor)).take(1).mapTo(null)); + }).distinctUntilChanged(); } -function getEditorDiagnosticUpdates( - editor: atom$TextEditor, - diagnosticUpdater: DiagnosticUpdater, -): Observable { - return observableFromSubscribeFunction(editor.onDidChangePath.bind(editor)) - .startWith(editor.getPath()) - .switchMap( - filePath => - filePath != null - ? observableFromSubscribeFunction(cb => - diagnosticUpdater.observeFileMessages(filePath, cb), - ) - : Observable.empty(), - ) - .map(diagnosticMessages => { - return { - ...diagnosticMessages, - messages: diagnosticMessages.messages.filter( - diagnostic => diagnostic.type !== 'Hint', - ), - }; - }) - .takeUntil( - observableFromSubscribeFunction(editor.onDidDestroy.bind(editor)), - ); +function getEditorDiagnosticUpdates(editor, diagnosticUpdater) { + return (0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidChangePath.bind(editor)).startWith(editor.getPath()).switchMap(filePath => filePath != null ? (0, (_event || _load_event()).observableFromSubscribeFunction)(cb => diagnosticUpdater.observeFileMessages(filePath, cb)) : _rxjsBundlesRxMinJs.Observable.empty()).map(diagnosticMessages => { + return Object.assign({}, diagnosticMessages, { + messages: diagnosticMessages.messages.filter(diagnostic => diagnostic.type !== 'Hint') + }); + }).takeUntil((0, (_event || _load_event()).observableFromSubscribeFunction)(editor.onDidDestroy.bind(editor))); } -createPackage(module.exports, Activation); +(0, (_createPackage || _load_createPackage()).default)(module.exports, Activation); \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showActionsMenu.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showActionsMenu.js index 71a29dee..13ca501b 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showActionsMenu.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showActionsMenu.js @@ -1,111 +1,103 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type { - DiagnosticUpdater, - DiagnosticMessage, -} from '../../atom-ide-diagnostics/lib/types'; - -import invariant from 'assert'; -import electron from 'electron'; -import {Observable} from 'rxjs'; -import {arrayCompact, arrayFlatten} from 'nuclide-commons/collection'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; - -const {remote} = electron; -invariant(remote != null); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = showActionsMenu; + +var _electron = _interopRequireDefault(require('electron')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const { remote } = _electron.default; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +if (!(remote != null)) { + throw new Error('Invariant violation: "remote != null"'); +} const CODE_ACTIONS_TIMEOUT = 2000; -export default function showActionsMenu( - editor: TextEditor, - position: atom$Point, - messagesAtPosition: Array, - diagnosticUpdater: DiagnosticUpdater, -): IDisposable { +function showActionsMenu(editor, position, messagesAtPosition, diagnosticUpdater) { diagnosticUpdater.fetchCodeActions(editor, messagesAtPosition); - return new UniversalDisposable( - observableFromSubscribeFunction(cb => - diagnosticUpdater.observeCodeActionsForMessage(cb), - ) - .filter(codeActionsForMessage => { - return messagesAtPosition.every(message => - codeActionsForMessage.has(message), - ); - }) - .take(1) - .race(Observable.of(new WeakMap()).delay(CODE_ACTIONS_TIMEOUT)) - .subscribe(codeActionsForMessage => { - const currentWindow = remote.getCurrentWindow(); - const menu = new remote.Menu(); - const fixes = arrayCompact( - messagesAtPosition.map(message => { - const {fix} = message; - if (fix == null) { - return null; - } - const fixTitle = fix.title == null ? 'Fix' : fix.title; - return { - title: `${fixTitle} (${message.providerName})`, - apply: () => diagnosticUpdater.applyFix(message), - }; - }), - ); - const actions = arrayFlatten( - messagesAtPosition.map(message => { - const codeActions = codeActionsForMessage.get(message); - if (codeActions == null) { - return []; - } - return Array.from(codeActions).map(([title, codeAction]) => ({ - title, - apply: () => codeAction.apply(), - })); - }), - ); - - [...fixes, ...actions].forEach(action => { - menu.append( - new remote.MenuItem({ - type: 'normal', - label: action.title, - click: () => { - action.apply(); - }, - }), - ); - }); - - const screenPosition = editor.screenPositionForBufferPosition(position); - const editorView = atom.views.getView(editor); - const pixelPosition = editorView.pixelPositionForScreenPosition( - screenPosition, - ); - // Pixel coordinates are relative to the editor's scroll view. - const scrollView = editorView.querySelector('.scroll-view'); - invariant(scrollView != null); - const boundingRect = scrollView.getBoundingClientRect(); - menu.popup( - currentWindow, - Math.round( - boundingRect.left + pixelPosition.left - editorView.getScrollLeft(), - ), - Math.round( - boundingRect.top + pixelPosition.top - editorView.getScrollTop(), - ), - 0, - ); - }), - ); -} + return new (_UniversalDisposable || _load_UniversalDisposable()).default((0, (_event || _load_event()).observableFromSubscribeFunction)(cb => diagnosticUpdater.observeCodeActionsForMessage(cb)).filter(codeActionsForMessage => { + return messagesAtPosition.every(message => codeActionsForMessage.has(message)); + }).take(1).race(_rxjsBundlesRxMinJs.Observable.of(new WeakMap()).delay(CODE_ACTIONS_TIMEOUT)).subscribe(codeActionsForMessage => { + const currentWindow = remote.getCurrentWindow(); + const menu = new remote.Menu(); + const fixes = (0, (_collection || _load_collection()).arrayCompact)(messagesAtPosition.map(message => { + const { fix } = message; + if (fix == null) { + return null; + } + const fixTitle = fix.title == null ? 'Fix' : fix.title; + return { + title: `${fixTitle} (${message.providerName})`, + apply: () => diagnosticUpdater.applyFix(message) + }; + })); + const actions = (0, (_collection || _load_collection()).arrayFlatten)(messagesAtPosition.map(message => { + const codeActions = codeActionsForMessage.get(message); + if (codeActions == null) { + return []; + } + return Array.from(codeActions).map(([title, codeAction]) => ({ + title, + apply: () => codeAction.apply() + })); + })); + + [...fixes, ...actions].forEach(action => { + menu.append(new remote.MenuItem({ + type: 'normal', + label: action.title, + click: () => { + action.apply(); + } + })); + }); + + const screenPosition = editor.screenPositionForBufferPosition(position); + const editorView = atom.views.getView(editor); + const pixelPosition = editorView.pixelPositionForScreenPosition(screenPosition); + // Pixel coordinates are relative to the editor's scroll view. + const scrollView = editorView.querySelector('.scroll-view'); + + if (!(scrollView != null)) { + throw new Error('Invariant violation: "scrollView != null"'); + } + + const boundingRect = scrollView.getBoundingClientRect(); + menu.popup(currentWindow, Math.round(boundingRect.left + pixelPosition.left - editorView.getScrollLeft()), Math.round(boundingRect.top + pixelPosition.top - editorView.getScrollTop()), 0); + })); +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showAtomLinterWarning.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showAtomLinterWarning.js index 38ec763f..071cf587 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showAtomLinterWarning.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/showAtomLinterWarning.js @@ -1,3 +1,32 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = showAtomLinterWarning; + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _event; + +function _load_event() { + return _event = require('nuclide-commons/event'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,85 +35,52 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import featureConfig from 'nuclide-commons-atom/feature-config'; -import {observableFromSubscribeFunction} from 'nuclide-commons/event'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {Observable} from 'rxjs'; - const LINTER_PACKAGE = 'linter'; -function observePackageIsEnabled(): Observable { - return Observable.merge( - Observable.of(atom.packages.isPackageActive(LINTER_PACKAGE)), - observableFromSubscribeFunction( - atom.packages.onDidActivatePackage.bind(atom.packages), - ) - .filter(pkg => pkg.name === LINTER_PACKAGE) - .mapTo(true), - observableFromSubscribeFunction( - atom.packages.onDidDeactivatePackage.bind(atom.packages), - ) - .filter(pkg => pkg.name === LINTER_PACKAGE) - .mapTo(false), - ); +function observePackageIsEnabled() { + return _rxjsBundlesRxMinJs.Observable.merge(_rxjsBundlesRxMinJs.Observable.of(atom.packages.isPackageActive(LINTER_PACKAGE)), (0, (_event || _load_event()).observableFromSubscribeFunction)(atom.packages.onDidActivatePackage.bind(atom.packages)).filter(pkg => pkg.name === LINTER_PACKAGE).mapTo(true), (0, (_event || _load_event()).observableFromSubscribeFunction)(atom.packages.onDidDeactivatePackage.bind(atom.packages)).filter(pkg => pkg.name === LINTER_PACKAGE).mapTo(false)); } -function disableLinter(): void { +function disableLinter() { atom.packages.disablePackage(LINTER_PACKAGE); } -function disableDiagnostics(): void { - featureConfig.set('use.atom-ide-diagnostics-ui', false); +function disableDiagnostics() { + (_featureConfig || _load_featureConfig()).default.set('use.atom-ide-diagnostics-ui', false); } -export default function showAtomLinterWarning(): IDisposable { - const packageName = featureConfig.getPackageName(); - return new UniversalDisposable( - observePackageIsEnabled() - .distinctUntilChanged() - .switchMap(enabled => { - if (!enabled) { - return Observable.empty(); +function showAtomLinterWarning() { + const packageName = (_featureConfig || _load_featureConfig()).default.getPackageName(); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(observePackageIsEnabled().distinctUntilChanged().switchMap(enabled => { + if (!enabled) { + return _rxjsBundlesRxMinJs.Observable.empty(); + } + const notification = atom.notifications.addInfo('Choose a linter UI', { + description: 'You have both `linter` and `atom-ide-diagnostics` enabled, which will both ' + 'display lint results for Linter-based packages.\n\n' + 'To avoid duplicate results, please disable one of the packages.' + (packageName === 'nuclide' ? '\n\nNote that Flow and Hack errors are not compatible with `linter`.' : ''), + dismissable: true, + buttons: [{ + text: 'Disable Linter', + onDidClick() { + disableLinter(); } - const notification = atom.notifications.addInfo('Choose a linter UI', { - description: - 'You have both `linter` and `atom-ide-diagnostics` enabled, which will both ' + - 'display lint results for Linter-based packages.\n\n' + - 'To avoid duplicate results, please disable one of the packages.' + - (packageName === 'nuclide' - ? '\n\nNote that Flow and Hack errors are not compatible with `linter`.' - : ''), - dismissable: true, - buttons: [ - { - text: 'Disable Linter', - onDidClick() { - disableLinter(); - }, - }, - { - text: 'Disable Diagnostics', - onDidClick() { - disableDiagnostics(); - atom.notifications.addInfo('Re-enabling Diagnostics', { - description: - 'To re-enable diagnostics, please enable "Diagnostics" under the "Enabled Features" ' + - `section in \`${packageName}\` settings.`, - }); - }, - }, - ], - }); - return Observable.create(() => ({ - unsubscribe() { - notification.dismiss(); - }, - })); - }) - .subscribe(), - ); -} + }, { + text: 'Disable Diagnostics', + onDidClick() { + disableDiagnostics(); + atom.notifications.addInfo('Re-enabling Diagnostics', { + description: 'To re-enable diagnostics, please enable "Diagnostics" under the "Enabled Features" ' + `section in \`${packageName}\` settings.` + }); + } + }] + }); + return _rxjsBundlesRxMinJs.Observable.create(() => ({ + unsubscribe() { + notification.dismiss(); + } + })); + }).subscribe()); +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/sortDiagnostics.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/sortDiagnostics.js index c5ad3aaa..4e6d7e31 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/sortDiagnostics.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/sortDiagnostics.js @@ -1,3 +1,14 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = sortDiagnostics; + + +/* + * Sorts the diagnostics according to given column and sort direction + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,35 +17,19 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {Row} from 'nuclide-commons-ui/Table'; -import type { - DiagnosticMessageKind, - DiagnosticMessageType, -} from '../../atom-ide-diagnostics/lib/types'; -import type {DisplayDiagnostic} from './ui/DiagnosticsTable'; +function sortDiagnostics(diagnostics, sortedColumnName, sortDescending) { + const compare = SORT_FUNCTIONS[sortedColumnName]; -import invariant from 'assert'; + if (!(compare != null)) { + throw new Error('Invariant violation: "compare != null"'); + } + // Don't sort in place. -type DiagnosticsComparison = ( - a: Row, - b: Row, -) => number; -/* - * Sorts the diagnostics according to given column and sort direction - */ -export default function sortDiagnostics( - diagnostics: Array>, - sortedColumnName: $Keys, - sortDescending: boolean, -): Array> { - const compare = SORT_FUNCTIONS[sortedColumnName]; - invariant(compare != null); - // Don't sort in place. const sorted = diagnostics.slice().sort(compare); // We can't just reverse the sign of the comparison function because that would maintain the // ordering of "equal" items with respect to eachother. @@ -42,53 +37,19 @@ export default function sortDiagnostics( } const SORT_FUNCTIONS = { - classification: compose( - compareClassification, - compareSource, - comparePath, - compareDescription, - ), - providerName: compose( - compareSource, - compareClassification, - compareDescription, - comparePath, - ), - description: compose( - compareDescription, - compareSource, - compareClassification, - comparePath, - ), - dir: compose( - comparePath, - compareSource, - compareClassification, - compareDescription, - ), - location: compose( - compareBasename, - comparePath, - compareClassification, - compareSource, - compareDescription, - ), - line: compose( - compareBasename, - comparePath, - compareClassification, - compareSource, - compareDescription, - ), + classification: compose(compareClassification, compareSource, comparePath, compareDescription), + providerName: compose(compareSource, compareClassification, compareDescription, comparePath), + description: compose(compareDescription, compareSource, compareClassification, comparePath), + dir: compose(comparePath, compareSource, compareClassification, compareDescription), + location: compose(compareBasename, comparePath, compareClassification, compareSource, compareDescription), + line: compose(compareBasename, comparePath, compareClassification, compareSource, compareDescription) }; /** * Compose comparison functions so that, when one identifies the items as equal, the subsequent * functions are used to resolve the abiguity. */ -function compose( - ...comparisons: Array -): DiagnosticsComparison { +function compose(...comparisons) { return (a, b) => { for (const compare of comparisons) { const val = compare(a, b); @@ -100,28 +61,13 @@ function compose( }; } -function compareClassification( - a: Row, - b: Row, -): number { - return ( - compareClassificationKind( - a.data.classification.kind, - b.data.classification.kind, - ) || - compareClassificationSeverity( - a.data.classification.severity, - b.data.classification.severity, - ) - ); +function compareClassification(a, b) { + return compareClassificationKind(a.data.classification.kind, b.data.classification.kind) || compareClassificationSeverity(a.data.classification.severity, b.data.classification.severity); } const KIND_ORDER = ['review', 'lint']; -function compareClassificationKind( - a: ?DiagnosticMessageKind, - b: ?DiagnosticMessageKind, -): number { +function compareClassificationKind(a, b) { const aKind = a || 'lint'; const bKind = b || 'lint'; return KIND_ORDER.indexOf(aKind) - KIND_ORDER.indexOf(bKind); @@ -129,31 +75,19 @@ function compareClassificationKind( const SEVERITY_ORDER = ['Info', 'Warning', 'Error']; -function compareClassificationSeverity( - a: DiagnosticMessageType, - b: DiagnosticMessageType, -): number { +function compareClassificationSeverity(a, b) { return SEVERITY_ORDER.indexOf(a) - SEVERITY_ORDER.indexOf(b); } -function compareSource( - a: Row, - b: Row, -): number { +function compareSource(a, b) { return compareStrings(a.data.providerName, b.data.providerName); } -function compareDescription( - a: Row, - b: Row, -): number { +function compareDescription(a, b) { return compareStrings(a.data.description.text, b.data.description.text); } -function comparePath( - a: Row, - b: Row, -): number { +function comparePath(a, b) { const aLocation = a.data.location; const bLocation = b.data.location; if (aLocation == null && bLocation == null) { @@ -169,17 +103,12 @@ function comparePath( if (pathComparison !== 0) { return pathComparison; } - const aLine = - aLocation.locationInFile == null ? 0 : aLocation.locationInFile.line; - const bLine = - bLocation.locationInFile == null ? 0 : bLocation.locationInFile.line; + const aLine = aLocation.locationInFile == null ? 0 : aLocation.locationInFile.line; + const bLine = bLocation.locationInFile == null ? 0 : bLocation.locationInFile.line; return compareNumbers(aLine, bLine); } -function compareBasename( - a: Row, - b: Row, -): number { +function compareBasename(a, b) { const aLocationInFile = a.data.location && a.data.location.locationInFile; const bLocationInFile = b.data.location && b.data.location.locationInFile; if (aLocationInFile == null && bLocationInFile == null) { @@ -191,16 +120,13 @@ function compareBasename( if (bLocationInFile == null) { return 1; } - return ( - compareStrings(aLocationInFile.basename, bLocationInFile.basename) || - compareNumbers(aLocationInFile.line, bLocationInFile.line) - ); + return compareStrings(aLocationInFile.basename, bLocationInFile.basename) || compareNumbers(aLocationInFile.line, bLocationInFile.line); } -function compareStrings(a: string, b: string): number { +function compareStrings(a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); } -function compareNumbers(a: number, b: number): number { +function compareNumbers(a, b) { return a - b; -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/types.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/types.js index b56120b0..a726efc4 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/types.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/types.js @@ -1,40 +1 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; -import type { - DiagnosticMessage, - DiagnosticMessageKind, - UiConfig, -} from '../../atom-ide-diagnostics/lib/types'; - -// We group diagnostics based on kind and severity. -export type DiagnosticGroup = - | 'errors' - | 'warnings' - | 'info' - | 'review' - | 'action'; - -// State that's shared between every diagnostics panel instance. -export type GlobalViewState = { - diagnostics: Array, - pathToActiveTextEditor: ?NuclideUri, - filterByActiveTextEditor: boolean, - onFilterByActiveTextEditorChange: (isChecked: boolean) => mixed, - showDirectoryColumn: boolean, - autoVisibility: boolean, - showTraces: boolean, - onShowTracesChange: (isChecked: boolean) => mixed, - supportedMessageKinds: Set, - uiConfig: UiConfig, -}; +'use strict'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsCodeActions.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsCodeActions.js index 4465e985..ce88845b 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsCodeActions.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsCodeActions.js @@ -1,64 +1,80 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {CodeAction} from '../../../atom-ide-code-actions/lib/types'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = DiagnosticsCodeActions; -import {TextEditor} from 'atom'; -import * as React from 'react'; -import {Button} from 'nuclide-commons-ui/Button'; -import {ButtonGroup} from 'nuclide-commons-ui/ButtonGroup'; +var _atom = require('atom'); + +var _react = _interopRequireWildcard(require('react')); + +var _Button; + +function _load_Button() { + return _Button = require('nuclide-commons-ui/Button'); +} + +var _ButtonGroup; + +function _load_ButtonGroup() { + return _ButtonGroup = require('nuclide-commons-ui/ButtonGroup'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } // Maximum number of CodeActions to show for a given Diagnostic. -const MAX_CODE_ACTIONS = 4; +const MAX_CODE_ACTIONS = 4; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -export default function DiagnosticsCodeActions(props: { - codeActions: Map, -}): React.Element { - return ( -
- {Array.from(props.codeActions.entries()) - .splice(0, MAX_CODE_ACTIONS) - // TODO: (seansegal) T21130259 Display a "more" indicator when there are many CodeActions. - .map(([title, codeAction], i) => { - return ( - - - - ); - })} -
+function DiagnosticsCodeActions(props) { + return _react.createElement( + 'div', + { className: 'diagnostics-code-actions' }, + Array.from(props.codeActions.entries()).splice(0, MAX_CODE_ACTIONS) + // TODO: (seansegal) T21130259 Display a "more" indicator when there are many CodeActions. + .map(([title, codeAction], i) => { + return _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + { key: i }, + _react.createElement( + (_Button || _load_Button()).Button, + { + className: 'diagnostics-code-action-button', + size: 'EXTRA_SMALL', + onClick: () => { + // TODO: (seansegal) T21130332 Display CodeAction status indicators + codeAction.apply().catch(handleCodeActionFailure).then(() => { + // Return focus to the editor after clicking. + const activeItem = atom.workspace.getActivePaneItem(); + if (activeItem && activeItem instanceof _atom.TextEditor) { + activeItem.element.focus(); + } + }); + } }, + _react.createElement( + 'span', + { className: 'inline-block' }, + title + ) + ) + ); + }) ); } -function handleCodeActionFailure(error: ?Error) { +function handleCodeActionFailure(error) { atom.notifications.addWarning('Code action could not be applied', { description: error ? error.message : '', - dismissable: true, + dismissable: true }); -} +} \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessage.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessage.js index e8cb1d46..768d4cb0 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessage.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessage.js @@ -1,3 +1,38 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DiagnosticsMessageNoHeader = exports.DiagnosticsMessage = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Button; + +function _load_Button() { + return _Button = require('nuclide-commons-ui/Button'); +} + +var _ButtonGroup; + +function _load_ButtonGroup() { + return _ButtonGroup = require('nuclide-commons-ui/ButtonGroup'); +} + +var _DiagnosticsMessageText; + +function _load_DiagnosticsMessageText() { + return _DiagnosticsMessageText = require('./DiagnosticsMessageText'); +} + +var _DiagnosticsTraceItem; + +function _load_DiagnosticsTraceItem() { + return _DiagnosticsTraceItem = require('./DiagnosticsTraceItem'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,37 +41,19 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {DiagnosticMessage} from '../../../atom-ide-diagnostics/lib/types'; - -import * as React from 'react'; -import {Button, ButtonTypes} from 'nuclide-commons-ui/Button'; -import {ButtonGroup} from 'nuclide-commons-ui/ButtonGroup'; -import {DiagnosticsMessageText} from './DiagnosticsMessageText'; -import {DiagnosticsTraceItem} from './DiagnosticsTraceItem'; - -type DiagnosticsMessageProps = { - // these are processed in traceElements below - /* eslint-disable react/no-unused-prop-types */ - message: DiagnosticMessage, - goToLocation: (path: string, line: number) => mixed, - fixer: (message: DiagnosticMessage) => void, - children?: React.Node, - /* eslint-enable react/no-unused-prop-types */ -}; - const PROVIDER_CLASS_NAME = { Error: 'highlight-error', Warning: 'highlight-warning', Info: 'highlight-info', - Hint: '', + Hint: '' }; -function diagnosticHeader(props: DiagnosticsMessageProps) { - const {message, fixer} = props; +function diagnosticHeader(props) { + const { message, fixer } = props; const providerClassName = PROVIDER_CLASS_NAME[message.type]; let fixButton = null; if (message.fix != null) { @@ -44,55 +61,63 @@ function diagnosticHeader(props: DiagnosticsMessageProps) { fixer(message); }; const speculative = message.fix.speculative === true; - const buttonType = speculative ? undefined : ButtonTypes.SUCCESS; - fixButton = ( - + const buttonType = speculative ? undefined : (_Button || _load_Button()).ButtonTypes.SUCCESS; + fixButton = _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: buttonType, size: 'EXTRA_SMALL', onClick: applyFix }, + // flowlint-next-line sketchy-null-string:off + message.fix.title || 'Fix' ); } - return ( -
- {fixButton} - {message.providerName} -
+ return _react.createElement( + 'div', + { className: 'diagnostics-popup-header' }, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + null, + fixButton + ), + _react.createElement( + 'span', + { className: providerClassName }, + message.providerName + ) ); } -function traceElements(props: DiagnosticsMessageProps) { - const {message, goToLocation} = props; - return message.trace && message.trace.length ? ( -
- {message.trace.map((traceItem, i) => ( - - ))} -
+function traceElements(props) { + const { message, goToLocation } = props; + return message.trace && message.trace.length ? _react.createElement( + 'div', + { className: 'diagnostics-popup-trace' }, + message.trace.map((traceItem, i) => _react.createElement((_DiagnosticsTraceItem || _load_DiagnosticsTraceItem()).DiagnosticsTraceItem, { + key: i, + trace: traceItem, + goToLocation: goToLocation + })) ) : null; } -export const DiagnosticsMessage = (props: DiagnosticsMessageProps) => { - return ( -
- {diagnosticHeader(props)} -
- -
- {traceElements(props)} - {props.children} -
+const DiagnosticsMessage = exports.DiagnosticsMessage = props => { + return _react.createElement( + 'div', + null, + diagnosticHeader(props), + _react.createElement( + 'div', + { className: 'diagnostics-popup-message' }, + _react.createElement((_DiagnosticsMessageText || _load_DiagnosticsMessageText()).DiagnosticsMessageText, { message: props.message }) + ), + traceElements(props), + props.children ); }; -export const DiagnosticsMessageNoHeader = (props: DiagnosticsMessageProps) => { - return ( -
- - {traceElements(props)} -
+const DiagnosticsMessageNoHeader = exports.DiagnosticsMessageNoHeader = props => { + return _react.createElement( + 'div', + null, + _react.createElement((_DiagnosticsMessageText || _load_DiagnosticsMessageText()).DiagnosticsMessageText, { message: props.message }), + traceElements(props) ); -}; +}; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessageText.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessageText.js index 303ac8b3..382b960a 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessageText.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsMessageText.js @@ -1,39 +1,19 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import invariant from 'assert'; -import * as React from 'react'; -import {shell} from 'electron'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DiagnosticsMessageText = undefined; +exports.separateUrls = separateUrls; -type DiagnosticsMessageTextProps = { - preserveNewlines?: boolean, // defaults to true - message: { - html?: string, - text?: string, - }, -}; +var _react = _interopRequireWildcard(require('react')); -type UrlOrText = - | { - isUrl: true, - url: string, - } - | { - isUrl: false, - text: string, - }; +var _electron = require('electron'); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } // Exported for testing. -export function separateUrls(message: string): Array { +function separateUrls(message) { // Don't match periods at the end of URLs, because those are usually just to // end the sentence and not actually part of the URL. Optionally match // parameters following a question mark. @@ -42,84 +22,91 @@ export function separateUrls(message: string): Array { const mainUrl = /https?:\/\/[\w/.%-]*[\w/-]/.source; // characters allowed in query/fragment, disallow `.` at the end const queryChars = /[\w-~%&+.!=:@/?]*[\w-~%&+!=:@/?]/.source; - const urlRegex = new RegExp( - `${mainUrl}(?:\\?${queryChars})?(?:#${queryChars})?`, - 'g', - ); + const urlRegex = new RegExp(`${mainUrl}(?:\\?${queryChars})?(?:#${queryChars})?`, 'g'); const urls = message.match(urlRegex); const nonUrls = message.split(urlRegex); - const parts: Array = [ - { - isUrl: false, - text: nonUrls[0], - }, - ]; + const parts = [{ + isUrl: false, + text: nonUrls[0] + }]; for (let i = 1; i < nonUrls.length; i++) { - invariant(urls != null); + if (!(urls != null)) { + throw new Error('Invariant violation: "urls != null"'); + } + parts.push({ isUrl: true, - url: urls[i - 1], + url: urls[i - 1] }); parts.push({ isUrl: false, - text: nonUrls[i], + text: nonUrls[i] }); } return parts; -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ const LEADING_WHITESPACE_RE = /^\s+/; const NBSP = '\xa0'; -function renderRowWithLinks( - message: string, - rowIndex: number, -): React.Element { - const messageWithWhitespace = message.replace( - LEADING_WHITESPACE_RE, - whitespace => NBSP.repeat(whitespace.length), - ); +function renderRowWithLinks(message, rowIndex) { + const messageWithWhitespace = message.replace(LEADING_WHITESPACE_RE, whitespace => NBSP.repeat(whitespace.length)); const parts = separateUrls(messageWithWhitespace).map((part, index) => { if (!part.isUrl) { return part.text; } else { const openUrl = () => { - shell.openExternal(part.url); + _electron.shell.openExternal(part.url); }; - return ( - - {part.url} - + return _react.createElement( + 'a', + { href: '#', key: index, onClick: openUrl }, + part.url ); } }); return ( // We need to use a span here instead of a div so that `text-overflow: ellipsis` works. - - {parts} -
-
+ _react.createElement( + 'span', + { key: rowIndex }, + parts, + _react.createElement('br', null) + ) ); } -export const DiagnosticsMessageText = (props: DiagnosticsMessageTextProps) => { - const {message} = props; +const DiagnosticsMessageText = exports.DiagnosticsMessageText = props => { + const { message } = props; if (message.html != null) { - return ( - - ); + return _react.createElement('span', { + title: message.text, + dangerouslySetInnerHTML: { __html: message.html } + }); } else if (message.text != null) { - const rows = - props.preserveNewlines !== false - ? message.text.split('\n') - : [message.text]; - return {rows.map(renderRowWithLinks)}; + const rows = props.preserveNewlines !== false ? message.text.split('\n') : [message.text]; + return _react.createElement( + 'span', + { title: message.text }, + rows.map(renderRowWithLinks) + ); } else { - return Diagnostic lacks message.; + return _react.createElement( + 'span', + null, + 'Diagnostic lacks message.' + ); } -}; +}; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsPopup.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsPopup.js index 771761e2..bc2c70ee 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsPopup.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsPopup.js @@ -1,89 +1,101 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; -import type {DiagnosticMessage} from '../../../atom-ide-diagnostics/lib/types'; -import type {CodeAction} from '../../../atom-ide-code-actions/lib/types'; - -import * as React from 'react'; -import classnames from 'classnames'; -import analytics from 'nuclide-commons-atom/analytics'; -import {mapUnion} from 'nuclide-commons/collection'; -import {DiagnosticsMessage} from './DiagnosticsMessage'; -import DiagnosticsCodeActions from './DiagnosticsCodeActions'; - -type DiagnosticsPopupProps = { - messages: Array, - goToLocation: (filePath: NuclideUri, line: number) => mixed, - fixer: (message: DiagnosticMessage) => void, - codeActionsForMessage?: Map>, -}; - -function renderMessage( - fixer: (message: DiagnosticMessage) => void, - goToLocation: (filePath: NuclideUri, line: number) => mixed, - codeActionsForMessage: ?Map>, - message: DiagnosticMessage, - index: number, -): React.Element { - const className = classnames( - // native-key-bindings and tabIndex=-1 are both needed to allow copying the text in the popup. - 'native-key-bindings', - 'diagnostics-popup-diagnostic', - { - 'diagnostics-popup-error': message.type === 'Error', - 'diagnostics-popup-warning': message.type === 'Warning', - 'diagnostics-popup-info': message.type === 'Info', - }, - ); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DiagnosticsPopup = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _react = _interopRequireWildcard(require('react')); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _DiagnosticsMessage; + +function _load_DiagnosticsMessage() { + return _DiagnosticsMessage = require('./DiagnosticsMessage'); +} + +var _DiagnosticsCodeActions; + +function _load_DiagnosticsCodeActions() { + return _DiagnosticsCodeActions = _interopRequireDefault(require('./DiagnosticsCodeActions')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function renderMessage(fixer, goToLocation, codeActionsForMessage, message, index) { + const className = (0, (_classnames || _load_classnames()).default)( + // native-key-bindings and tabIndex=-1 are both needed to allow copying the text in the popup. + 'native-key-bindings', 'diagnostics-popup-diagnostic', { + 'diagnostics-popup-error': message.type === 'Error', + 'diagnostics-popup-warning': message.type === 'Warning', + 'diagnostics-popup-info': message.type === 'Info' + }); const codeActions = getCodeActions(message, codeActionsForMessage); - return ( -
- - {codeActions && codeActions.size ? ( - - ) : null} - -
+ return _react.createElement( + 'div', + { className: className, key: index, tabIndex: -1 }, + _react.createElement( + (_DiagnosticsMessage || _load_DiagnosticsMessage()).DiagnosticsMessage, + { + fixer: fixer, + goToLocation: goToLocation, + message: message }, + codeActions && codeActions.size ? _react.createElement((_DiagnosticsCodeActions || _load_DiagnosticsCodeActions()).default, { codeActions: codeActions }) : null + ) ); } -function getCodeActions( - message: DiagnosticMessage, - codeActionsForMessage: ?Map>, -): ?Map { +function getCodeActions(message, codeActionsForMessage) { const codeActionMaps = []; if (message.actions != null && message.actions.length > 0) { - codeActionMaps.push( - new Map( - message.actions.map(action => { - return [ - action.title, - { - async getTitle() { - return action.title; - }, - async apply() { - action.apply(); - }, - dispose() {}, - }, - ]; - }), - ), - ); + codeActionMaps.push(new Map(message.actions.map(action => { + return [action.title, { + getTitle() { + return (0, _asyncToGenerator.default)(function* () { + return action.title; + })(); + }, + apply() { + return (0, _asyncToGenerator.default)(function* () { + action.apply(); + })(); + }, + dispose() {} + }]; + }))); } if (codeActionsForMessage) { const actions = codeActionsForMessage.get(message); @@ -91,29 +103,29 @@ function getCodeActions( codeActionMaps.push(actions); } } - return codeActionMaps.length > 0 ? mapUnion(...codeActionMaps) : null; + return codeActionMaps.length > 0 ? (0, (_collection || _load_collection()).mapUnion)(...codeActionMaps) : null; } // TODO move LESS styles to nuclide-ui -export class DiagnosticsPopup extends React.Component { +class DiagnosticsPopup extends _react.Component { componentDidMount() { - analytics.track('diagnostics-show-popup'); + (_analytics || _load_analytics()).default.track('diagnostics-show-popup'); } render() { - const { + const _props = this.props, + { fixer, goToLocation, codeActionsForMessage, - messages, - ...rest - } = this.props; - return ( -
- {messages.map( - renderMessage.bind(null, fixer, goToLocation, codeActionsForMessage), - )} -
+ messages + } = _props, + rest = _objectWithoutProperties(_props, ['fixer', 'goToLocation', 'codeActionsForMessage', 'messages']); + return _react.createElement( + 'div', + Object.assign({ className: 'diagnostics-popup' }, rest), + messages.map(renderMessage.bind(null, fixer, goToLocation, codeActionsForMessage)) ); } } +exports.DiagnosticsPopup = DiagnosticsPopup; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTable.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTable.js index 1b893bd0..7df4b4e2 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTable.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTable.js @@ -1,156 +1,127 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _idx; + +function _load_idx() { + return _idx = _interopRequireDefault(require('idx')); +} + +var _memoizeUntilChanged; + +function _load_memoizeUntilChanged() { + return _memoizeUntilChanged = _interopRequireDefault(require('nuclide-commons/memoizeUntilChanged')); +} + +var _humanizePath; + +function _load_humanizePath() { + return _humanizePath = _interopRequireDefault(require('nuclide-commons-atom/humanizePath')); +} + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('nuclide-commons/nuclideUri')); +} + +var _goToLocation; + +function _load_goToLocation() { + return _goToLocation = require('nuclide-commons-atom/go-to-location'); +} + +var _Table; + +function _load_Table() { + return _Table = require('nuclide-commons-ui/Table'); +} + +var _sortDiagnostics; + +function _load_sortDiagnostics() { + return _sortDiagnostics = _interopRequireDefault(require('../sortDiagnostics')); +} + +var _DiagnosticsMessage; + +function _load_DiagnosticsMessage() { + return _DiagnosticsMessage = require('./DiagnosticsMessage'); +} + +var _DiagnosticsMessageText; + +function _load_DiagnosticsMessageText() { + return _DiagnosticsMessageText = require('./DiagnosticsMessageText'); +} + +var _Icon; + +function _load_Icon() { + return _Icon = require('nuclide-commons-ui/Icon'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const DIAGNOSTICS_TO_ROWS_TRACES_MAP = new WeakMap(); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -import type { - DiagnosticMessage, - DiagnosticMessageKind, - DiagnosticMessageType, -} from '../../../atom-ide-diagnostics/lib/types'; -import type {NuclideUri} from 'nuclide-commons/nuclideUri'; -import type {Column, Row} from 'nuclide-commons-ui/Table'; -import type {IconName} from 'nuclide-commons-ui/Icon'; - -import classnames from 'classnames'; -import invariant from 'assert'; -import idx from 'idx'; -import memoizeUntilChanged from 'nuclide-commons/memoizeUntilChanged'; -import humanizePath from 'nuclide-commons-atom/humanizePath'; -import {insideOut, arrayEqual} from 'nuclide-commons/collection'; -import * as React from 'react'; -import nuclideUri from 'nuclide-commons/nuclideUri'; -import {goToLocation} from 'nuclide-commons-atom/go-to-location'; -import {Table} from 'nuclide-commons-ui/Table'; -import sortDiagnostics from '../sortDiagnostics'; -import {DiagnosticsMessageNoHeader} from './DiagnosticsMessage'; -import {DiagnosticsMessageText} from './DiagnosticsMessageText'; -import {Icon} from 'nuclide-commons-ui/Icon'; - -const DIAGNOSTICS_TO_ROWS_TRACES_MAP = new WeakMap(); const DIAGNOSTICS_TO_ROWS_NO_TRACES_MAP = new WeakMap(); // text is always used for sorting, while we render the element. -type DescriptionField = { - diagnostic: DiagnosticMessage, - showTraces: boolean, - text: string, - isPlainText: boolean, -}; - -type Location = {| - fullPath: NuclideUri, - locationInFile: ?{| - basename: string, - line: number, - |}, -|}; - -export type DisplayDiagnostic = { - +classification: { - kind: DiagnosticMessageKind, - severity: DiagnosticMessageType, - }, - +providerName: string, - +description: { - showTraces: boolean, - diagnostic: DiagnosticMessage, - text: string, - isPlainText: boolean, - }, - +dir: string, - +location: ?Location, - +line: ?number, -}; -type ColumnName = $Keys; // Maximum number of results to render in the table before truncating and displaying a "Max results // reached" message. const MAX_RESULTS_COUNT = 1000; -type Props = { - diagnostics: Array, - selectedMessage: ?DiagnosticMessage, - gotoMessageLocation: ( - message: DiagnosticMessage, - options: {|focusEditor: boolean|}, - ) => void, - selectMessage: (message: DiagnosticMessage) => void, - showFileName: ?boolean, - showDirectoryColumn: boolean, - showTraces: boolean, -}; - -type State = { - sortDescending: boolean, - sortedColumn: ColumnName, -}; +class DiagnosticsTable extends _react.PureComponent { -export default class DiagnosticsTable extends React.PureComponent< - Props, - State, -> { - _previousSelectedIndex: number = -1; - _table: ?Table; - - constructor(props: Props) { + constructor(props) { super(props); // Memoize `_getRows()` - (this: any)._getRows = memoizeUntilChanged( - this._getRows, - (diagnostics, showTraces) => ({diagnostics, showTraces}), - (a, b) => - a.showTraces === b.showTraces && - arrayEqual(a.diagnostics, b.diagnostics), - ); + + _initialiseProps.call(this); + + this._getRows = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(this._getRows, (diagnostics, showTraces) => ({ diagnostics, showTraces }), (a, b) => a.showTraces === b.showTraces && (0, (_collection || _load_collection()).arrayEqual)(a.diagnostics, b.diagnostics)); this.state = { sortDescending: true, - sortedColumn: 'classification', + sortedColumn: 'classification' }; } - _handleSort = (sortedColumn: ColumnName, sortDescending: boolean): void => { - this.setState({ - sortedColumn, - sortDescending, - }); - }; - - _handleSelectTableRow = ( - item: {diagnostic: DiagnosticMessage}, - index: number, - event: Event | SyntheticEvent<*>, - ): void => { - this.props.selectMessage(item.diagnostic); - // Users navigating with the keyboard may just be moving through items on their way to another. - // If they have pending pane items enabled, it's not a big deal if we open the editor anyway. - // But if they don't, we could wind up opening a ton of files they didn't even care about so, - // to be safe, we won't do anything in that case. - if ( - event.type !== 'click' && - !atom.config.get('core.allowPendingPaneItems') - ) { - return; - } - this.props.gotoMessageLocation(item.diagnostic, {focusEditor: false}); - }; - - _handleConfirmTableRow = (item: {diagnostic: DiagnosticMessage}): void => { - this.props.gotoMessageLocation(item.diagnostic, {focusEditor: true}); - }; - - _getColumns(): Array> { - const {showFileName, showDirectoryColumn} = this.props; + _getColumns() { + const { showFileName, showDirectoryColumn } = this.props; // These need to add up to 1. // TODO: Update the Table component so that we can have more control over this (and provide @@ -172,7 +143,7 @@ export default class DiagnosticsTable extends React.PureComponent< title: 'Path', width: DIR_WIDTH, shouldRightAlign: true, - cellClassName: 'nuclide-diagnostics-ui-cell-dir', + cellClassName: 'nuclide-diagnostics-ui-cell-dir' }); descriptionWidth -= DIR_WIDTH; } @@ -182,7 +153,7 @@ export default class DiagnosticsTable extends React.PureComponent< key: 'location', title: 'File Name', width: FILENAME_WIDTH, - cellClassName: 'nuclide-diagnostics-ui-cell-filename', + cellClassName: 'nuclide-diagnostics-ui-cell-filename' }); descriptionWidth -= FILENAME_WIDTH; } else { @@ -193,57 +164,37 @@ export default class DiagnosticsTable extends React.PureComponent< title: 'Line', shouldRightAlign: true, width: LINE_NUMBER_WIDTH, - minWidth: 60, + minWidth: 60 }); descriptionWidth -= LINE_NUMBER_WIDTH; } - return [ - { - component: TypeComponent, - key: 'classification', - title: 'Type', - width: TYPE_WIDTH, - minWidth: 55, - cellClassName: 'nuclide-diagnostics-ui-cell-classification', - }, - { - key: 'providerName', - title: 'Source', - width: SOURCE_WIDTH, - minWidth: 100, - }, - { - component: this._renderDescription, - key: 'description', - title: 'Description', - width: descriptionWidth, - cellClassName: 'nuclide-diagnostics-ui-cell-description', - }, - ...filePathColumns, - ]; + return [{ + component: TypeComponent, + key: 'classification', + title: 'Type', + width: TYPE_WIDTH, + minWidth: 55, + cellClassName: 'nuclide-diagnostics-ui-cell-classification' + }, { + key: 'providerName', + title: 'Source', + width: SOURCE_WIDTH, + minWidth: 100 + }, { + component: this._renderDescription, + key: 'description', + title: 'Description', + width: descriptionWidth, + cellClassName: 'nuclide-diagnostics-ui-cell-description' + }, ...filePathColumns]; } // False positive for this lint rule? // eslint-disable-next-line react/no-unused-prop-types - _renderDescription = (props: {data: DescriptionField}) => { - const {showTraces, diagnostic, text, isPlainText} = props.data; - return showTraces - ? DiagnosticsMessageNoHeader({ - message: diagnostic, - goToLocation: (file: string, line: number) => - goToLocation(file, {line}), - fixer: () => {}, - }) - : DiagnosticsMessageText({ - preserveNewlines: showTraces, - message: {text, html: isPlainText ? undefined : text}, - }); - }; - _getSortOptions( - columns: Array>, - ): {|sortedColumn: ColumnName, sortDescending: boolean|} { + + _getSortOptions(columns) { // If the column the user sorted by has been removed, return the default sorting. We do this // (instead of updating the state) so that if the column gets added back we can return to // sorting by that. @@ -251,78 +202,72 @@ export default class DiagnosticsTable extends React.PureComponent< if (!columnKeys.includes(this.state.sortedColumn)) { return { sortedColumn: 'classification', - sortDescending: true, + sortDescending: true }; } // Otherwise, return the sorting they've chosen. return { sortedColumn: this.state.sortedColumn, - sortDescending: this.state.sortDescending, + sortDescending: this.state.sortDescending }; } - render(): React.Node { - const {diagnostics, selectedMessage, showTraces} = this.props; + render() { + const { diagnostics, selectedMessage, showTraces } = this.props; const columns = this._getColumns(); - const {sortedColumn, sortDescending} = this._getSortOptions(columns); + const { sortedColumn, sortDescending } = this._getSortOptions(columns); const diagnosticRows = this._getRows(diagnostics, showTraces); - let sortedRows = this._sortRows( - diagnosticRows, - sortedColumn, - sortDescending, - ); + let sortedRows = this._sortRows(diagnosticRows, sortedColumn, sortDescending); let maxResultsMessage; if (sortedRows.length > MAX_RESULTS_COUNT) { sortedRows = sortedRows.slice(0, MAX_RESULTS_COUNT); - maxResultsMessage = ( -
- Max results ({MAX_RESULTS_COUNT}) reached. Fix diagnostics or show - only diagnostics for the current file to view more. -
+ maxResultsMessage = _react.createElement( + 'div', + { className: 'highlight-warning diagnostics-ui-table-message' }, + 'Max results (', + MAX_RESULTS_COUNT, + ') reached. Fix diagnostics or show only diagnostics for the current file to view more.' ); } const selectedIndex = this._findSelectedIndex(selectedMessage, sortedRows); - return ( -
- { - this._table = table; - }} - collapsable={true} - columns={columns} - emptyComponent={EmptyComponent} - fixedHeader={true} - maxBodyHeight="99999px" - rows={sortedRows} - sortable={true} - onSort={this._handleSort} - sortedColumn={sortedColumn} - sortDescending={sortDescending} - selectable={true} - selectedIndex={selectedIndex} - onSelect={this._handleSelectTableRow} - onConfirm={this._handleConfirmTableRow} - enableKeyboardNavigation={true} - /> - {maxResultsMessage} - + 'diagnostics-ui-table-container-empty': sortedRows.length === 0 + }) }, + _react.createElement((_Table || _load_Table()).Table, { + ref: table => { + this._table = table; + }, + collapsable: true, + columns: columns, + emptyComponent: EmptyComponent, + fixedHeader: true, + maxBodyHeight: '99999px', + rows: sortedRows, + sortable: true, + onSort: this._handleSort, + sortedColumn: sortedColumn, + sortDescending: sortDescending, + selectable: true, + selectedIndex: selectedIndex, + onSelect: this._handleSelectTableRow, + onConfirm: this._handleConfirmTableRow, + enableKeyboardNavigation: true + }), + maxResultsMessage ); } - focus(): void { + focus() { if (this._table != null) { this._table.focus(); } } - _findSelectedIndex( - selectedMessage: ?DiagnosticMessage, - rows: Array>, - ): number { + _findSelectedIndex(selectedMessage, rows) { if (selectedMessage == null) { return -1; } @@ -331,8 +276,8 @@ export default class DiagnosticsTable extends React.PureComponent< let bestRankedIndex = -1; // Look for the closest match, starting with the previously selected index. - for (const [row, i] of insideOut(rows, this._previousSelectedIndex)) { - const {diagnostic} = row.data.description; + for (const [row, i] of (0, (_collection || _load_collection()).insideOut)(rows, this._previousSelectedIndex)) { + const { diagnostic } = row.data.description; if (diagnostic === selectedMessage) { bestRankedIndex = i; break; @@ -352,34 +297,30 @@ export default class DiagnosticsTable extends React.PureComponent< return bestRankedIndex; } - _getRows( - diagnostics: Array, - showTraces: boolean, - ): Array> { - const diagnosticsToRows = showTraces - ? DIAGNOSTICS_TO_ROWS_TRACES_MAP - : DIAGNOSTICS_TO_ROWS_NO_TRACES_MAP; + _getRows(diagnostics, showTraces) { + const diagnosticsToRows = showTraces ? DIAGNOSTICS_TO_ROWS_TRACES_MAP : DIAGNOSTICS_TO_ROWS_NO_TRACES_MAP; return diagnostics.map(diagnostic => { let row = diagnosticsToRows.get(diagnostic); if (row == null) { - const {dir, location} = getLocation(diagnostic); + var _ref, _ref2; + + const { dir, location } = getLocation(diagnostic); row = { data: { classification: { kind: diagnostic.kind || 'lint', - severity: diagnostic.type, + severity: diagnostic.type }, providerName: diagnostic.providerName, - description: { + description: Object.assign({ showTraces, - diagnostic, - ...getMessageContent(diagnostic, showTraces), - }, + diagnostic + }, getMessageContent(diagnostic, showTraces)), dir, location, diagnostic, - line: idx(location, _ => _.locationInFile.line), - }, + line: (_ref = location) != null ? (_ref2 = _ref.locationInFile) != null ? _ref2.line : _ref2 : _ref + } }; diagnosticsToRows.set(diagnostic, row); } @@ -388,36 +329,74 @@ export default class DiagnosticsTable extends React.PureComponent< } // TODO: Memoize this so we don't recompute unnecessarily. - _sortRows( - rows: Array>, - sortedColumn: $Keys, - descending: boolean, - ): Array> { - return sortDiagnostics(rows, sortedColumn, descending); + _sortRows(rows, sortedColumn, descending) { + return (0, (_sortDiagnostics || _load_sortDiagnostics()).default)(rows, sortedColumn, descending); } } -const EmptyComponent = () => ( -
No diagnostic messages
-); +exports.default = DiagnosticsTable; + +var _initialiseProps = function () { + this._previousSelectedIndex = -1; -type Classification = { - kind: DiagnosticMessageKind, - severity: DiagnosticMessageType, + this._handleSort = (sortedColumn, sortDescending) => { + this.setState({ + sortedColumn, + sortDescending + }); + }; + + this._handleSelectTableRow = (item, index, event) => { + this.props.selectMessage(item.diagnostic); + // Users navigating with the keyboard may just be moving through items on their way to another. + // If they have pending pane items enabled, it's not a big deal if we open the editor anyway. + // But if they don't, we could wind up opening a ton of files they didn't even care about so, + // to be safe, we won't do anything in that case. + if (event.type !== 'click' && !atom.config.get('core.allowPendingPaneItems')) { + return; + } + this.props.gotoMessageLocation(item.diagnostic, { focusEditor: false }); + }; + + this._handleConfirmTableRow = item => { + this.props.gotoMessageLocation(item.diagnostic, { focusEditor: true }); + }; + + this._renderDescription = props => { + const { showTraces, diagnostic, text, isPlainText } = props.data; + return showTraces ? (0, (_DiagnosticsMessage || _load_DiagnosticsMessage()).DiagnosticsMessageNoHeader)({ + message: diagnostic, + goToLocation: (file, line) => (0, (_goToLocation || _load_goToLocation()).goToLocation)(file, { line }), + fixer: () => {} + }) : (0, (_DiagnosticsMessageText || _load_DiagnosticsMessageText()).DiagnosticsMessageText)({ + preserveNewlines: showTraces, + message: { text, html: isPlainText ? undefined : text } + }); + }; }; -function TypeComponent(props: {data: Classification}): React.Element { +const EmptyComponent = () => _react.createElement( + 'div', + { className: 'diagnostics-ui-empty-component' }, + 'No diagnostic messages' +); + +function TypeComponent(props) { const classification = props.data; const iconName = getIconName(classification); - return ; + return _react.createElement((_Icon || _load_Icon()).Icon, { icon: iconName }); } -function getIconName(classification: Classification): IconName { - const {kind, severity} = classification; +function getIconName(classification) { + const { kind, severity } = classification; if (kind === 'review') { return 'nuclicon-comment-discussion'; } - invariant(severity !== 'Hint'); + + if (!(severity !== 'Hint')) { + throw new Error('Invariant violation: "severity !== \'Hint\'"'); + } + switch (severity) { case 'Warning': return 'nuclicon-warning'; @@ -426,22 +405,16 @@ function getIconName(classification: Classification): IconName { case 'Info': return 'info'; default: - (severity: empty); + severity; throw new Error(`Invalid severity: ${severity}`); } } -function getMessageContent( - diagnostic: DiagnosticMessage, - showTraces: boolean, -): {text: string, isPlainText: boolean} { +function getMessageContent(diagnostic, showTraces) { let text = ''; let isPlainText = true; const traces = diagnostic.trace || []; - const allMessages: Array<{html?: string, text?: string}> = [ - diagnostic, - ...traces, - ]; + const allMessages = [diagnostic, ...traces]; for (const message of allMessages) { // TODO: A mix of html and text diagnostics will yield a wonky sort ordering. if (message.html != null) { @@ -453,64 +426,79 @@ function getMessageContent( throw new Error('Neither text nor html property defined on message'); } } - return {text: text.trim(), isPlainText}; + return { text: text.trim(), isPlainText }; } -function DirComponent(props: {data: string}): React.Element { +function DirComponent(props) { return ( // We're abusing `direction: rtl` here so we need the LRM to keep the slash on the right. -
- ‎{nuclideUri.normalizeDir(props.data)}‎ -
+ _react.createElement( + 'div', + { className: 'nuclide-diagnostics-ui-dir-cell-contents' }, + '\u200E', + (_nuclideUri || _load_nuclideUri()).default.normalizeDir(props.data), + '\u200E' + ) ); } -function FilenameComponent(props: {data: ?Location}): React.Element { +function FilenameComponent(props) { const locationInFile = props.data && props.data.locationInFile; if (locationInFile == null) { // This is a project diagnostic. - return {DASH}; + return _react.createElement( + 'span', + null, + DASH + ); } - const {basename, line} = locationInFile; - return ( - - {basename} - :{line} - + const { basename, line } = locationInFile; + return _react.createElement( + 'span', + null, + basename, + _react.createElement( + 'span', + { className: 'nuclide-diagnostics-ui-line-number' }, + ':', + line + ) ); } -function LineNumberComponent(props: {data: ?number}): React.Element { +function LineNumberComponent(props) { const line = props.data; // Show a dash if this is a project diagnostic. - return {line == null ? DASH : line}; + return _react.createElement( + 'span', + null, + line == null ? DASH : line + ); } -function getLocation( - diagnostic: DiagnosticMessage, -): {dir: string, location: ?Location} { - const {filePath, range} = diagnostic; +function getLocation(diagnostic) { + const { filePath, range } = diagnostic; const line = range ? range.start.row + 1 : 0; - const humanized = humanizePath(filePath); - if (nuclideUri.endsWithSeparator(humanized)) { + const humanized = (0, (_humanizePath || _load_humanizePath()).default)(filePath); + if ((_nuclideUri || _load_nuclideUri()).default.endsWithSeparator(humanized)) { // It's a directory. return { dir: humanized, location: { fullPath: filePath, - locationInFile: null, - }, + locationInFile: null + } }; } - const {dir, base: basename} = nuclideUri.parsePath(humanized); + const { dir, base: basename } = (_nuclideUri || _load_nuclideUri()).default.parsePath(humanized); return { dir, location: { fullPath: filePath, - locationInFile: {basename, line}, - }, + locationInFile: { basename, line } + } }; } @@ -518,17 +506,12 @@ function getLocation( * Compute a number indicating the relative similarity of two messages. The smaller the number, the * more similar. (`null` indicates not at all similar.) */ -function compareMessages(a: DiagnosticMessage, b: DiagnosticMessage): ?number { +function compareMessages(a, b) { const aKind = a.kind || 'lint'; const bKind = b.kind || 'lint'; const aFilePath = a.filePath; const bFilePath = b.filePath; - if ( - aKind !== bKind || - a.providerName !== b.providerName || - a.type !== b.type || - aFilePath !== bFilePath - ) { + if (aKind !== bKind || a.providerName !== b.providerName || a.type !== b.type || aFilePath !== bFilePath) { return null; } const aRange = a.range; @@ -549,4 +532,4 @@ function compareMessages(a: DiagnosticMessage, b: DiagnosticMessage): ?number { return Math.abs(aRange.start.row - bRange.start.row); } -const DASH = '\u2014'; +const DASH = '\u2014'; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTraceItem.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTraceItem.js index 7087e3aa..dc8fa9c5 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTraceItem.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsTraceItem.js @@ -1,28 +1,23 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {DiagnosticTrace} from '../../../atom-ide-diagnostics/lib/types'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DiagnosticsTraceItem = undefined; -import * as React from 'react'; -import {DiagnosticsMessageText} from './DiagnosticsMessageText'; +var _react = _interopRequireWildcard(require('react')); -type DiagnosticsTraceItemProps = { - trace: DiagnosticTrace, - goToLocation: (path: string, line: number) => mixed, -}; +var _DiagnosticsMessageText; + +function _load_DiagnosticsMessageText() { + return _DiagnosticsMessageText = require('./DiagnosticsMessageText'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } // TODO move LESS styles to nuclide-ui -export const DiagnosticsTraceItem = (props: DiagnosticsTraceItemProps) => { - const {trace, goToLocation} = props; +const DiagnosticsTraceItem = exports.DiagnosticsTraceItem = props => { + const { trace, goToLocation } = props; let locSpan = null; // Local variable so that the type refinement holds in the onClick handler. const path = trace.filePath; @@ -33,23 +28,36 @@ export const DiagnosticsTraceItem = (props: DiagnosticsTraceItemProps) => { if (trace.range) { locString += `:${trace.range.start.row + 1}`; } - const onClick = (event: SyntheticMouseEvent<>) => { + const onClick = event => { event.stopPropagation(); goToLocation(path, Math.max(trace.range ? trace.range.start.row : 0, 0)); }; - locSpan = ( - - :{' '} - - {locString} - - + locSpan = _react.createElement( + 'span', + null, + ':', + ' ', + _react.createElement( + 'a', + { href: '#', onClick: onClick }, + locString + ) ); } - return ( -
- - {locSpan} -
+ return _react.createElement( + 'div', + null, + _react.createElement((_DiagnosticsMessageText || _load_DiagnosticsMessageText()).DiagnosticsMessageText, { message: trace }), + locSpan ); -}; +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsView.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsView.js index 1f1a1d7e..00c70ac9 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsView.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/DiagnosticsView.js @@ -1,3 +1,90 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _DiagnosticsTable; + +function _load_DiagnosticsTable() { + return _DiagnosticsTable = _interopRequireDefault(require('./DiagnosticsTable')); +} + +var _showModal; + +function _load_showModal() { + return _showModal = _interopRequireDefault(require('nuclide-commons-ui/showModal')); +} + +var _Toggle; + +function _load_Toggle() { + return _Toggle = require('nuclide-commons-ui/Toggle'); +} + +var _Toolbar; + +function _load_Toolbar() { + return _Toolbar = require('nuclide-commons-ui/Toolbar'); +} + +var _ToolbarLeft; + +function _load_ToolbarLeft() { + return _ToolbarLeft = require('nuclide-commons-ui/ToolbarLeft'); +} + +var _ToolbarRight; + +function _load_ToolbarRight() { + return _ToolbarRight = require('nuclide-commons-ui/ToolbarRight'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _Button; + +function _load_Button() { + return _Button = require('nuclide-commons-ui/Button'); +} + +var _ButtonGroup; + +function _load_ButtonGroup() { + return _ButtonGroup = require('nuclide-commons-ui/ButtonGroup'); +} + +var _FilterButton; + +function _load_FilterButton() { + return _FilterButton = _interopRequireDefault(require('./FilterButton')); +} + +var _RegExpFilter; + +function _load_RegExpFilter() { + return _RegExpFilter = _interopRequireDefault(require('nuclide-commons-ui/RegExpFilter')); +} + +var _SettingsModal; + +function _load_SettingsModal() { + return _SettingsModal = _interopRequireDefault(require('./SettingsModal')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Dismissable panel that displays the diagnostics from nuclide-diagnostics-store. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,72 +93,49 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type { - DiagnosticMessage, - DiagnosticMessageKind, - UiConfig, -} from '../../../atom-ide-diagnostics/lib/types'; -import type {DiagnosticGroup} from '../types'; -import type { - RegExpFilterChange, - RegExpFilterValue, -} from 'nuclide-commons-ui/RegExpFilter'; - -import analytics from 'nuclide-commons-atom/analytics'; -import DiagnosticsTable from './DiagnosticsTable'; -import showModal from 'nuclide-commons-ui/showModal'; -import {Toggle} from 'nuclide-commons-ui/Toggle'; -import {Toolbar} from 'nuclide-commons-ui/Toolbar'; -import {ToolbarLeft} from 'nuclide-commons-ui/ToolbarLeft'; -import {ToolbarRight} from 'nuclide-commons-ui/ToolbarRight'; -import * as React from 'react'; -import {Button, ButtonSizes} from 'nuclide-commons-ui/Button'; -import {ButtonGroup} from 'nuclide-commons-ui/ButtonGroup'; -import FilterButton from './FilterButton'; -import RegExpFilter from 'nuclide-commons-ui/RegExpFilter'; -import SettingsModal from './SettingsModal'; - -export type Props = { - diagnostics: Array, - filterByActiveTextEditor: boolean, - onFilterByActiveTextEditorChange: (isChecked: boolean) => mixed, - showDirectoryColumn: boolean, - showTraces: boolean, - onShowTracesChange: (isChecked: boolean) => mixed, - gotoMessageLocation: ( - message: DiagnosticMessage, - options: {|focusEditor: boolean|}, - ) => void, - selectMessage: (message: DiagnosticMessage) => void, - selectedMessage: ?DiagnosticMessage, - supportedMessageKinds: Set, - uiConfig: UiConfig, - isVisible: boolean, - // Used by the DiagnosticsViewModel. - autoVisibility: boolean, // eslint-disable-line react/no-unused-prop-types - - hiddenGroups: Set, - onTypeFilterChange: (type: DiagnosticGroup) => mixed, - textFilter: RegExpFilterValue, - onTextFilterChange: (change: RegExpFilterChange) => mixed, -}; +class DiagnosticsView extends _react.Component { + constructor(...args) { + var _temp; -/** - * Dismissable panel that displays the diagnostics from nuclide-diagnostics-store. - */ -export default class DiagnosticsView extends React.Component { - _table: ?DiagnosticsTable; + return _temp = super(...args), this._showSettings = () => { + (0, (_showModal || _load_showModal()).default)(() => _react.createElement((_SettingsModal || _load_SettingsModal()).default, { config: this.props.uiConfig })); + }, this._handleShowTracesChange = isChecked => { + (_analytics || _load_analytics()).default.track('diagnostics-panel-toggle-show-traces', { + isChecked: isChecked.toString() + }); + this.props.onShowTracesChange.call(null, isChecked); + }, this._handleFilterByActiveTextEditorChange = shouldFilter => { + (_analytics || _load_analytics()).default.track('diagnostics-panel-toggle-current-file', { + isChecked: shouldFilter.toString() + }); + this.props.onFilterByActiveTextEditorChange.call(null, shouldFilter); + }, this._openAllFilesWithErrors = () => { + atom.commands.dispatch(atom.views.getView(atom.workspace), 'diagnostics:open-all-files-with-errors'); + }, this._handleFocus = event => { + if (this._table == null) { + return; + } + let el = event.target; + while (el != null) { + if (el.tagName === 'INPUT' || el.tagName === 'BUTTON') { + return; + } + el = el.parentElement; + } + this._table.focus(); + }, _temp; + } - shouldComponentUpdate(nextProps: Props): boolean { + shouldComponentUpdate(nextProps) { return nextProps.isVisible; } - render(): React.Element { - const {diagnostics, showDirectoryColumn, showTraces} = this.props; + render() { + const { diagnostics, showDirectoryColumn, showTraces } = this.props; const groups = ['errors', 'warnings', 'info']; if (this.props.supportedMessageKinds.has('review')) { @@ -81,124 +145,90 @@ export default class DiagnosticsView extends React.Component { groups.push('action'); } - const showFullDescriptionToggle = diagnostics.find( - diagnostic => - // flowlint-next-line sketchy-null-string:off - diagnostic.trace || (diagnostic.text && diagnostic.text.includes('\n')), - ); + const showFullDescriptionToggle = diagnostics.find(diagnostic => + // flowlint-next-line sketchy-null-string:off + diagnostic.trace || diagnostic.text && diagnostic.text.includes('\n')); - return ( -
- - - - {groups.map(group => ( - { - this.props.onTypeFilterChange(group); - }} - /> - ))} - - - {/* TODO: This will probably change to a dropdown to also accommodate Head Changes */} - - - - {showFullDescriptionToggle ? ( - - ) : null} - -
+ width: '100%' + } }, + _react.createElement( + (_Toolbar || _load_Toolbar()).Toolbar, + { location: 'top' }, + _react.createElement( + (_ToolbarLeft || _load_ToolbarLeft()).ToolbarLeft, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + { className: 'inline-block' }, + groups.map(group => _react.createElement((_FilterButton || _load_FilterButton()).default, { + key: group, + group: group, + selected: !this.props.hiddenGroups.has(group), + onClick: () => { + this.props.onTypeFilterChange(group); + } + })) + ), + _react.createElement((_RegExpFilter || _load_RegExpFilter()).default, { + value: this.props.textFilter, + onChange: this.props.onTextFilterChange + }), + _react.createElement((_Toggle || _load_Toggle()).Toggle, { + className: 'inline-block', + onChange: this._handleFilterByActiveTextEditorChange, + toggled: this.props.filterByActiveTextEditor, + label: 'Current File Only' + }) + ), + _react.createElement( + (_ToolbarRight || _load_ToolbarRight()).ToolbarRight, + null, + showFullDescriptionToggle ? _react.createElement((_Toggle || _load_Toggle()).Toggle, { + className: 'inline-block', + onChange: this._handleShowTracesChange, + toggled: this.props.showTraces, + label: 'Full Description' + }) : null, + _react.createElement( + (_Button || _load_Button()).Button, + { + onClick: this._openAllFilesWithErrors, + size: (_Button || _load_Button()).ButtonSizes.SMALL, + disabled: diagnostics.length === 0, + className: 'inline-block', + title: 'Open All' }, + 'Open All' + ), + _react.createElement((_Button || _load_Button()).Button, { + icon: 'gear', + size: (_Button || _load_Button()).ButtonSizes.SMALL, + onClick: this._showSettings + }) + ) + ), + _react.createElement((_DiagnosticsTable || _load_DiagnosticsTable()).default, { + ref: table => { + this._table = table; + }, + showFileName: !this.props.filterByActiveTextEditor, + diagnostics: diagnostics, + showDirectoryColumn: showDirectoryColumn, + showTraces: showTraces, + selectedMessage: this.props.selectedMessage, + selectMessage: this.props.selectMessage, + gotoMessageLocation: this.props.gotoMessageLocation + }) ); } - _showSettings = (): void => { - showModal(() => ); - }; - - _handleShowTracesChange = (isChecked: boolean): void => { - analytics.track('diagnostics-panel-toggle-show-traces', { - isChecked: isChecked.toString(), - }); - this.props.onShowTracesChange.call(null, isChecked); - }; - - _handleFilterByActiveTextEditorChange = (shouldFilter: boolean): void => { - analytics.track('diagnostics-panel-toggle-current-file', { - isChecked: shouldFilter.toString(), - }); - this.props.onFilterByActiveTextEditorChange.call(null, shouldFilter); - }; - - _openAllFilesWithErrors = (): void => { - atom.commands.dispatch( - atom.views.getView(atom.workspace), - 'diagnostics:open-all-files-with-errors', - ); - }; - - _handleFocus = (event: SyntheticMouseEvent<*>): void => { - if (this._table == null) { - return; - } - let el = event.target; - while (el != null) { - if (el.tagName === 'INPUT' || el.tagName === 'BUTTON') { - return; - } - el = (el: any).parentElement; - } - this._table.focus(); - }; } +exports.default = DiagnosticsView; \ No newline at end of file diff --git a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/FilterButton.js b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/FilterButton.js index a7885750..adea11cf 100644 --- a/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/FilterButton.js +++ b/modules/atom-ide-ui/pkg/atom-ide-diagnostics-ui/lib/ui/FilterButton.js @@ -1,3 +1,26 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = FilterButton; + +var _Button; + +function _load_Button() { + return _Button = require('nuclide-commons-ui/Button'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _GroupUtils; + +function _load_GroupUtils() { + return _GroupUtils = _interopRequireWildcard(require('../GroupUtils')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,33 +29,19 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {DiagnosticGroup} from '../types'; - -import {Button, ButtonSizes} from 'nuclide-commons-ui/Button'; -import * as React from 'react'; -import * as GroupUtils from '../GroupUtils'; - -type Props = {| - group: DiagnosticGroup, - selected: boolean, - onClick: () => mixed, -|}; - -export default function FilterButton(props: Props): React.Node { - const {selected, group} = props; - const displayName = GroupUtils.getDisplayName(group); +function FilterButton(props) { + const { selected, group } = props; + const displayName = (_GroupUtils || _load_GroupUtils()).getDisplayName(group); const title = props.selected ? `Hide ${displayName}` : `Show ${displayName}`; - return ( - - - - - -); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ButtonExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); +} + +var _ButtonGroup; + +function _load_ButtonGroup() { + return _ButtonGroup = require('./ButtonGroup'); +} + +var _ButtonToolbar; + +function _load_ButtonToolbar() { + return _ButtonToolbar = require('./ButtonToolbar'); +} + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const ButtonSizeExample = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', size: 'EXTRA_SMALL' }, + 'extra_small' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', size: 'SMALL' }, + 'small' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block' }, + 'regular' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', size: 'LARGE' }, + 'large' + ) +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -const ButtonDisabledExample = (): React.Element => ( - - - - +const ButtonDisabledExample = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block' }, + 'enabled' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', disabled: true }, + 'disabled' + ) ); -const ButtonColorExample = (): React.Element => ( -
- - - - - - - - - - -

selected:

- - - - - - - -
-
+const ButtonColorExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + null, + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'PRIMARY' }, + 'primary' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'INFO' }, + 'info' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'SUCCESS' }, + 'success' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'WARNING' }, + 'warning' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'ERROR' }, + 'error' + ) + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + 'p', + null, + 'selected:' + ), + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + null, + _react.createElement( + (_Button || _load_Button()).Button, + { selected: true, buttonType: 'PRIMARY' }, + 'primary' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { selected: true, buttonType: 'INFO' }, + 'info' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { selected: true, buttonType: 'SUCCESS' }, + 'success' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { selected: true, buttonType: 'WARNING' }, + 'warning' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { selected: true, buttonType: 'ERROR' }, + 'error' + ) + ) + ) ); -const ButtonIconExample = (): React.Element => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +const ButtonGroupExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + { size: 'EXTRA_SMALL' }, + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'SUCCESS' }, + 'extra small' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'button' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'group' + ) + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + { size: 'SMALL' }, + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'SUCCESS' }, + 'small' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'button' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'group' + ) + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + null, + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'SUCCESS' }, + 'regular' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'button' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'group' + ) + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + { size: 'LARGE' }, + _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: 'SUCCESS' }, + 'large' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'button' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'group' + ) + ) + ) ); -const ButtonToolbarExample = (): React.Element => ( -
- - - - - - - - - - - -
+const ButtonToolbarExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_ButtonToolbar || _load_ButtonToolbar()).ButtonToolbar, + null, + _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + null, + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'ButtonGroup' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'in a' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'toolbar' + ) + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'single buttons' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'in toolbar' + ) + ) + ) ); -export const ButtonExamples = { +const ButtonExamples = exports.ButtonExamples = { sectionName: 'Buttons', description: 'For clicking things.', - examples: [ - { - title: 'Button sizes', - component: ButtonSizeExample, - }, - { - title: 'Disabled/enabled', - component: ButtonDisabledExample, - }, - { - title: 'Button colors', - component: ButtonColorExample, - }, - { - title: 'Buttons with icons', - component: ButtonIconExample, - }, - { - title: 'Button Group', - component: ButtonGroupExample, - }, - { - title: 'Button Toolbar', - component: ButtonToolbarExample, - }, - ], -}; + examples: [{ + title: 'Button sizes', + component: ButtonSizeExample + }, { + title: 'Disabled/enabled', + component: ButtonDisabledExample + }, { + title: 'Button colors', + component: ButtonColorExample + }, { + title: 'Buttons with icons', + component: ButtonIconExample + }, { + title: 'Button Group', + component: ButtonGroupExample + }, { + title: 'Button Toolbar', + component: ButtonToolbarExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Button.js b/modules/nuclide-commons-ui/Button.js index 8fabf8ad..bfc03094 100644 --- a/modules/nuclide-commons-ui/Button.js +++ b/modules/nuclide-commons-ui/Button.js @@ -1,62 +1,66 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Button = exports.ButtonTypes = exports.ButtonSizes = undefined; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _string; + +function _load_string() { + return _string = require('nuclide-commons/string'); +} + +var _addTooltip; + +function _load_addTooltip() { + return _addTooltip = _interopRequireDefault(require('./addTooltip')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -import type {IconName} from './Icon'; - -import classnames from 'classnames'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import {maybeToString} from 'nuclide-commons/string'; -import addTooltip from './addTooltip'; - -export type ButtonType = 'PRIMARY' | 'INFO' | 'SUCCESS' | 'WARNING' | 'ERROR'; -export type ButtonSize = 'EXTRA_SMALL' | 'SMALL' | 'LARGE'; -type ButtonNodeName = 'button' | 'a'; - -type Props = { - /** Icon name, without the `icon-` prefix. E.g. `'arrow-up'` */ - icon?: IconName, - /** Optional specifier for special buttons, e.g. primary, info, success or error buttons. */ - buttonType?: ButtonType, - selected?: boolean, - /** */ - size?: ButtonSize, - className?: string, - /** The button's content; generally a string. */ - children?: mixed, - /** Allows specifying an element other than `button` to be used as the wrapper node. */ - wrapperElement?: ButtonNodeName, - tooltip?: atom$TooltipsAddOptions, - disabled?: boolean, -}; - -export const ButtonSizes = Object.freeze({ +const ButtonSizes = exports.ButtonSizes = Object.freeze({ EXTRA_SMALL: 'EXTRA_SMALL', SMALL: 'SMALL', - LARGE: 'LARGE', + LARGE: 'LARGE' }); -export const ButtonTypes = Object.freeze({ +const ButtonTypes = exports.ButtonTypes = Object.freeze({ PRIMARY: 'PRIMARY', INFO: 'INFO', SUCCESS: 'SUCCESS', WARNING: 'WARNING', - ERROR: 'ERROR', + ERROR: 'ERROR' }); const ButtonSizeClassnames = Object.freeze({ EXTRA_SMALL: 'btn-xs', SMALL: 'btn-sm', - LARGE: 'btn-lg', + LARGE: 'btn-lg' }); const ButtonTypeClassnames = Object.freeze({ @@ -64,15 +68,15 @@ const ButtonTypeClassnames = Object.freeze({ INFO: 'btn-info', SUCCESS: 'btn-success', WARNING: 'btn-warning', - ERROR: 'btn-error', + ERROR: 'btn-error' }); /** * Generic Button wrapper. */ -export class Button extends React.Component { - focus(): void { - const node = ReactDOM.findDOMNode(this); +class Button extends _react.Component { + focus() { + const node = _reactDom.default.findDOMNode(this); if (node == null) { return; } @@ -80,8 +84,9 @@ export class Button extends React.Component { node.focus(); } - render(): React.Node { - const { + render() { + const _props = this.props, + { icon, buttonType, selected, @@ -89,30 +94,32 @@ export class Button extends React.Component { children, className, wrapperElement, - tooltip, - ...remainingProps - } = this.props; + tooltip + } = _props, + remainingProps = _objectWithoutProperties(_props, ['icon', 'buttonType', 'selected', 'size', 'children', 'className', 'wrapperElement', 'tooltip']); const sizeClassname = size == null ? '' : ButtonSizeClassnames[size] || ''; - const buttonTypeClassname = - buttonType == null ? '' : ButtonTypeClassnames[buttonType] || ''; - const ref = tooltip && !this.props.disabled ? addTooltip(tooltip) : null; + const buttonTypeClassname = buttonType == null ? '' : ButtonTypeClassnames[buttonType] || ''; + const ref = tooltip && !this.props.disabled ? (0, (_addTooltip || _load_addTooltip()).default)(tooltip) : null; const titleToolTip = tooltip && this.props.disabled ? tooltip.title : null; - const newClassName = classnames(className, 'btn', { - [`icon icon-${maybeToString(icon)}`]: icon != null, + const newClassName = (0, (_classnames || _load_classnames()).default)(className, 'btn', { + [`icon icon-${(0, (_string || _load_string()).maybeToString)(icon)}`]: icon != null, [sizeClassname]: size != null, selected, - [buttonTypeClassname]: buttonType != null, + [buttonTypeClassname]: buttonType != null }); const Wrapper = wrapperElement == null ? 'button' : wrapperElement; return ( // $FlowFixMe(>=0.53.0) Flow suppress - - {children} - + _react.createElement( + Wrapper, + Object.assign({ + className: newClassName, + ref: ref + }, remainingProps, { + title: titleToolTip }), + children + ) ); } } +exports.Button = Button; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ButtonGroup.js b/modules/nuclide-commons-ui/ButtonGroup.js index a517d226..9aca6a04 100644 --- a/modules/nuclide-commons-ui/ButtonGroup.js +++ b/modules/nuclide-commons-ui/ButtonGroup.js @@ -1,3 +1,22 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ButtonGroup = exports.ButtonGroupSizes = undefined; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,47 +25,37 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import classnames from 'classnames'; -import * as React from 'react'; - -type ButtonGroupSize = 'EXTRA_SMALL' | 'SMALL' | 'LARGE'; - -type Props = { - /** The size of the buttons within the group. Overrides any `size` props on child buttons. */ - size?: ButtonGroupSize, - /** The contents of the ButtonGroup; Generally, an instance of `Button`. */ - children?: mixed, - className?: string, -}; - -export const ButtonGroupSizes = Object.freeze({ +const ButtonGroupSizes = exports.ButtonGroupSizes = Object.freeze({ EXTRA_SMALL: 'EXTRA_SMALL', SMALL: 'SMALL', - LARGE: 'LARGE', + LARGE: 'LARGE' }); const ButtonGroupSizeClassnames = Object.freeze({ EXTRA_SMALL: 'btn-group-xs', SMALL: 'btn-group-sm', - LARGE: 'btn-group-lg', + LARGE: 'btn-group-lg' }); /** * Visually groups Buttons passed in as children. */ -export const ButtonGroup = (props: Props) => { - const {size, children, className} = props; - const sizeClassName = - size == null ? '' : ButtonGroupSizeClassnames[size] || ''; - const newClassName = classnames(className, 'btn-group', 'nuclide-btn-group', { - [sizeClassName]: size != null, +const ButtonGroup = exports.ButtonGroup = props => { + const { size, children, className } = props; + const sizeClassName = size == null ? '' : ButtonGroupSizeClassnames[size] || ''; + const newClassName = (0, (_classnames || _load_classnames()).default)(className, 'btn-group', 'nuclide-btn-group', { + [sizeClassName]: size != null }); return ( // $FlowFixMe(>=0.53.0) Flow suppress -
{children}
+ _react.createElement( + 'div', + { className: newClassName }, + children + ) ); -}; +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ButtonToolbar.js b/modules/nuclide-commons-ui/ButtonToolbar.js index 90785fcf..cc2c1f11 100644 --- a/modules/nuclide-commons-ui/ButtonToolbar.js +++ b/modules/nuclide-commons-ui/ButtonToolbar.js @@ -1,3 +1,25 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ButtonToolbar = undefined; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Visually groups Buttons passed in as children. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,25 +28,18 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import classnames from 'classnames'; -import * as React from 'react'; - -type Props = { - className?: string, - children?: mixed, -}; - -/** - * Visually groups Buttons passed in as children. - */ -export const ButtonToolbar = (props: Props) => { - const {children, className} = props; +const ButtonToolbar = exports.ButtonToolbar = props => { + const { children, className } = props; return ( // $FlowFixMe(>=0.53.0) Flow suppress -
{children}
+ _react.createElement( + 'div', + { className: (0, (_classnames || _load_classnames()).default)('btn-toolbar', className) }, + children + ) ); -}; +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Checkbox.example.js b/modules/nuclide-commons-ui/Checkbox.example.js index 3a26e060..680a9471 100644 --- a/modules/nuclide-commons-ui/Checkbox.example.js +++ b/modules/nuclide-commons-ui/Checkbox.example.js @@ -1,76 +1,101 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import * as React from 'react'; -import {Block} from './Block'; -import {Checkbox} from './Checkbox'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.CheckboxExamples = undefined; -const NOOP = () => {}; +var _react = _interopRequireWildcard(require('react')); -const CheckboxExample = (): React.Element => ( -
- - - - - - - - - - - - - - - -
+var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Checkbox; + +function _load_Checkbox() { + return _Checkbox = require('./Checkbox'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const NOOP = () => {}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const CheckboxExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Checkbox || _load_Checkbox()).Checkbox, { + checked: false, + onClick: NOOP, + onChange: NOOP, + label: 'A Checkbox.' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Checkbox || _load_Checkbox()).Checkbox, { + onClick: NOOP, + onChange: NOOP, + checked: true, + label: 'A checked Checkbox.' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Checkbox || _load_Checkbox()).Checkbox, { + onClick: NOOP, + onChange: NOOP, + disabled: true, + checked: false, + label: 'A disabled Checkbox.' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Checkbox || _load_Checkbox()).Checkbox, { + onClick: NOOP, + onChange: NOOP, + checked: true, + disabled: true, + label: 'A disabled, checked Checkbox.' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Checkbox || _load_Checkbox()).Checkbox, { + onClick: NOOP, + onChange: NOOP, + indeterminate: true, + checked: false, + label: 'An indeterminate Checkbox.' + }) + ) ); -export const CheckboxExamples = { +const CheckboxExamples = exports.CheckboxExamples = { sectionName: 'Checkbox', description: '', - examples: [ - { - title: '', - component: CheckboxExample, - }, - ], -}; + examples: [{ + title: '', + component: CheckboxExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Checkbox.js b/modules/nuclide-commons-ui/Checkbox.js index 3d426d02..3fcf24fc 100644 --- a/modules/nuclide-commons-ui/Checkbox.js +++ b/modules/nuclide-commons-ui/Checkbox.js @@ -1,3 +1,38 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Checkbox = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _addTooltip; + +function _load_addTooltip() { + return _addTooltip = _interopRequireDefault(require('./addTooltip')); +} + +var _ignoreTextSelectionEvents; + +function _load_ignoreTextSelectionEvents() { + return _ignoreTextSelectionEvents = _interopRequireDefault(require('./ignoreTextSelectionEvents')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +/** + * A checkbox component with an input checkbox and a label. We restrict the label to a string + * to ensure this component is pure. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,55 +41,15 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import * as React from 'react'; -import classnames from 'classnames'; -import addTooltip from './addTooltip'; - -import ignoreTextSelectionEvents from './ignoreTextSelectionEvents'; - -type DefaultProps = { - disabled: boolean, - indeterminate: boolean, - label: string, - onClick: (event: SyntheticMouseEvent<>) => mixed, - onMouseDown: (event: SyntheticMouseEvent<>) => mixed, -}; - -type Props = { - className?: string, - checked: boolean, - disabled: boolean, - indeterminate: boolean, - label: string, - onChange: (isChecked: boolean) => mixed, - onClick: (event: SyntheticMouseEvent<>) => mixed, - tooltip?: atom$TooltipsAddOptions, - title?: ?string, - onMouseDown: (event: SyntheticMouseEvent<>) => mixed, -}; +class Checkbox extends _react.PureComponent { -/** - * A checkbox component with an input checkbox and a label. We restrict the label to a string - * to ensure this component is pure. - */ -export class Checkbox extends React.PureComponent { - _input: ?HTMLInputElement; - - static defaultProps: DefaultProps = { - disabled: false, - indeterminate: false, - label: '', - onClick(event) {}, - onMouseDown(event) {}, - }; - - constructor(props: Props) { + constructor(props) { super(props); - (this: any)._onChange = this._onChange.bind(this); + this._onChange = this._onChange.bind(this); } componentDidMount() { @@ -65,8 +60,8 @@ export class Checkbox extends React.PureComponent { this._setIndeterminate(); } - _onChange(event: SyntheticEvent<>) { - const isChecked = ((event.target: any): HTMLInputElement).checked; + _onChange(event) { + const isChecked = event.target.checked; this.props.onChange.call(null, isChecked); } @@ -76,14 +71,14 @@ export class Checkbox extends React.PureComponent { * * @see https://www.w3.org/TR/html5/forms.html#the-input-element */ - _setIndeterminate(): void { + _setIndeterminate() { if (this._input == null) { return; } this._input.indeterminate = this.props.indeterminate; } - render(): React.Node { + render() { const { checked, className, @@ -94,35 +89,45 @@ export class Checkbox extends React.PureComponent { onClick, tooltip, title, - onMouseDown, + onMouseDown } = this.props; - const ref = tooltip ? addTooltip(tooltip) : null; - const text = - label === '' ? null : ( - {label} - ); - return ( - + const ref = tooltip ? (0, (_addTooltip || _load_addTooltip()).default)(tooltip) : null; + const text = label === '' ? null : _react.createElement( + 'span', + { className: 'nuclide-ui-checkbox-label-text' }, + ' ', + label + ); + return _react.createElement( + 'label', + { + className: (0, (_classnames || _load_classnames()).default)(className, 'nuclide-ui-checkbox-label', { + 'nuclide-ui-checkbox-disabled': disabled + }), + ref: ref, + onClick: onClick && (0, (_ignoreTextSelectionEvents || _load_ignoreTextSelectionEvents()).default)(onClick), + title: title }, + _react.createElement('input', { + checked: checked, + className: 'input-checkbox nuclide-ui-checkbox', + disabled: disabled, + onChange: this._onChange, + onMouseDown: onMouseDown, + ref: el => { + this._input = el; + }, + type: 'checkbox' + }), + text ); } } +exports.Checkbox = Checkbox; +Checkbox.defaultProps = { + disabled: false, + indeterminate: false, + label: '', + onClick(event) {}, + onMouseDown(event) {} +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ClickOutsideBoundary.js b/modules/nuclide-commons-ui/ClickOutsideBoundary.js index 770e8a12..b7d4bdec 100644 --- a/modules/nuclide-commons-ui/ClickOutsideBoundary.js +++ b/modules/nuclide-commons-ui/ClickOutsideBoundary.js @@ -1,35 +1,58 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import * as React from 'react'; -import {findDOMNode} from 'react-dom'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -type Props = { - onClickOutside: ?() => mixed, - children: ?React.Element, -}; +var _react = _interopRequireWildcard(require('react')); -export default class ClickOutsideBoundary extends React.Component { - _lastInternalEvent: ?MouseEvent; - _node: null | Element | Text; +var _reactDom = require('react-dom'); - constructor(props: Props) { +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class ClickOutsideBoundary extends _react.Component { + + constructor(props) { super(props); + + this._handleDocumentClick = e => { + // A more straight-forward approach would be to use + // `this._node.contains(e.target)`, however that fails in the edge case were + // some other event handler causes the target to be removed from the DOM + // before the event reaches the document root. So instead, we use this + // reference comparison approach which works for all cases where an event + // passed trough the boundary node, and makes it all the way to the document + // root. + if (e !== this._lastInternalEvent) { + if (this.props.onClickOutside != null) { + this.props.onClickOutside(); + } + } + this._lastInternalEvent = null; + }; + + this._handleInternalClick = e => { + this._lastInternalEvent = e; + }; + this._lastInternalEvent = null; this._node = null; } componentDidMount() { - const node = (this._node = findDOMNode(this)); + const node = this._node = (0, _reactDom.findDOMNode)(this); if (node == null) { return; } @@ -41,26 +64,6 @@ export default class ClickOutsideBoundary extends React.Component { node.addEventListener('click', this._handleInternalClick); } - _handleDocumentClick = (e: MouseEvent) => { - // A more straight-forward approach would be to use - // `this._node.contains(e.target)`, however that fails in the edge case were - // some other event handler causes the target to be removed from the DOM - // before the event reaches the document root. So instead, we use this - // reference comparison approach which works for all cases where an event - // passed trough the boundary node, and makes it all the way to the document - // root. - if (e !== this._lastInternalEvent) { - if (this.props.onClickOutside != null) { - this.props.onClickOutside(); - } - } - this._lastInternalEvent = null; - }; - - _handleInternalClick = (e: MouseEvent) => { - this._lastInternalEvent = e; - }; - componentWillUnmount() { window.document.removeEventListener('click', this._handleDocumentClick); if (this._node != null) { @@ -69,7 +72,10 @@ export default class ClickOutsideBoundary extends React.Component { } render() { - const {onClickOutside, ...passThroughProps} = this.props; - return
; + const _props = this.props, + { onClickOutside } = _props, + passThroughProps = _objectWithoutProperties(_props, ['onClickOutside']); + return _react.createElement('div', passThroughProps); } } +exports.default = ClickOutsideBoundary; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/CodeSnippet.js b/modules/nuclide-commons-ui/CodeSnippet.js index 53d3e850..8cc9e695 100644 --- a/modules/nuclide-commons-ui/CodeSnippet.js +++ b/modules/nuclide-commons-ui/CodeSnippet.js @@ -1,3 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.CodeSnippet = undefined; + +var _AtomInput; + +function _load_AtomInput() { + return _AtomInput = require('./AtomInput'); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,31 +23,19 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import {AtomInput} from './AtomInput'; -import invariant from 'assert'; -import * as React from 'react'; - -type Props = { - text: string, - grammar?: atom$Grammar, - highlights?: Array, - startLine: number, - endLine: number, - onClick: (event: SyntheticMouseEvent<>) => mixed, - onLineClick: (event: SyntheticMouseEvent<>, line: number) => mixed, -}; - -export class CodeSnippet extends React.Component { - _editor: ?AtomInput; +class CodeSnippet extends _react.Component { componentDidMount() { - invariant(this._editor != null); + if (!(this._editor != null)) { + throw new Error('Invariant violation: "this._editor != null"'); + } + const editor = this._editor.getTextEditor(); - const {grammar, highlights, startLine} = this.props; + const { grammar, highlights, startLine } = this.props; if (grammar) { editor.setGrammar(grammar); @@ -38,52 +43,49 @@ export class CodeSnippet extends React.Component { if (highlights != null) { highlights.forEach(range => { - const marker = editor.markBufferRange([ - [range.start.row - startLine, range.start.column], - [range.end.row - startLine, range.end.column], - ]); + const marker = editor.markBufferRange([[range.start.row - startLine, range.start.column], [range.end.row - startLine, range.end.column]]); editor.decorateMarker(marker, { type: 'highlight', - class: 'code-snippet-highlight', + class: 'code-snippet-highlight' }); }); // Make sure at least one highlight is visible. if (highlights.length > 0) { - editor.scrollToBufferPosition([ - highlights[0].end.row - startLine + 1, - highlights[0].end.column, - ]); + editor.scrollToBufferPosition([highlights[0].end.row - startLine + 1, highlights[0].end.column]); } } } - render(): React.Node { + render() { const lineNumbers = []; for (let i = this.props.startLine; i <= this.props.endLine; i++) { - lineNumbers.push( -
this.props.onLineClick(evt, i)}> - {i + 1} -
, - ); + lineNumbers.push(_react.createElement( + 'div', + { + key: i, + className: 'nuclide-ui-code-snippet-line-number', + onClick: evt => this.props.onLineClick(evt, i) }, + i + 1 + )); } - return ( -
-
- {lineNumbers} -
- { - this._editor = input; - }} - initialValue={this.props.text} - disabled={true} - onClick={this.props.onClick} - /> -
+ return _react.createElement( + 'div', + { className: 'nuclide-ui-code-snippet' }, + _react.createElement( + 'div', + { className: 'nuclide-ui-code-snippet-line-number-column' }, + lineNumbers + ), + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + ref: input => { + this._editor = input; + }, + initialValue: this.props.text, + disabled: true, + onClick: this.props.onClick + }) ); } } +exports.CodeSnippet = CodeSnippet; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/EmptyState.js b/modules/nuclide-commons-ui/EmptyState.js index 6273290f..92637f64 100644 --- a/modules/nuclide-commons-ui/EmptyState.js +++ b/modules/nuclide-commons-ui/EmptyState.js @@ -1,31 +1,40 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +"use strict"; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.EmptyState = undefined; -type Props = { - title: string, - message: React$Node, -}; +var _react = _interopRequireWildcard(require("react")); -export class EmptyState extends React.Component { - render(): React.Node { - return ( -
-
-

{this.props.title}

- {this.props.message} -
-
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +class EmptyState extends _react.Component { + render() { + return _react.createElement( + "div", + { className: "nuclide-ui-empty-state-container" }, + _react.createElement( + "div", + { className: "nuclide-ui-empty-state-message" }, + _react.createElement( + "h1", + null, + this.props.title + ), + this.props.message + ) ); } } +exports.EmptyState = EmptyState; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/HR.js b/modules/nuclide-commons-ui/HR.js index 9a3a929a..d0174eaa 100644 --- a/modules/nuclide-commons-ui/HR.js +++ b/modules/nuclide-commons-ui/HR.js @@ -1,15 +1,22 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import * as React from 'react'; - -export const HR = () =>
; +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.HR = undefined; + +var _react = _interopRequireWildcard(require("react")); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const HR = exports.HR = () => _react.createElement("hr", { className: "nuclide-ui-hr" }); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Highlight.example.js b/modules/nuclide-commons-ui/Highlight.example.js index 1a62f608..f1443aef 100644 --- a/modules/nuclide-commons-ui/Highlight.example.js +++ b/modules/nuclide-commons-ui/Highlight.example.js @@ -1,47 +1,91 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import * as React from 'react'; -import {Block} from './Block'; -import {Highlight, HighlightColors} from './Highlight'; - -const HighlightExample = (): React.Element => ( -
- - Default - - - Info - - - Success - - - Warning - - - Error - -
-); - -export const HighlightExamples = { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.HighlightExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Highlight; + +function _load_Highlight() { + return _Highlight = require('./Highlight'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const HighlightExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Highlight || _load_Highlight()).Highlight, + null, + 'Default' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Highlight || _load_Highlight()).Highlight, + { color: (_Highlight || _load_Highlight()).HighlightColors.info }, + 'Info' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Highlight || _load_Highlight()).Highlight, + { color: (_Highlight || _load_Highlight()).HighlightColors.success }, + 'Success' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Highlight || _load_Highlight()).Highlight, + { color: (_Highlight || _load_Highlight()).HighlightColors.warning }, + 'Warning' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Highlight || _load_Highlight()).Highlight, + { color: (_Highlight || _load_Highlight()).HighlightColors.error }, + 'Error' + ) + ) +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const HighlightExamples = exports.HighlightExamples = { sectionName: 'Highlight', - description: - 'Highlights are useful for calling out inline content, such as tags.', - examples: [ - { - title: 'Highlights', - component: HighlightExample, - }, - ], -}; + description: 'Highlights are useful for calling out inline content, such as tags.', + examples: [{ + title: 'Highlights', + component: HighlightExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Highlight.js b/modules/nuclide-commons-ui/Highlight.js index 76b9db67..9447de86 100644 --- a/modules/nuclide-commons-ui/Highlight.js +++ b/modules/nuclide-commons-ui/Highlight.js @@ -1,37 +1,40 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import classnames from 'classnames'; -import * as React from 'react'; - -export type HighlightColor = - | 'default' - | 'info' - | 'success' - | 'warning' - | 'error'; - -type Props = { - className?: string, - color?: HighlightColor, - children: React.Node, -}; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Highlight = exports.HighlightColors = undefined; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -export const HighlightColors = Object.freeze({ +const HighlightColors = exports.HighlightColors = Object.freeze({ default: 'default', info: 'info', success: 'success', warning: 'warning', - error: 'error', + error: 'error' }); const HighlightColorClassNames = Object.freeze({ @@ -39,17 +42,18 @@ const HighlightColorClassNames = Object.freeze({ info: 'highlight-info', success: 'highlight-success', warning: 'highlight-warning', - error: 'highlight-error', + error: 'highlight-error' }); -export const Highlight = (props: Props) => { - const {className, color, children, ...remainingProps} = props; - const colorClassName = - HighlightColorClassNames[color == null ? 'default' : color]; - const newClassName = classnames(colorClassName, className); - return ( - - {children} - +const Highlight = props => { + const { className, color, children } = props, + remainingProps = _objectWithoutProperties(props, ['className', 'color', 'children']); + const colorClassName = HighlightColorClassNames[color == null ? 'default' : color]; + const newClassName = (0, (_classnames || _load_classnames()).default)(colorClassName, className); + return _react.createElement( + 'span', + Object.assign({ className: newClassName }, remainingProps), + children ); }; +exports.Highlight = Highlight; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/HighlightedText.js b/modules/nuclide-commons-ui/HighlightedText.js index 309dc299..fa9bc1a7 100644 --- a/modules/nuclide-commons-ui/HighlightedText.js +++ b/modules/nuclide-commons-ui/HighlightedText.js @@ -1,3 +1,19 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,44 +22,20 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import * as React from 'react'; -import invariant from 'assert'; -import {arrayEqual} from 'nuclide-commons/collection'; - -export type TextRange = [/* start */ number, /* end */ number]; -type Props = {| - className?: ?string, - /* - * A list of ranges of the text string (pairs of indexes, inclusive lower - * bound, exclusive upper bound -- just like .slice()) that should be - * highlighted - */ - highlightedRanges: Array, - style?: ?Object, - text: string, -|}; - -export default class HighlightedText extends React.Component { - shouldComponentUpdate(nextProps: Props) { - return ( - this.props.text !== nextProps.text || - !arrayEqual( - this.props.highlightedRanges, - nextProps.highlightedRanges, - rangeEqual, - ) - ); +class HighlightedText extends _react.Component { + shouldComponentUpdate(nextProps) { + return this.props.text !== nextProps.text || !(0, (_collection || _load_collection()).arrayEqual)(this.props.highlightedRanges, nextProps.highlightedRanges, rangeEqual); } - render(): React.Element { - const {className, highlightedRanges, style, text} = this.props; + render() { + const { className, highlightedRanges, style, text } = this.props; // generate counterpart unhighlightedRanges for the highlightedRanges - const unhighlightedRanges: Array = []; + const unhighlightedRanges = []; for (let i = 0; i < highlightedRanges.length; i++) { const lastHighlighted = highlightedRanges[i - 1]; const currentHighlighted = highlightedRanges[i]; @@ -59,11 +51,10 @@ export default class HighlightedText extends React.Component { } if ( - // if the last matched range - i === highlightedRanges.length - 1 && - // doesn't end perfectly at the end of the text, - currentHighlighted[1] !== text.length - ) { + // if the last matched range + i === highlightedRanges.length - 1 && + // doesn't end perfectly at the end of the text, + currentHighlighted[1] !== text.length) { // add an additional unmatched range to cover the rest of the text unhighlightedRanges.push([currentHighlighted[1], text.length]); } @@ -73,66 +64,55 @@ export default class HighlightedText extends React.Component { unhighlightedRanges.push([0, text.length]); } - invariant( - unhighlightedRanges.length === highlightedRanges.length || - unhighlightedRanges.length === highlightedRanges.length + 1, - ); - const renderedSequences: Array> = []; + if (!(unhighlightedRanges.length === highlightedRanges.length || unhighlightedRanges.length === highlightedRanges.length + 1)) { + throw new Error('Invariant violation: "unhighlightedRanges.length === highlightedRanges.length ||\\n unhighlightedRanges.length === highlightedRanges.length + 1"'); + } + + const renderedSequences = []; for (let i = 0; i < unhighlightedRanges.length; i++) { const unhighlightedRange = unhighlightedRanges[i]; const highlightedRange = highlightedRanges[i]; if (!rangeEmpty(unhighlightedRange)) { - renderedSequences.push( - renderUnmatchedSubsequence( - text.slice(unhighlightedRange[0], unhighlightedRange[1]), - unhighlightedRange.join(','), - ), - ); + renderedSequences.push(renderUnmatchedSubsequence(text.slice(unhighlightedRange[0], unhighlightedRange[1]), unhighlightedRange.join(','))); } if (highlightedRange != null && !rangeEmpty(highlightedRange)) { - renderedSequences.push( - renderMatchedSubsequence( - text.slice(highlightedRange[0], highlightedRange[1]), - highlightedRange.join(','), - ), - ); + renderedSequences.push(renderMatchedSubsequence(text.slice(highlightedRange[0], highlightedRange[1]), highlightedRange.join(','))); } } - return ( - - {renderedSequences} - + return _react.createElement( + 'span', + { className: className, style: style }, + renderedSequences ); } } -function renderSubsequence(seq: string, props: Object): React.Element { - return {seq}; +exports.default = HighlightedText; +function renderSubsequence(seq, props) { + return _react.createElement( + 'span', + props, + seq + ); } -function renderUnmatchedSubsequence( - seq: string, - key: number | string, -): React.Element { - return renderSubsequence(seq, {key}); +function renderUnmatchedSubsequence(seq, key) { + return renderSubsequence(seq, { key }); } -function renderMatchedSubsequence( - seq: string, - key: number | string, -): React.Element { +function renderMatchedSubsequence(seq, key) { return renderSubsequence(seq, { key, - className: 'nuclide-match-highlighted-text-match', + className: 'nuclide-match-highlighted-text-match' }); } -function rangeEqual(a: TextRange, b: TextRange): boolean { +function rangeEqual(a, b) { return a[0] === b[0] && a[1] === b[1]; } -function rangeEmpty(range: TextRange): boolean { +function rangeEmpty(range) { return range[0] === range[1]; -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Icon.example.js b/modules/nuclide-commons-ui/Icon.example.js index 5ec2d3a5..d4b01179 100644 --- a/modules/nuclide-commons-ui/Icon.example.js +++ b/modules/nuclide-commons-ui/Icon.example.js @@ -1,56 +1,92 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import * as React from 'react'; -import {Block} from './Block'; -import {Icon} from './Icon'; - -const IconExample = (): React.Element => ( -
- - - - - -
-); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.IconExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Icon; + +function _load_Icon() { + return _Icon = require('./Icon'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const IconExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Icon || _load_Icon()).Icon, { icon: 'gift' }), + _react.createElement((_Icon || _load_Icon()).Icon, { icon: 'heart' }), + _react.createElement((_Icon || _load_Icon()).Icon, { icon: 'info' }) + ) +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -const IconWithTextExample = (): React.Element => ( -
- -
- gift -
-
- heart -
-
- info -
-
-
+const IconWithTextExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + 'div', + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'gift' }, + 'gift' + ) + ), + _react.createElement( + 'div', + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'heart' }, + 'heart' + ) + ), + _react.createElement( + 'div', + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'info' }, + 'info' + ) + ) + ) ); -export const IconExamples = { +const IconExamples = exports.IconExamples = { sectionName: 'Icons', description: 'Octicons with optional text.', - examples: [ - { - title: 'Icons', - component: IconExample, - }, - { - title: 'You can pass optional text as children.', - component: IconWithTextExample, - }, - ], -}; + examples: [{ + title: 'Icons', + component: IconExample + }, { + title: 'You can pass optional text as children.', + component: IconWithTextExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Icon.js b/modules/nuclide-commons-ui/Icon.js index 13d27da5..7d4a3376 100644 --- a/modules/nuclide-commons-ui/Icon.js +++ b/modules/nuclide-commons-ui/Icon.js @@ -1,82 +1,45 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import classnames from 'classnames'; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Icon = undefined; -export type Nuclicon = - | 'nuclicon-nuclide' - | 'nuclicon-react' - | 'nuclicon-buck' - | 'nuclicon-hhvm' - | 'nuclicon-hack' - | 'nuclicon-relay' - | 'nuclicon-swift' - | 'nuclicon-file-directory' - | 'nuclicon-file-directory-starred' - | 'nuclicon-debugger' - | 'nuclicon-arrow-down' - | 'nuclicon-bug' - | 'nuclicon-graphql' - | 'nuclicon-comment-discussion' - | 'nuclicon-comment' - | 'nuclicon-jest-outline' - | 'nuclicon-flow' - | 'nuclicon-react-devtools' - | 'nuclicon-funnel' - | 'nuclicon-error' - // Currently, "nuclicon-warning" is the same as Octicon's "alert" but we duplicate it because the - // Octicons aren't vertically centered and the fact that this one's frequently shown next to - // nuclicon-error makes it wayyyy more obvious. - | 'nuclicon-warning' - | 'nuclicon-kebab-horizontal' - | 'nuclicon-cs' - | 'nuclicon-metro' - | 'nuclicon-connected' - | 'nuclicon-disconnected' - | 'nuclicon-eject' - | 'nuclicon-all-items' - | 'nuclicon-local' - | 'nuclicon-remote' - | 'nuclicon-config' - | 'nuclicon-snapshot' - | 'nuclicon-success' - | 'nuclicon-time-start' - | 'nuclicon-time-end' - | 'nuclicon-metro-disabled' - | 'nuclicon-metro-waiting'; +var _classnames; -export type IconName = Nuclicon | atom$Octicon; +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} -type Props = { - /** Icon name, without the `icon-` prefix. E.g. `'arrow-up'` */ - icon: IconName, - className?: string, - /** Optional text content to render next to the icon. */ - children?: React.Node, -}; +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ /** * Renders an icon with optional text next to it. */ -export const Icon = (props: Props) => { - const {icon, children, className, ...remainingProps} = props; - const newClassName = classnames( - className, - icon == null ? null : `icon icon-${icon}`, - ); - return ( - - {children} - +const Icon = props => { + const { icon, children, className } = props, + remainingProps = _objectWithoutProperties(props, ['icon', 'children', 'className']); + const newClassName = (0, (_classnames || _load_classnames()).default)(className, icon == null ? null : `icon icon-${icon}`); + return _react.createElement( + 'span', + Object.assign({ className: newClassName }, remainingProps), + children ); }; +exports.Icon = Icon; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Keybinding.js b/modules/nuclide-commons-ui/Keybinding.js index ecb7d8e0..bfa1f233 100644 --- a/modules/nuclide-commons-ui/Keybinding.js +++ b/modules/nuclide-commons-ui/Keybinding.js @@ -1,3 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = Keybinding; + +var _react = _interopRequireDefault(require('react')); + +var _humanizeKeystroke; + +function _load_humanizeKeystroke() { + return _humanizeKeystroke = _interopRequireDefault(require('nuclide-commons/humanizeKeystroke')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,21 +23,14 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import React from 'react'; -import humanizeKeystroke from 'nuclide-commons/humanizeKeystroke'; - -type Props = {| - keystrokes: string, -|}; - -export default function Keybinding({keystrokes}: Props) { - return ( - - {humanizeKeystroke(keystrokes, process.platform)} - +function Keybinding({ keystrokes }) { + return _react.default.createElement( + 'kbd', + { className: 'key-binding' }, + (0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)(keystrokes, process.platform) ); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/LazyNestedValueComponent.js b/modules/nuclide-commons-ui/LazyNestedValueComponent.js index 20d0641e..dec9cea2 100644 --- a/modules/nuclide-commons-ui/LazyNestedValueComponent.js +++ b/modules/nuclide-commons-ui/LazyNestedValueComponent.js @@ -1,3 +1,82 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.LazyNestedValueComponent = undefined; + +var _AtomInput; + +function _load_AtomInput() { + return _AtomInput = require('./AtomInput'); +} + +var _Icon; + +function _load_Icon() { + return _Icon = require('./Icon'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _bindObservableAsProps; + +function _load_bindObservableAsProps() { + return _bindObservableAsProps = require('./bindObservableAsProps'); +} + +var _analytics; + +function _load_analytics() { + return _analytics = _interopRequireDefault(require('nuclide-commons-atom/analytics')); +} + +var _highlightOnUpdate; + +function _load_highlightOnUpdate() { + return _highlightOnUpdate = require('./highlightOnUpdate'); +} + +var _SimpleValueComponent; + +function _load_SimpleValueComponent() { + return _SimpleValueComponent = require('./SimpleValueComponent'); +} + +var _ValueComponentClassNames; + +function _load_ValueComponentClassNames() { + return _ValueComponentClassNames = require('./ValueComponentClassNames'); +} + +var _Tree; + +function _load_Tree() { + return _Tree = require('./Tree'); +} + +var _LoadingSpinner; + +function _load_LoadingSpinner() { + return _LoadingSpinner = require('./LoadingSpinner'); +} + +var _ignoreTextSelectionEvents; + +function _load_ignoreTextSelectionEvents() { + return _ignoreTextSelectionEvents = _interopRequireDefault(require('./ignoreTextSelectionEvents')); +} + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,68 +85,34 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ // TODO @jxg export debugger typedefs from main module. (t11406963) -import type {EvaluationResult} from './TextRenderer'; -import type {Observable} from 'rxjs'; - -import {AtomInput} from './AtomInput'; -import {Icon} from './Icon'; -import * as React from 'react'; -import invariant from 'assert'; -import {bindObservableAsProps} from './bindObservableAsProps'; -import analytics from 'nuclide-commons-atom/analytics'; -import {highlightOnUpdate} from './highlightOnUpdate'; -import {STRING_REGEX} from './SimpleValueComponent'; -import {ValueComponentClassNames} from './ValueComponentClassNames'; -import {TreeList, TreeItem, NestedTreeItem} from './Tree'; -import {LoadingSpinner} from './LoadingSpinner'; -import ignoreTextSelectionEvents from './ignoreTextSelectionEvents'; -import classnames from 'classnames'; - -export type ExpansionResult = Array<{ - name: string, - value: EvaluationResult, -}>; - -const {track} = analytics; +const { track } = (_analytics || _load_analytics()).default; const EDIT_VALUE_FROM_ICON = 'edit-value-from-icon'; const NOT_AVAILABLE_MESSAGE = ''; const SPINNER_DELAY = 100; /* ms */ -function isObjectValue(result: EvaluationResult): boolean { +function isObjectValue(result) { return result.objectId != null; } -function TreeItemWithLoadingSpinner(): React.Element { - return ( - - - +function TreeItemWithLoadingSpinner() { + return _react.createElement( + (_Tree || _load_Tree()).TreeItem, + { className: 'nuclide-ui-lazy-nested-value-spinner' }, + _react.createElement((_LoadingSpinner || _load_LoadingSpinner()).LoadingSpinner, { size: 'EXTRA_SMALL', delay: SPINNER_DELAY }) ); } -type LoadableValueComponentProps = { - children?: ExpansionResult, - fetchChildren: ?(objectId: string) => Observable, - path: string, - expandedValuePaths: Map, - onExpandedStateChange: (path: string, isExpanded: boolean) => void, - simpleValueComponent: React.ComponentType, - shouldCacheChildren: boolean, - getCachedChildren: (path: string) => ?ExpansionResult, - setCachedChildren: (path: string, children: ExpansionResult) => void, -}; - /** * A wrapper that renders a (delayed) spinner while the list of child properties is being loaded. * Otherwise, it renders ValueComponent for each property in `children`. */ -const LoadableValueComponent = (props: LoadableValueComponentProps) => { +const LoadableValueComponent = props => { const { children, fetchChildren, @@ -77,7 +122,7 @@ const LoadableValueComponent = (props: LoadableValueComponentProps) => { simpleValueComponent, shouldCacheChildren, getCachedChildren, - setCachedChildren, + setCachedChildren } = props; if (children == null) { return TreeItemWithLoadingSpinner(); @@ -85,127 +130,102 @@ const LoadableValueComponent = (props: LoadableValueComponentProps) => { if (shouldCacheChildren) { setCachedChildren(path, children); } - return ( - - {children.map(child => ( - - - - ))} - + return _react.createElement( + 'span', + null, + children.map(child => _react.createElement( + (_Tree || _load_Tree()).TreeItem, + { key: child.name }, + _react.createElement(ValueComponent, { + evaluationResult: child.value, + fetchChildren: fetchChildren, + expression: child.name, + expandedValuePaths: expandedValuePaths, + onExpandedStateChange: onExpandedStateChange, + path: path + '.' + child.name, + simpleValueComponent: simpleValueComponent, + shouldCacheChildren: shouldCacheChildren, + getCachedChildren: getCachedChildren, + setCachedChildren: setCachedChildren + }) + )) ); }; // TODO allow passing action components (edit button, pin button) here -function renderValueLine( - expression: React.Element | ?string, - value: React.Element | string, -): React.Element { +function renderValueLine(expression, value) { if (expression == null) { - return ( -
{value}
+ return _react.createElement( + 'div', + { className: 'nuclide-ui-lazy-nested-value-container' }, + value ); } else { // TODO @jxg use a text editor to apply proper syntax highlighting for expressions (t11408154) - return ( -
- - {expression} - - : {value} -
+ return _react.createElement( + 'div', + { className: 'nuclide-ui-lazy-nested-value-container' }, + _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.identifier }, + expression + ), + ': ', + value ); } } -type LazyNestedValueComponentProps = { - evaluationResult: ?EvaluationResult, - fetchChildren: ?(objectId: string) => Observable, - setVariable?: ?(expression: ?string, newValue: ?string) => void, - expression: ?string, - isRoot?: boolean, - expandedValuePaths: Map, - onExpandedStateChange: (path: string, expanded: boolean) => void, - path: string, - simpleValueComponent: React.ComponentType, - shouldCacheChildren: boolean, - getCachedChildren: (path: string) => ?ExpansionResult, - setCachedChildren: (path: string, children: ExpansionResult) => void, -}; - -type LazyNestedValueComponentState = { - isExpanded: boolean, - children: ?Observable, - isBeingEdited: boolean, - newValueForExpression: ?string, -}; - /** * A component that knows how to render recursive, interactive expression/evaluationResult pairs. * The rendering of non-expandable "leaf" values is delegated to the SimpleValueComponent. */ -class ValueComponent extends React.Component< - LazyNestedValueComponentProps, - LazyNestedValueComponentState, -> { - _toggleExpandFiltered: (e: SyntheticMouseEvent<>) => void; +class ValueComponent extends _react.Component { - constructor(props: LazyNestedValueComponentProps) { + constructor(props) { super(props); + + this._showSetVariableDisplay = () => { + const { isRoot, setVariable } = this.props; + if (isRoot && setVariable) { + this.setState({ isBeingEdited: true }); + } + }; + + this._hideSetVariableDisplay = () => { + this.setState({ + isBeingEdited: false, + newValueForExpression: null + }); + }; + + this._setVariable = () => { + const { setVariable, expression } = this.props; + if (setVariable) { + setVariable(expression, this.state.newValueForExpression); + this.setState({ isBeingEdited: false }); + } + }; + this.state = { isExpanded: false, children: null, isBeingEdited: false, - newValueForExpression: null, + newValueForExpression: null }; - (this: any)._toggleExpandFiltered = ignoreTextSelectionEvents( - this._toggleExpand.bind(this), - ); + this._toggleExpandFiltered = (0, (_ignoreTextSelectionEvents || _load_ignoreTextSelectionEvents()).default)(this._toggleExpand.bind(this)); } - _showSetVariableDisplay = (): void => { - const {isRoot, setVariable} = this.props; - if (isRoot && setVariable) { - this.setState({isBeingEdited: true}); - } - }; - - _hideSetVariableDisplay = (): void => { - this.setState({ - isBeingEdited: false, - newValueForExpression: null, - }); - }; - - _setVariable = (): void => { - const {setVariable, expression} = this.props; - if (setVariable) { - setVariable(expression, this.state.newValueForExpression); - this.setState({isBeingEdited: false}); - } - }; - - componentDidMount(): void { + componentDidMount() { this.setState(this._getNextState(this.props)); } - componentWillReceiveProps(nextProps: LazyNestedValueComponentProps): void { + componentWillReceiveProps(nextProps) { this.setState(this._getNextState(nextProps)); } - _toggleExpand(event: SyntheticMouseEvent<>): void { - const {onExpandedStateChange, path} = this.props; + _toggleExpand(event) { + const { onExpandedStateChange, path } = this.props; const newState = this._getNextState(this.props, true /* toggleExpansion */); onExpandedStateChange(path, newState.isExpanded); this.setState(newState); @@ -230,11 +250,8 @@ class ValueComponent extends React.Component< * the new value of isExpanded, children is set appropriately * (see shouldFetchChildren()). */ - _getNextState( - props: LazyNestedValueComponentProps, - toggleExpansion?: boolean, - ): LazyNestedValueComponentState { - const {evaluationResult, expandedValuePaths, fetchChildren, path} = props; + _getNextState(props, toggleExpansion) { + const { evaluationResult, expandedValuePaths, fetchChildren, path } = props; let isExpanded = false; let children = null; // The value of isExpanded is taken from its cached value in nodeData @@ -248,9 +265,18 @@ class ValueComponent extends React.Component< // Children are loaded if the component will be expanded // and other conditions (see shouldFetchChildren()) are true if (isExpanded && shouldFetchChildren(props)) { - invariant(fetchChildren != null); - invariant(evaluationResult != null); - invariant(evaluationResult.objectId != null); + if (!(fetchChildren != null)) { + throw new Error('Invariant violation: "fetchChildren != null"'); + } + + if (!(evaluationResult != null)) { + throw new Error('Invariant violation: "evaluationResult != null"'); + } + + if (!(evaluationResult.objectId != null)) { + throw new Error('Invariant violation: "evaluationResult.objectId != null"'); + } + children = fetchChildren(evaluationResult.objectId); } @@ -258,19 +284,14 @@ class ValueComponent extends React.Component< isExpanded, children, isBeingEdited: false, - newValueForExpression: null, + newValueForExpression: null }; } - _getStringRepresentationForEvaluationResult( - evaluationResult: ?EvaluationResult, - ): string { + _getStringRepresentationForEvaluationResult(evaluationResult) { if (evaluationResult) { if (evaluationResult.value != null) { - if ( - evaluationResult.type === 'string' && - !STRING_REGEX.test(evaluationResult.value) - ) { + if (evaluationResult.type === 'string' && !(_SimpleValueComponent || _load_SimpleValueComponent()).STRING_REGEX.test(evaluationResult.value)) { return '"' + evaluationResult.value + '"'; } else { return evaluationResult.value; @@ -282,45 +303,43 @@ class ValueComponent extends React.Component< return ''; } - _renderEditView(): React.Element { - return ( -
- { - this.setState({newValueForExpression}); - }} - onConfirm={this._setVariable} - onCancel={this._hideSetVariableDisplay} - onBlur={this._hideSetVariableDisplay} - /> -
+ _renderEditView() { + return _react.createElement( + 'div', + { className: 'nuclide-ui-lazy-nested-value-container' }, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + className: 'nuclide-debugger-watch-expression-input', + size: 'sm', + autofocus: true, + startSelected: true, + initialValue: this._getStringRepresentationForEvaluationResult(this.props.evaluationResult), + onDidChange: newValueForExpression => { + this.setState({ newValueForExpression }); + }, + onConfirm: this._setVariable, + onCancel: this._hideSetVariableDisplay, + onBlur: this._hideSetVariableDisplay + }) ); } - _renderEditableScopeView(): ?React.Element { - const {isRoot, setVariable} = this.props; - return isRoot && setVariable && !this.state.isBeingEdited ? ( -
- { - track(EDIT_VALUE_FROM_ICON); - this._showSetVariableDisplay(); - }} - /> -
+ _renderEditableScopeView() { + const { isRoot, setVariable } = this.props; + return isRoot && setVariable && !this.state.isBeingEdited ? _react.createElement( + 'div', + { className: 'nuclide-debugger-scopes-view-controls' }, + _react.createElement((_Icon || _load_Icon()).Icon, { + icon: 'pencil', + className: 'nuclide-debugger-scopes-view-edit-control', + onClick: _ => { + track(EDIT_VALUE_FROM_ICON); + this._showSetVariableDisplay(); + } + }) ) : null; } - render(): React.Node { + render() { const { evaluationResult, expression, @@ -332,135 +351,96 @@ class ValueComponent extends React.Component< shouldCacheChildren, getCachedChildren, setCachedChildren, - simpleValueComponent: SimpleValueComponent, + simpleValueComponent: SimpleValueComponent } = this.props; if (evaluationResult == null) { return renderValueLine(expression, NOT_AVAILABLE_MESSAGE); } if (!isObjectValue(evaluationResult)) { - const simpleValueElement = this.state.isBeingEdited ? ( - this._renderEditView() - ) : ( -
- - {this._renderEditableScopeView()} -
+ const simpleValueElement = this.state.isBeingEdited ? this._renderEditView() : _react.createElement( + 'div', + { onDoubleClick: this._showSetVariableDisplay }, + _react.createElement(SimpleValueComponent, { + expression: expression, + evaluationResult: evaluationResult, + simpleValueComponent: SimpleValueComponent + }), + this._renderEditableScopeView() ); - return isRoot ? ( + return isRoot ? simpleValueElement : _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, simpleValueElement - ) : ( - {simpleValueElement} ); } const description = - // flowlint-next-line sketchy-null-string:off - evaluationResult.description || ''; - const {children, isExpanded} = this.state; + // flowlint-next-line sketchy-null-string:off + evaluationResult.description || ''; + const { children, isExpanded } = this.state; let childListElement = null; if (isExpanded) { const cachedChildren = getCachedChildren(path); if (shouldCacheChildren && cachedChildren != null) { - childListElement = ( - - ); + childListElement = _react.createElement(LoadableValueComponent, { + children: cachedChildren, + fetchChildren: fetchChildren, + path: path, + expandedValuePaths: expandedValuePaths, + onExpandedStateChange: onExpandedStateChange, + simpleValueComponent: SimpleValueComponent, + shouldCacheChildren: shouldCacheChildren, + getCachedChildren: getCachedChildren, + setCachedChildren: setCachedChildren + }); } else if (children == null) { - childListElement = ; + childListElement = _react.createElement(TreeItemWithLoadingSpinner, null); } else { - const ChildrenComponent = bindObservableAsProps( - children - .map(childrenValue => ({children: childrenValue})) - .startWith({children: null}), - LoadableValueComponent, - ); - childListElement = ( - - ); + const ChildrenComponent = (0, (_bindObservableAsProps || _load_bindObservableAsProps()).bindObservableAsProps)(children.map(childrenValue => ({ children: childrenValue })).startWith({ children: null }), LoadableValueComponent); + childListElement = _react.createElement(ChildrenComponent, { + fetchChildren: fetchChildren, + path: path, + expandedValuePaths: expandedValuePaths, + onExpandedStateChange: onExpandedStateChange, + simpleValueComponent: SimpleValueComponent, + shouldCacheChildren: shouldCacheChildren, + getCachedChildren: getCachedChildren, + setCachedChildren: setCachedChildren + }); } } - const title = this.state.isBeingEdited - ? this._renderEditView() - : renderValueLine(expression, description); - return ( - - {} : this._toggleExpandFiltered - } - title={title}> - {childListElement} - - {this._renderEditableScopeView()} - + const title = this.state.isBeingEdited ? this._renderEditView() : renderValueLine(expression, description); + return _react.createElement( + (_Tree || _load_Tree()).TreeList, + { + showArrows: true, + className: 'nuclide-ui-lazy-nested-value-treelist' }, + _react.createElement( + (_Tree || _load_Tree()).NestedTreeItem, + { + collapsed: !this.state.isExpanded, + onConfirm: this._showSetVariableDisplay, + onSelect: this.state.isBeingEdited ? () => {} : this._toggleExpandFiltered, + title: title }, + childListElement + ), + this._renderEditableScopeView() ); } } -function shouldFetchChildren(props: LazyNestedValueComponentProps): boolean { - const {fetchChildren, evaluationResult} = props; - return ( - shouldFetchBecauseNothingIsCached(props) && - typeof fetchChildren === 'function' && - evaluationResult != null && - evaluationResult.objectId != null - ); +function shouldFetchChildren(props) { + const { fetchChildren, evaluationResult } = props; + return shouldFetchBecauseNothingIsCached(props) && typeof fetchChildren === 'function' && evaluationResult != null && evaluationResult.objectId != null; } -function shouldFetchBecauseNothingIsCached( - props: LazyNestedValueComponentProps, -): boolean { - const {shouldCacheChildren, getCachedChildren, path} = props; +function shouldFetchBecauseNothingIsCached(props) { + const { shouldCacheChildren, getCachedChildren, path } = props; const children = getCachedChildren(path); return !shouldCacheChildren || children == null; } -type TopLevelValueComponentProps = { - className?: string, - evaluationResult: ?EvaluationResult, - fetchChildren: ?(objectId: string) => Observable, - setVariable?: ?(expression: ?string, newValue: ?string) => void, - expression?: string, - simpleValueComponent: React.ComponentType, - shouldCacheChildren?: boolean, - // An (arbitrary) reference object used to track expansion state of the component's - // children across multiple re-renders. To ensure persistent re-use of the expansion state, - // simply continue passing the same instance. - expansionStateId: Object, -}; - -type NodeData = { - isExpanded: boolean, - cachedChildren: ?ExpansionResult, -}; - -const expansionStates: WeakMap> = new WeakMap(); +const expansionStates = new WeakMap(); /** * TopLevelValueComponent wraps all expandable value components. It is in charge of keeping track * of the set of recursively expanded values. The set is keyed by a "path", which is a string @@ -468,42 +448,50 @@ const expansionStates: WeakMap> = new WeakMap(); * is necessary to preserve the expansion state while the values are temporarily unavailable, such * as after stepping in the debugger, which triggers a recursive re-fetch. */ -class TopLevelLazyNestedValueComponent extends React.PureComponent< - TopLevelValueComponentProps, -> { - shouldCacheChildren: boolean; +class TopLevelLazyNestedValueComponent extends _react.PureComponent { - constructor(props: TopLevelValueComponentProps) { + constructor(props) { super(props); - this.shouldCacheChildren = - this.props.shouldCacheChildren == null - ? false - : this.props.shouldCacheChildren; - } - handleExpansionChange = ( - expandedValuePath: string, - isExpanded: boolean, - ): void => { - const expandedValuePaths = this.getExpandedValuePaths(); - const nodeData = expandedValuePaths.get(expandedValuePath) || { - isExpanded, - cachedChildren: null, + this.handleExpansionChange = (expandedValuePath, isExpanded) => { + const expandedValuePaths = this.getExpandedValuePaths(); + const nodeData = expandedValuePaths.get(expandedValuePath) || { + isExpanded, + cachedChildren: null + }; + if (isExpanded) { + expandedValuePaths.set(expandedValuePath, Object.assign({}, nodeData, { + isExpanded: true + })); + } else { + expandedValuePaths.set(expandedValuePath, Object.assign({}, nodeData, { + isExpanded: false + })); + } }; - if (isExpanded) { - expandedValuePaths.set(expandedValuePath, { - ...nodeData, - isExpanded: true, - }); - } else { - expandedValuePaths.set(expandedValuePath, { - ...nodeData, - isExpanded: false, - }); - } - }; - getExpandedValuePaths(): Map { + this.getCachedChildren = path => { + const nodeData = this.getExpandedValuePaths().get(path); + if (nodeData == null) { + return null; + } else { + return nodeData.cachedChildren; + } + }; + + this.setCachedChildren = (path, children) => { + const nodeData = this.getExpandedValuePaths().get(path); + if (nodeData != null) { + this.getExpandedValuePaths().set(path, Object.assign({}, nodeData, { + cachedChildren: children + })); + } + }; + + this.shouldCacheChildren = this.props.shouldCacheChildren == null ? false : this.props.shouldCacheChildren; + } + + getExpandedValuePaths() { const reference = this.props.expansionStateId; let expandedValuePaths = expansionStates.get(reference); if (expandedValuePaths == null) { @@ -513,51 +501,28 @@ class TopLevelLazyNestedValueComponent extends React.PureComponent< return expandedValuePaths; } - getCachedChildren = (path: string): ?ExpansionResult => { - const nodeData = this.getExpandedValuePaths().get(path); - if (nodeData == null) { - return null; - } else { - return nodeData.cachedChildren; - } - }; - - setCachedChildren = (path: string, children: ExpansionResult): void => { - const nodeData = this.getExpandedValuePaths().get(path); - if (nodeData != null) { - this.getExpandedValuePaths().set(path, { - ...nodeData, - cachedChildren: children, - }); - } - }; - - render(): React.Node { - const className = classnames(this.props.className, { + render() { + const className = (0, (_classnames || _load_classnames()).default)(this.props.className, { // Note(vjeux): the following line should probably be `: true` - 'nuclide-ui-lazy-nested-value': this.props.className == null, + 'nuclide-ui-lazy-nested-value': this.props.className == null }); - return ( - - - + return _react.createElement( + 'span', + { className: className, tabIndex: -1 }, + _react.createElement(ValueComponent, Object.assign({}, this.props, { + isRoot: true, + expandedValuePaths: this.getExpandedValuePaths(), + onExpandedStateChange: this.handleExpansionChange, + path: 'root', + shouldCacheChildren: this.shouldCacheChildren, + getCachedChildren: this.getCachedChildren, + setCachedChildren: this.setCachedChildren + })) ); } } -function arePropsEqual( - p1: LazyNestedValueComponentProps, - p2: LazyNestedValueComponentProps, -): boolean { +function arePropsEqual(p1, p2) { const evaluationResult1 = p1.evaluationResult; const evaluationResult2 = p2.evaluationResult; if (evaluationResult1 === evaluationResult2) { @@ -566,15 +531,8 @@ function arePropsEqual( if (evaluationResult1 == null || evaluationResult2 == null) { return false; } - return ( - evaluationResult1.value === evaluationResult2.value && - evaluationResult1.type === evaluationResult2.type && - evaluationResult1.description === evaluationResult2.description - ); + return evaluationResult1.value === evaluationResult2.value && evaluationResult1.type === evaluationResult2.type && evaluationResult1.description === evaluationResult2.description; } -export const LazyNestedValueComponent = highlightOnUpdate( - TopLevelLazyNestedValueComponent, - arePropsEqual, - undefined /* custom classname */, - undefined /* custom delay */, -); +const LazyNestedValueComponent = exports.LazyNestedValueComponent = (0, (_highlightOnUpdate || _load_highlightOnUpdate()).highlightOnUpdate)(TopLevelLazyNestedValueComponent, arePropsEqual, undefined /* custom classname */ +, undefined /* custom delay */ +); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/LoadingSpinner.js b/modules/nuclide-commons-ui/LoadingSpinner.js index f5fd4193..cd349d48 100644 --- a/modules/nuclide-commons-ui/LoadingSpinner.js +++ b/modules/nuclide-commons-ui/LoadingSpinner.js @@ -1,88 +1,85 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.LoadingSpinner = exports.LoadingSpinnerSizes = undefined; + +var _addTooltip; + +function _load_addTooltip() { + return _addTooltip = _interopRequireDefault(require('./addTooltip')); +} -import addTooltip from './addTooltip'; -import classnames from 'classnames'; -import * as React from 'react'; - -export type LoadingSpinnerSize = 'EXTRA_SMALL' | 'SMALL' | 'MEDIUM' | 'LARGE'; -type Props = { - className?: string, - /** The size of the LoadingSpinner. Defaults to MEDIUM. */ - size?: LoadingSpinnerSize, - /** - * An optional delay (in milliseconds) between mounting the component and actually rendering - * the spinner to avoid UI churn. - */ - delay?: number, - tooltip?: atom$TooltipsAddOptions, -}; - -export const LoadingSpinnerSizes = Object.freeze({ +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const LoadingSpinnerSizes = exports.LoadingSpinnerSizes = Object.freeze({ EXTRA_SMALL: 'EXTRA_SMALL', SMALL: 'SMALL', MEDIUM: 'MEDIUM', - LARGE: 'LARGE', -}); + LARGE: 'LARGE' +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ const LoadingSpinnerClassnames = Object.freeze({ EXTRA_SMALL: 'loading-spinner-tiny', SMALL: 'loading-spinner-small', MEDIUM: 'loading-spinner-medium', - LARGE: 'loading-spinner-large', + LARGE: 'loading-spinner-large' }); /** * Shows an indefinite, animated LoadingSpinner. */ -export class LoadingSpinner extends React.Component< - Props, - {shouldRender: boolean}, -> { - _timeout: ?TimeoutID; +class LoadingSpinner extends _react.Component { - constructor(props: Props) { + constructor(props) { super(props); - this.state = {shouldRender: !this.props.delay}; + this.state = { shouldRender: !this.props.delay }; } - componentDidMount(): void { + componentDidMount() { if (!this.state.shouldRender) { - this._timeout = setTimeout( - () => this.setState({shouldRender: true}), - this.props.delay, - ); + this._timeout = setTimeout(() => this.setState({ shouldRender: true }), this.props.delay); } } - componentWillUnmount(): void { + componentWillUnmount() { if (this._timeout != null) { clearTimeout(this._timeout); } } - render(): React.Node { - const {className, size, tooltip} = this.props; + render() { + const { className, size, tooltip } = this.props; if (!this.state.shouldRender) { return null; } - const ref = tooltip ? addTooltip(tooltip) : null; - const safeSize = - size != null && LoadingSpinnerSizes.hasOwnProperty(size) - ? size - : LoadingSpinnerSizes.MEDIUM; + const ref = tooltip ? (0, (_addTooltip || _load_addTooltip()).default)(tooltip) : null; + const safeSize = size != null && LoadingSpinnerSizes.hasOwnProperty(size) ? size : LoadingSpinnerSizes.MEDIUM; const sizeClassname = LoadingSpinnerClassnames[safeSize]; - const newClassName = classnames(className, 'loading', sizeClassname); - return
; + const newClassName = (0, (_classnames || _load_classnames()).default)(className, 'loading', sizeClassname); + return _react.createElement('div', { className: newClassName, ref: ref }); } } +exports.LoadingSpinner = LoadingSpinner; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/MeasuredComponent.js b/modules/nuclide-commons-ui/MeasuredComponent.js index 0639d76b..af99f502 100644 --- a/modules/nuclide-commons-ui/MeasuredComponent.js +++ b/modules/nuclide-commons-ui/MeasuredComponent.js @@ -1,57 +1,66 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.MeasuredComponent = undefined; + +var _react = _interopRequireWildcard(require('react')); -import * as React from 'react'; +var _observableDom; + +function _load_observableDom() { + return _observableDom = require('./observable-dom'); +} -import {ResizeObservable} from './observable-dom'; -import invariant from 'assert'; +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } -type Props = { - onMeasurementsChanged: ( - measurements: DOMRectReadOnly, - target: HTMLElement, - ) => mixed, - children?: React.Element, -}; +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ /** A container which invokes a callback function supplied in props whenever the * container's height and width measurements change. The callback is invoked once * when the MeasuredComponent has mounted. */ -export class MeasuredComponent extends React.Component { +class MeasuredComponent extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._updateDomNode = node => { + if (node == null) { + this._domNode = null; + // _updateDomNode is called before component unmount, so don't need to unsubscribe() + // in componentWillUnmount() + this._resizeSubscription.unsubscribe(); + return; + } + this._resizeSubscription = new (_observableDom || _load_observableDom()).ResizeObservable(node).subscribe(entries => { + if (!(entries.length === 1)) { + throw new Error('Invariant violation: "entries.length === 1"'); + } + + this.props.onMeasurementsChanged(entries[0].contentRect, entries[0].target); + }); + this._domNode = node; + }, _temp; + } // Listens to the container DOM node for mutations - _resizeSubscription: rxjs$ISubscription; - _domNode: ?HTMLElement; - - _updateDomNode = (node: ?HTMLElement): void => { - if (node == null) { - this._domNode = null; - // _updateDomNode is called before component unmount, so don't need to unsubscribe() - // in componentWillUnmount() - this._resizeSubscription.unsubscribe(); - return; - } - this._resizeSubscription = new ResizeObservable(node).subscribe(entries => { - invariant(entries.length === 1); - this.props.onMeasurementsChanged( - entries[0].contentRect, - entries[0].target, - ); - }); - this._domNode = node; - }; - - render(): React.Node { - const {onMeasurementsChanged, ...passThroughProps} = this.props; - return
; + + + render() { + const _props = this.props, + { onMeasurementsChanged } = _props, + passThroughProps = _objectWithoutProperties(_props, ['onMeasurementsChanged']); + return _react.createElement('div', Object.assign({ ref: this._updateDomNode }, passThroughProps)); } } +exports.MeasuredComponent = MeasuredComponent; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Message.example.js b/modules/nuclide-commons-ui/Message.example.js index da9fa414..ee6b8f17 100644 --- a/modules/nuclide-commons-ui/Message.example.js +++ b/modules/nuclide-commons-ui/Message.example.js @@ -1,58 +1,120 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import * as React from 'react'; -import {Block} from './Block'; -import {Message, MessageTypes} from './Message'; - -const MessageExample = (): React.Element => ( -
- - -

Message

- Hello, I'm a simple message. -
-
- - - Hello I'm an info message. - - - - - Hello I'm a success message. - - - - - Hello I'm a warning message. - - - - - Hello I'm an error message. - - -
-); - -export const MessageExamples = { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.MessageExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Message; + +function _load_Message() { + return _Message = require('./Message'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const MessageExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Message || _load_Message()).Message, + null, + _react.createElement( + 'h2', + null, + 'Message' + ), + 'Hello, I\'m a simple message.' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Message || _load_Message()).Message, + { type: (_Message || _load_Message()).MessageTypes.info }, + 'Hello I\'m an ', + _react.createElement( + 'strong', + null, + 'info' + ), + ' message.' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Message || _load_Message()).Message, + { type: (_Message || _load_Message()).MessageTypes.success }, + 'Hello I\'m a ', + _react.createElement( + 'strong', + null, + 'success' + ), + ' message.' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Message || _load_Message()).Message, + { type: (_Message || _load_Message()).MessageTypes.warning }, + 'Hello I\'m a ', + _react.createElement( + 'strong', + null, + 'warning' + ), + ' message.' + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Message || _load_Message()).Message, + { type: (_Message || _load_Message()).MessageTypes.error }, + 'Hello I\'m an ', + _react.createElement( + 'strong', + null, + 'error' + ), + ' message.' + ) + ) +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const MessageExamples = exports.MessageExamples = { sectionName: 'Messages', - description: - 'Message boxes are used to surface issues, such as warnings, inline within Nuclide.', - examples: [ - { - title: 'Basic Messages', - component: MessageExample, - }, - ], -}; + description: 'Message boxes are used to surface issues, such as warnings, inline within Nuclide.', + examples: [{ + title: 'Basic Messages', + component: MessageExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Message.js b/modules/nuclide-commons-ui/Message.js index 1dd317b8..c51f8eea 100644 --- a/modules/nuclide-commons-ui/Message.js +++ b/modules/nuclide-commons-ui/Message.js @@ -1,3 +1,22 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Message = exports.MessageTypes = undefined; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,27 +25,16 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import classnames from 'classnames'; -import * as React from 'react'; - -export type MessageType = 'default' | 'info' | 'success' | 'warning' | 'error'; - -type Props = { - className?: string, - children?: React.Node, - type?: MessageType, -}; - -export const MessageTypes = Object.freeze({ +const MessageTypes = exports.MessageTypes = Object.freeze({ default: 'default', info: 'info', success: 'success', warning: 'warning', - error: 'error', + error: 'error' }); const MessageTypeClassNames = Object.freeze({ @@ -34,16 +42,16 @@ const MessageTypeClassNames = Object.freeze({ error: 'nuclide-ui-message-error', info: 'nuclide-ui-message-info', success: 'nuclide-ui-message-success', - warning: 'nuclide-ui-message-warning', + warning: 'nuclide-ui-message-warning' }); -export const Message = (props: Props) => { - const {className, children, type} = props; +const Message = exports.Message = props => { + const { className, children, type } = props; const resolvedType = type == null ? MessageTypes.default : type; - const newClassName = classnames( - className, - 'nuclide-ui-message', - MessageTypeClassNames[resolvedType], + const newClassName = (0, (_classnames || _load_classnames()).default)(className, 'nuclide-ui-message', MessageTypeClassNames[resolvedType]); + return _react.createElement( + 'div', + { className: newClassName }, + children ); - return
{children}
; -}; +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Modal.js b/modules/nuclide-commons-ui/Modal.js index 94ef907c..a59ab94a 100644 --- a/modules/nuclide-commons-ui/Modal.js +++ b/modules/nuclide-commons-ui/Modal.js @@ -1,108 +1,109 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -// DEPRECATED, AVOID USING THIS. Use 'showModal' in nuclide-commons-ui instead +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Modal = undefined; + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import {Observable} from 'rxjs'; +var _react = _interopRequireWildcard(require('react')); -type Props = { - children?: any, - modalClassName?: string, - onDismiss: () => void, -}; +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +// DEPRECATED, AVOID USING THIS. Use 'showModal' in nuclide-commons-ui instead /** * Shows a modal dialog when rendered, using Atom's APIs (atom.workspace.addModalPanel). */ -export class Modal extends React.Component { - _container: HTMLElement; - _cancelDisposable: ?IDisposable; - _innerElement: ?HTMLElement; - _panel: atom$Panel; +class Modal extends _react.Component { + constructor(...args) { + var _temp; - componentWillMount(): void { + return _temp = super(...args), this._handleWindowClick = event => { + // If the user clicks outside of the modal, and not on a tooltip or + // notification, close it. + if (this._innerElement && !this._innerElement.contains(event.target) && event.target.closest('atom-notifications, .tooltip') == null) { + this.props.onDismiss(); + } + }, this._handleContainerInnerElement = el => { + if (this._cancelDisposable != null) { + this._cancelDisposable.dispose(); + } + + this._innerElement = el; + if (el == null) { + return; + } + + el.focus(); + this._cancelDisposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.commands.add(window, 'core:cancel', () => { + this.props.onDismiss(); + }), _rxjsBundlesRxMinJs.Observable.fromEvent(window, 'mousedown') + // Ignore clicks in the current tick. We don't want to capture the click that showed this + // modal. + .skipUntil(_rxjsBundlesRxMinJs.Observable.interval(0).first()).subscribe(this._handleWindowClick)); + }, _temp; + } + + componentWillMount() { this._container = document.createElement('div'); this._panel = atom.workspace.addModalPanel({ item: this._container, - className: this.props.modalClassName, + className: this.props.modalClassName }); } - componentWillUnmount(): void { + componentWillUnmount() { this._panel.destroy(); } - componentDidUpdate(prevProps: Props): void { - const {modalClassName} = this.props; - const {modalClassName: prevModalClassName} = prevProps; + componentDidUpdate(prevProps) { + const { modalClassName } = this.props; + const { modalClassName: prevModalClassName } = prevProps; const panelElement = this._panel.getElement(); if (prevModalClassName != null) { - panelElement.classList.remove( - ...prevModalClassName.split(/\s+/).filter(token => token.length > 0), - ); + panelElement.classList.remove(...prevModalClassName.split(/\s+/).filter(token => token.length > 0)); } if (modalClassName != null) { - panelElement.classList.add( - ...modalClassName.split(/\s+/).filter(token => token.length > 0), - ); + panelElement.classList.add(...modalClassName.split(/\s+/).filter(token => token.length > 0)); } } - _handleWindowClick = (event: SyntheticMouseEvent<>): void => { - // If the user clicks outside of the modal, and not on a tooltip or - // notification, close it. - if ( - this._innerElement && - !this._innerElement.contains(((event.target: any): Node)) && - (event.target: any).closest('atom-notifications, .tooltip') == null - ) { - this.props.onDismiss(); - } - }; - // Since we're rendering null, we can't use `findDOMNode(this)`. - _handleContainerInnerElement = (el: ?HTMLElement): void => { - if (this._cancelDisposable != null) { - this._cancelDisposable.dispose(); - } - this._innerElement = el; - if (el == null) { - return; - } - - el.focus(); - this._cancelDisposable = new UniversalDisposable( - atom.commands.add(window, 'core:cancel', () => { - this.props.onDismiss(); - }), - Observable.fromEvent(window, 'mousedown') - // Ignore clicks in the current tick. We don't want to capture the click that showed this - // modal. - .skipUntil(Observable.interval(0).first()) - .subscribe(this._handleWindowClick), - ); - }; render() { - const {modalClassName, children, onDismiss, ...props} = this.props; - return ReactDOM.createPortal( -
- {this.props.children} -
, - this._container, - ); + const _props = this.props, + { modalClassName, children, onDismiss } = _props, + props = _objectWithoutProperties(_props, ['modalClassName', 'children', 'onDismiss']); + return _reactDom.default.createPortal(_react.createElement( + 'div', + Object.assign({ tabIndex: '0' }, props, { ref: this._handleContainerInnerElement }), + this.props.children + ), this._container); } } +exports.Modal = Modal; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ModalMultiSelect.js b/modules/nuclide-commons-ui/ModalMultiSelect.js index f539d4c6..a5c88998 100644 --- a/modules/nuclide-commons-ui/ModalMultiSelect.js +++ b/modules/nuclide-commons-ui/ModalMultiSelect.js @@ -1,177 +1,211 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {ButtonSize} from './Button'; -import type {OptionComponentProps} from './MultiSelectList'; - -import {Button, ButtonSizes, ButtonTypes} from './Button'; -import {ButtonGroup} from './ButtonGroup'; -import {Modal} from './Modal'; -import {MultiSelectList} from './MultiSelectList'; -import classnames from 'classnames'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; - -type Option = { - // $FlowFixMe(>=0.53.0) Flow suppress - label: React.Children, - value: any, -}; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ModalMultiSelect = undefined; -type Props = { - labelComponent?: (props: LabelComponentProps) => React.Element, - optionComponent?: (props: OptionComponentProps) => React.Element, - className?: string, - disabled?: boolean, - options: Array
+ return _react.createElement( + 'div', + { key: i, className: 'nuclide-ui-radiogroup-div' }, + _react.createElement('input', { + className: 'input-radio', + type: 'radio', + checked: i === selectedIndex, + name: 'radiogroup-' + this.state.uid, + id: id, + onChange: () => { + onSelectedChange(i); + } + }), + _react.createElement( + 'label', + { + className: 'input-label nuclide-ui-radiogroup-label', + htmlFor: id }, + labelContent + ) ); }); - return
{checkboxes}
; + return _react.createElement( + 'div', + { className: className }, + checkboxes + ); } } +exports.default = RadioGroup; +RadioGroup.defaultProps = { + optionLabels: [], + onSelectedChange: selectedIndex => {}, + selectedIndex: 0 +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ReactMountRootElement.js b/modules/nuclide-commons-ui/ReactMountRootElement.js index 743649ac..be9fb98e 100644 --- a/modules/nuclide-commons-ui/ReactMountRootElement.js +++ b/modules/nuclide-commons-ui/ReactMountRootElement.js @@ -1,56 +1,67 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -/* global HTMLElement */ +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -import invariant from 'assert'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } /** * A custom HTMLElement we render React elements into. */ class ReactMountRootElement extends HTMLElement { - _reactElement: ?React.Element; - setReactElement(reactElement: React.Element): void { + setReactElement(reactElement) { this._reactElement = reactElement; } - attachedCallback(): mixed { + attachedCallback() { if (this._reactElement == null) { return; } - ReactDOM.render(this._reactElement, this); + _reactDom.default.render(this._reactElement, this); } - detachedCallback(): mixed { + detachedCallback() { if (this._reactElement == null) { return; } - ReactDOM.unmountComponentAtNode(this); + _reactDom.default.unmountComponentAtNode(this); } -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +/* global HTMLElement */ let reactMountRootElement; try { reactMountRootElement = document.registerElement('nuclide-react-mount-root', { - prototype: ReactMountRootElement.prototype, + prototype: ReactMountRootElement.prototype }); } catch (e) { // Element was already registered. Retrieve its constructor: const oldElem = document.createElement('nuclide-react-mount-root'); - invariant(oldElem.constructor.name === 'nuclide-react-mount-root'); - reactMountRootElement = (oldElem.constructor: any); + + if (!(oldElem.constructor.name === 'nuclide-react-mount-root')) { + throw new Error('Invariant violation: "oldElem.constructor.name === \'nuclide-react-mount-root\'"'); + } + + reactMountRootElement = oldElem.constructor; } -export default (reactMountRootElement: Class); +exports.default = reactMountRootElement; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ReadOnlyNotice.js b/modules/nuclide-commons-ui/ReadOnlyNotice.js index be719428..3460bee3 100644 --- a/modules/nuclide-commons-ui/ReadOnlyNotice.js +++ b/modules/nuclide-commons-ui/ReadOnlyNotice.js @@ -1,3 +1,31 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +var _TextEditorBanner; + +function _load_TextEditorBanner() { + return _TextEditorBanner = require('./TextEditorBanner'); +} + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); +} + +var _Message; + +function _load_Message() { + return _Message = require('./Message'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,52 +34,49 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import * as React from 'react'; -import {Notice} from './TextEditorBanner'; -import {Button, ButtonTypes} from './Button'; -import {MessageTypes} from './Message'; - -type Props = { - detailedMessage: string, - canEditAnyway?: boolean, - onEditAnyway?: () => void, - onDismiss?: () => void, -}; - -export default class ReadOnlyNotice extends React.Component { - render(): React.Node { +class ReadOnlyNotice extends _react.Component { + render() { let editAnywayButton; if (this.props.canEditAnyway) { - editAnywayButton = ( - + editAnywayButton = _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: (_Button || _load_Button()).ButtonTypes.INFO, onClick: this.props.onEditAnyway }, + 'Edit Anyway' ); } - const dismissButton = ( - + const dismissButton = _react.createElement( + (_Button || _load_Button()).Button, + { buttonType: (_Button || _load_Button()).ButtonTypes.INFO, onClick: this.props.onDismiss }, + 'Dismiss' ); - return ( - - - This is a read-only file. -
- {this.props.detailedMessage} -
-
- {editAnywayButton} - {dismissButton} -
-
+ return _react.createElement( + (_TextEditorBanner || _load_TextEditorBanner()).Notice, + { messageType: (_Message || _load_Message()).MessageTypes.info }, + _react.createElement( + 'span', + null, + _react.createElement( + 'strong', + null, + 'This is a read-only file.' + ), + _react.createElement('br', null), + this.props.detailedMessage + ), + _react.createElement( + 'div', + null, + editAnywayButton, + dismissButton + ) ); } } +exports.default = ReadOnlyNotice; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/RegExpFilter.example.js b/modules/nuclide-commons-ui/RegExpFilter.example.js index 4c482b6d..04ae8ffb 100644 --- a/modules/nuclide-commons-ui/RegExpFilter.example.js +++ b/modules/nuclide-commons-ui/RegExpFilter.example.js @@ -1,3 +1,33 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _RegExpFilter; + +function _load_RegExpFilter() { + return _RegExpFilter = _interopRequireDefault(require('./RegExpFilter')); +} + +var _RegExpFilter2; + +function _load_RegExpFilter2() { + return _RegExpFilter2 = require('./RegExpFilter'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,58 +36,48 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {RegExpFilterChange} from './RegExpFilter'; - -import * as React from 'react'; -import {Block} from './Block'; -import RegExpFilter, {getFilterPattern} from './RegExpFilter'; - -type State = { - text: string, - isRegExp: boolean, - invalid: boolean, -}; - -class Example extends React.Component<{}, State> { - state = { - text: '', - isRegExp: false, - invalid: false, - }; - - render(): React.Node { - const {text, isRegExp, invalid} = this.state; - - return ( -
- - - -
+class Example extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this.state = { + text: '', + isRegExp: false, + invalid: false + }, this._handleChange = change => { + const { invalid } = (0, (_RegExpFilter2 || _load_RegExpFilter2()).getFilterPattern)(change.text, change.isRegExp); + this.setState(Object.assign({}, change, { invalid })); + }, _temp; + } + + render() { + const { text, isRegExp, invalid } = this.state; + + return _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_RegExpFilter || _load_RegExpFilter()).default, { + value: { text, isRegExp, invalid }, + onChange: this._handleChange + }) + ) ); } - _handleChange = (change: RegExpFilterChange): void => { - const {invalid} = getFilterPattern(change.text, change.isRegExp); - this.setState({...change, invalid}); - }; } -export default { +exports.default = { sectionName: 'RegExp Filter', - description: - 'An input for filtering that allows the use of regular expressions.', - examples: [ - { - title: 'RegExpFilter', - component: Example, - }, - ], -}; + description: 'An input for filtering that allows the use of regular expressions.', + examples: [{ + title: 'RegExpFilter', + component: Example + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/RegExpFilter.js b/modules/nuclide-commons-ui/RegExpFilter.js index de57b7eb..11d14612 100644 --- a/modules/nuclide-commons-ui/RegExpFilter.js +++ b/modules/nuclide-commons-ui/RegExpFilter.js @@ -1,163 +1,160 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {ButtonSize} from './Button'; - -import {AtomInput} from './AtomInput'; -import classnames from 'classnames'; -import {Button, ButtonSizes} from './Button'; -import {ButtonGroup} from './ButtonGroup'; -import escapeStringRegexp from 'escape-string-regexp'; -import * as React from 'react'; - -type Size = 'xs' | 'sm' | 'lg'; - -type Props = { - value: RegExpFilterValue, - inputWidth?: number, - inputClassName?: string, - onChange: (value: RegExpFilterChange) => mixed, - size?: Size, -}; - -type State = { - text: string, - isRegExp: boolean, - invalid: boolean, -}; - -export type RegExpFilterValue = { - text: string, - isRegExp: boolean, - invalid: boolean, -}; - -export type FilterPattern = { - pattern: ?RegExp, - invalid: boolean, -}; - -export type RegExpFilterChange = { - text: string, - isRegExp: boolean, -}; - -export default class RegExpFilter extends React.Component { - _currentValue: RegExpFilterValue; - _input: ?AtomInput; - - constructor(props: Props) { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getFilterPattern = getFilterPattern; + +var _AtomInput; + +function _load_AtomInput() { + return _AtomInput = require('./AtomInput'); +} + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); +} + +var _ButtonGroup; + +function _load_ButtonGroup() { + return _ButtonGroup = require('./ButtonGroup'); +} + +var _escapeStringRegexp; + +function _load_escapeStringRegexp() { + return _escapeStringRegexp = _interopRequireDefault(require('escape-string-regexp')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +class RegExpFilter extends _react.Component { + + constructor(props) { super(props); + + this._handleReToggleButtonClick = () => { + this.props.onChange({ + text: this._currentValue.text, + isRegExp: !this._currentValue.isRegExp + }); + }; + + this._handleTextChange = text => { + if (text === this._currentValue.text) { + return; + } + this.props.onChange({ + text, + isRegExp: this._currentValue.isRegExp + }); + }; + this._currentValue = props.value; } - componentWillReceiveProps(props: Props): void { + componentWillReceiveProps(props) { // We need to store this so that we can use it in the event handlers. this._currentValue = props.value; } - render(): React.Node { - const {value: {text, isRegExp, invalid}} = this.props; + render() { + const { value: { text, isRegExp, invalid } } = this.props; const size = this.props.size || 'sm'; const buttonSize = getButtonSize(size); - const inputWidth = - this.props.inputWidth == null ? 200 : this.props.inputWidth; - const inputClassName = classnames( - 'nuclide-ui-regexp-filter-input', - this.props.inputClassName, - ); - - return ( - - { - this._input = el; - }} - invalid={invalid} - className={inputClassName} - size={size} - width={inputWidth} - placeholderText="Filter" - onDidChange={this._handleTextChange} - value={text} - /> - - + const inputWidth = this.props.inputWidth == null ? 200 : this.props.inputWidth; + const inputClassName = (0, (_classnames || _load_classnames()).default)('nuclide-ui-regexp-filter-input', this.props.inputClassName); + + return _react.createElement( + (_ButtonGroup || _load_ButtonGroup()).ButtonGroup, + { className: 'inline-block' }, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + ref: el => { + this._input = el; + }, + invalid: invalid, + className: inputClassName, + size: size, + width: inputWidth, + placeholderText: 'Filter', + onDidChange: this._handleTextChange, + value: text + }), + _react.createElement( + (_Button || _load_Button()).Button, + { + className: 'nuclide-ui-regexp-filter-button', + size: buttonSize, + selected: isRegExp, + onClick: this._handleReToggleButtonClick, + tooltip: { title: 'Use Regex' } }, + '.*' + ) ); } - focus(): void { + focus() { if (this._input == null) { return; } this._input.focus(); } - _handleReToggleButtonClick = (): void => { - this.props.onChange({ - text: this._currentValue.text, - isRegExp: !this._currentValue.isRegExp, - }); - }; - - _handleTextChange = (text: string): void => { - if (text === this._currentValue.text) { - return; - } - this.props.onChange({ - text, - isRegExp: this._currentValue.isRegExp, - }); - }; } -function getButtonSize(size: Size): ButtonSize { +exports.default = RegExpFilter; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function getButtonSize(size) { switch (size) { case 'xs': - return ButtonSizes.EXTRA_SMALL; + return (_Button || _load_Button()).ButtonSizes.EXTRA_SMALL; case 'sm': - return ButtonSizes.SMALL; + return (_Button || _load_Button()).ButtonSizes.SMALL; case 'lg': - return ButtonSizes.LARGE; + return (_Button || _load_Button()).ButtonSizes.LARGE; default: - (size: empty); + size; throw new Error(`Invalid size: ${size}`); } } -export function getFilterPattern( - text: string, - isRegExp: boolean, -): FilterPattern { +function getFilterPattern(text, isRegExp) { if (text === '') { - return {pattern: null, invalid: false}; + return { pattern: null, invalid: false }; } - const source = isRegExp ? text : escapeStringRegexp(text); + const source = isRegExp ? text : (0, (_escapeStringRegexp || _load_escapeStringRegexp()).default)(text); try { return { pattern: new RegExp(source, 'i'), - invalid: false, + invalid: false }; } catch (err) { return { pattern: null, - invalid: true, + invalid: true }; } -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ResizeSensitiveContainer.js b/modules/nuclide-commons-ui/ResizeSensitiveContainer.js index a333dca6..2a840548 100644 --- a/modules/nuclide-commons-ui/ResizeSensitiveContainer.js +++ b/modules/nuclide-commons-ui/ResizeSensitiveContainer.js @@ -1,26 +1,35 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ResizeSensitiveContainer = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _nullthrows; -import * as React from 'react'; -import classnames from 'classnames'; -import nullthrows from 'nullthrows'; -import {nextAnimationFrame} from 'nuclide-commons/observable'; -import {Subject} from 'rxjs'; +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +var _observable; + +function _load_observable() { + return _observable = require('nuclide-commons/observable'); +} -type SensorProps = { - targetHeight: number, - targetWidth: number, - onDetectedResize: () => void, -}; +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } const EXPANSION_BUFFER = 50; @@ -39,25 +48,44 @@ const EXPANSION_BUFFER = 50; * * This strategy is derived from https://github.com/wnr/element-resize-detector */ -class ResizeSensor extends React.Component { - _expand: ?HTMLElement; - _shrink: ?HTMLElement; +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ - componentDidMount(): void { +class ResizeSensor extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._handleScroll = () => { + this._resetScrollbars(); + this.props.onDetectedResize(); + }, this._handleExpandRef = el => { + this._expand = el; + }, this._handleShrinkRef = el => { + this._shrink = el; + }, _temp; + } + + componentDidMount() { this._resetScrollbars(); } - componentDidUpdate(prevProps: SensorProps): void { - const {targetWidth, targetHeight} = this.props; - if ( - prevProps.targetWidth !== targetWidth || - prevProps.targetHeight !== targetHeight - ) { + componentDidUpdate(prevProps) { + const { targetWidth, targetHeight } = this.props; + if (prevProps.targetWidth !== targetWidth || prevProps.targetHeight !== targetHeight) { this._resetScrollbars(); } } - _resetScrollbars(): void { + _resetScrollbars() { if (this._expand == null || this._shrink == null) { return; } @@ -69,64 +97,43 @@ class ResizeSensor extends React.Component { this._shrink.scrollTop = this._shrink.scrollHeight; } - _handleScroll = (): void => { - this._resetScrollbars(); - this.props.onDetectedResize(); - }; - - _handleExpandRef = (el: HTMLElement): void => { - this._expand = el; - }; - - _handleShrinkRef = (el: HTMLElement): void => { - this._shrink = el; - }; - - render(): React.Node { - const {targetWidth, targetHeight} = this.props; + render() { + const { targetWidth, targetHeight } = this.props; const expandInnerStyle = { width: targetWidth + EXPANSION_BUFFER, - height: targetHeight + EXPANSION_BUFFER, + height: targetHeight + EXPANSION_BUFFER }; - return ( -
-
=0.53.0) Flow suppress - ref={this._handleExpandRef} - className="nuclide-resize-sensitive-container-expand" - onScroll={this._handleScroll}> -
-
-
=0.53.0) Flow suppress - ref={this._handleShrinkRef} - className="nuclide-resize-sensitive-container-shrink" - onScroll={this._handleScroll}> -
-
-
+ ref: this._handleShrinkRef, + className: 'nuclide-resize-sensitive-container-shrink', + onScroll: this._handleScroll }, + _react.createElement('div', { className: 'nuclide-resize-sensitive-container-shrink-inner' }) + ) ); } } -type Props = { - className?: string, - tabIndex?: string, - children?: React.Element, - onResize: (height: number, width: number) => void, -}; - -type State = { - height: number, - width: number, -}; - /** * Size-sensitive container that provides an onResize callback that * is invoked with the container's width and height whenever it changes. @@ -136,85 +143,80 @@ type State = { * changes as a result of a DOM mutation, use MeasuredComponent * instead. */ -export class ResizeSensitiveContainer extends React.Component { - _container: ?HTMLElement; - _resizeEvents: Subject = new Subject(); - _resizeSubscription: ?rxjs$Subscription; +class ResizeSensitiveContainer extends _react.Component { - constructor(props: Props) { + constructor(props) { super(props); + this._resizeEvents = new _rxjsBundlesRxMinJs.Subject(); + + this._handleContainer = el => { + this._container = el; + this._updateContainerSize(); + }; + + this._updateContainerSize = () => { + if (this._container == null) { + return; + } + + const { offsetHeight, offsetWidth } = this._container; + const { height, width } = this.state; + if (offsetHeight === height && offsetWidth === width) { + return; + } + + this.setState({ + height: offsetHeight, + width: offsetWidth + }); + this.props.onResize(offsetHeight, offsetWidth); + }; + + this._handleResize = () => { + this._resizeEvents.next(); + }; + this.state = { height: -1, - width: -1, + width: -1 }; } - componentDidMount(): void { - this._resizeSubscription = this._resizeEvents - .switchMap(() => nextAnimationFrame) - .subscribe(() => { - this._updateContainerSize(); - }); + componentDidMount() { + this._resizeSubscription = this._resizeEvents.switchMap(() => (_observable || _load_observable()).nextAnimationFrame).subscribe(() => { + this._updateContainerSize(); + }); } - componentWillUnmount(): void { - nullthrows(this._resizeSubscription).unsubscribe(); + componentWillUnmount() { + (0, (_nullthrows || _load_nullthrows()).default)(this._resizeSubscription).unsubscribe(); } - _containerRendered(): boolean { + _containerRendered() { return this.state.height !== -1 && this.state.width !== -1; } - _handleContainer = (el: ?HTMLElement): void => { - this._container = el; - this._updateContainerSize(); - }; - - _updateContainerSize = (): void => { - if (this._container == null) { - return; - } - - const {offsetHeight, offsetWidth} = this._container; - const {height, width} = this.state; - if (offsetHeight === height && offsetWidth === width) { - return; - } - - this.setState({ - height: offsetHeight, - width: offsetWidth, - }); - this.props.onResize(offsetHeight, offsetWidth); - }; - - _handleResize = (): void => { - this._resizeEvents.next(); - }; - - render(): React.Node { - const {children, className, tabIndex} = this.props; - const {height, width} = this.state; - const containerClasses = classnames( - 'nuclide-resize-sensitive-container', - className, - ); - return ( -
-
- {children} -
- {this._containerRendered() ? ( - - ) : null} -
+ render() { + const { children, className, tabIndex } = this.props; + const { height, width } = this.state; + const containerClasses = (0, (_classnames || _load_classnames()).default)('nuclide-resize-sensitive-container', className); + return _react.createElement( + 'div', + { className: 'nuclide-resize-sensitive-container-wrapper' }, + _react.createElement( + 'div', + { + ref: this._handleContainer, + className: containerClasses, + tabIndex: tabIndex }, + children + ), + this._containerRendered() ? _react.createElement(ResizeSensor, { + targetHeight: height, + targetWidth: width, + onDetectedResize: this._handleResize + }) : null ); } } +exports.ResizeSensitiveContainer = ResizeSensitiveContainer; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SelectableTree.js b/modules/nuclide-commons-ui/SelectableTree.js index 990e9f7a..7041ca6a 100644 --- a/modules/nuclide-commons-ui/SelectableTree.js +++ b/modules/nuclide-commons-ui/SelectableTree.js @@ -1,86 +1,135 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -/* eslint-env browser */ +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Tree = undefined; + +var _collection; + +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _shallowequal; + +function _load_shallowequal() { + return _shallowequal = _interopRequireDefault(require('shallowequal')); +} + +var _nullthrows; + +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +var _scrollIntoView; + +function _load_scrollIntoView() { + return _scrollIntoView = require('./scrollIntoView'); +} + +var _Tree; + +function _load_Tree() { + return _Tree = require('./Tree'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -import {arrayEqual, arrayFindLastIndex} from 'nuclide-commons/collection'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import * as React from 'react'; -import classnames from 'classnames'; -import invariant from 'assert'; -import {Observable} from 'rxjs'; -import shallowEqual from 'shallowequal'; -import nullthrows from 'nullthrows'; -import {scrollIntoView} from './scrollIntoView'; -import {TreeList} from './Tree'; - -export type NodePath = Array; -export type TreeNode = TreeLeafNode | TreeNestedNode; - -type TreeLeafNode = {| - type: 'LEAF', - label: React.Node, - hidden?: boolean, -|}; - -type TreeNestedNode = {| - type: 'NESTED', - children: Array, - label: React.Node, - hidden?: boolean, -|}; - -type TreeProps = {| - className?: string, - itemClassName?: string, - items: Array, - onSelect: (path: NodePath) => mixed, - onConfirm: (path: NodePath) => mixed, - onTripleClick: (path: NodePath) => mixed, - selectedPaths: Array, - collapsedPaths: Array, - onCollapse: (path: NodePath) => mixed, - onExpand: (path: NodePath) => mixed, -|}; - -type TreeState = {| - focusedPath: ?NodePath, - isFocused: boolean, -|}; - -export class Tree extends React.Component { - _rootNode: ?HTMLOListElement; - _subscriptions: UniversalDisposable; - state = { - isFocused: false, - focusedPath: null, - }; +class Tree extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this.state = { + isFocused: false, + focusedPath: null + }, this._selectNext = () => { + let nextNodePath; + if (this.state.focusedPath == null) { + nextNodePath = [0]; + } else { + nextNodePath = getNextNodePath(this.props.items, this.state.focusedPath, this.props.collapsedPaths); + } + if (nextNodePath != null) { + this.props.onSelect(nextNodePath); + this.setState({ focusedPath: nextNodePath }); + } + }, this._selectPrev = () => { + let prevNodePath; + if (this.state.focusedPath == null) { + prevNodePath = [0]; + } else { + prevNodePath = getPrevNodePath(this.props.items, this.state.focusedPath, this.props.collapsedPaths); + } + if (prevNodePath != null) { + this.props.onSelect(prevNodePath); + } + }, this._collapseNodeViaKeyboard = e => { + if (this.state.focusedPath == null) { + return; + } + + let collapsablePath = [...this.state.focusedPath]; + let collapsableNode = selectNodeAtPath(this.props.items, collapsablePath); + while (collapsableNode != null && collapsableNode.type !== 'NESTED') { + collapsablePath = collapsablePath.slice(0, collapsablePath.length - 1); + collapsableNode = selectNodeAtPath(this.props.items, collapsablePath); + } + + if (collapsableNode == null) { + return; + } + + this.props.onCollapse(collapsablePath); + // if a descendant of this node was selected when this node was collapsed, + // moving selection to this node seems like intuitive behavior (see Chrome's + // Elements tree) + this.props.onSelect(collapsablePath); + }, this._expandNodeViaKeyboard = e => { + const { focusedPath } = this.state; + if (focusedPath == null) { + return; + } + + const focusedNode = selectNodeAtPath(this.props.items, focusedPath); + if (focusedNode != null && focusedNode.type === 'NESTED') { + this.props.onExpand(focusedPath); + } + }, this._handleSelect = path => { + this.props.onSelect(path); + }, this._handleConfirm = path => { + this.props.onConfirm(path); + }, _temp; + } componentDidMount() { - const rootNode = nullthrows(this._rootNode); - this._subscriptions = new UniversalDisposable( - atom.commands.add(rootNode, { - 'core:move-up': this._selectPrev, - 'core:move-down': this._selectNext, - 'core:move-left': this._collapseNodeViaKeyboard, - 'core:move-right': this._expandNodeViaKeyboard, - 'core:confirm': () => - this.state.focusedPath && this._handleConfirm(this.state.focusedPath), - }), - Observable.merge( - Observable.fromEvent(rootNode, 'focusin').mapTo(true), - Observable.fromEvent(rootNode, 'focusout').mapTo(false), - ).subscribe(isFocused => this.setState({isFocused})), - ); + const rootNode = (0, (_nullthrows || _load_nullthrows()).default)(this._rootNode); + this._subscriptions = new (_UniversalDisposable || _load_UniversalDisposable()).default(atom.commands.add(rootNode, { + 'core:move-up': this._selectPrev, + 'core:move-down': this._selectNext, + 'core:move-left': this._collapseNodeViaKeyboard, + 'core:move-right': this._expandNodeViaKeyboard, + 'core:confirm': () => this.state.focusedPath && this._handleConfirm(this.state.focusedPath) + }), _rxjsBundlesRxMinJs.Observable.merge(_rxjsBundlesRxMinJs.Observable.fromEvent(rootNode, 'focusin').mapTo(true), _rxjsBundlesRxMinJs.Observable.fromEvent(rootNode, 'focusout').mapTo(false)).subscribe(isFocused => this.setState({ isFocused }))); } componentWillUnmount() { @@ -89,130 +138,60 @@ export class Tree extends React.Component { componentWillReceiveProps() { this.setState((state, props) => ({ - focusedPath: props.selectedPaths[props.selectedPaths.length - 1], + focusedPath: props.selectedPaths[props.selectedPaths.length - 1] })); } - _selectNext = () => { - let nextNodePath; - if (this.state.focusedPath == null) { - nextNodePath = [0]; - } else { - nextNodePath = getNextNodePath( - this.props.items, - this.state.focusedPath, - this.props.collapsedPaths, - ); - } - if (nextNodePath != null) { - this.props.onSelect(nextNodePath); - this.setState({focusedPath: nextNodePath}); - } - }; - - _selectPrev = () => { - let prevNodePath; - if (this.state.focusedPath == null) { - prevNodePath = [0]; - } else { - prevNodePath = getPrevNodePath( - this.props.items, - this.state.focusedPath, - this.props.collapsedPaths, - ); - } - if (prevNodePath != null) { - this.props.onSelect(prevNodePath); - } - }; - - _collapseNodeViaKeyboard = (e: atom$CustomEvent) => { - if (this.state.focusedPath == null) { - return; - } - - let collapsablePath = [...this.state.focusedPath]; - let collapsableNode = selectNodeAtPath(this.props.items, collapsablePath); - while (collapsableNode != null && collapsableNode.type !== 'NESTED') { - collapsablePath = collapsablePath.slice(0, collapsablePath.length - 1); - collapsableNode = selectNodeAtPath(this.props.items, collapsablePath); - } - - if (collapsableNode == null) { - return; - } - - this.props.onCollapse(collapsablePath); - // if a descendant of this node was selected when this node was collapsed, - // moving selection to this node seems like intuitive behavior (see Chrome's - // Elements tree) - this.props.onSelect(collapsablePath); - }; - - _expandNodeViaKeyboard = (e: atom$CustomEvent) => { - const {focusedPath} = this.state; - if (focusedPath == null) { - return; - } - - const focusedNode = selectNodeAtPath(this.props.items, focusedPath); - if (focusedNode != null && focusedNode.type === 'NESTED') { - this.props.onExpand(focusedPath); - } - }; - - _handleSelect = (path: NodePath) => { - this.props.onSelect(path); - }; - - _handleConfirm = (path: NodePath) => { - this.props.onConfirm(path); - }; - render() { const { className, collapsedPaths, itemClassName, items: nodes, - selectedPaths, + selectedPaths } = this.props; - const {focusedPath, isFocused} = this.state; - - return ( -
    (this._rootNode = node)} - role="tree" - style={{position: 'relative'}} - tabIndex="0"> - {nodes.map((node, i) => ( - - ))} -
+ const { focusedPath, isFocused } = this.state; + + return _react.createElement( + 'ol', + { + className: (0, (_classnames || _load_classnames()).default)('list-tree', 'nuclide-selectable-tree', 'has-collapsable-children', className, { focused: isFocused }), + ref: node => this._rootNode = node, + role: 'tree', + style: { position: 'relative' }, + tabIndex: '0' }, + nodes.map((node, i) => _react.createElement(AbstractTreeItem, { + key: i, + node: node, + path: [i], + focusedPath: focusedPath, + collapsedPaths: collapsedPaths, + selectedPaths: selectedPaths, + className: itemClassName, + onSelect: this._handleSelect, + onConfirm: this._handleConfirm, + onTripleClick: this.props.onTripleClick, + onCollapse: this.props.onCollapse, + onExpand: this.props.onExpand + })) ); } } +exports.Tree = Tree; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +/* eslint-env browser */ + function AbstractTreeItem({ className, collapsedPaths, @@ -224,20 +203,8 @@ function AbstractTreeItem({ onExpand, node, path, - selectedPaths, -}: { - className: ?string, - collapsedPaths: Array, - focusedPath: ?NodePath, - onConfirm: (path: NodePath) => mixed, - onSelect: (path: NodePath) => mixed, - onTripleClick: (path: NodePath) => mixed, - onCollapse: (path: NodePath) => mixed, - onExpand: (path: NodePath) => mixed, - node: TreeNode, - path: NodePath, - selectedPaths: Array, -}): ?React.Element<*> { + selectedPaths +}) { if (node.hidden) { return null; } @@ -245,196 +212,172 @@ function AbstractTreeItem({ if (node.type === 'LEAF') { return ( // $FlowIgnore - - {node.label} - + _react.createElement( + TreeItem, + { + className: className, + isFocused: focusedPath && (0, (_collection || _load_collection()).arrayEqual)(focusedPath, path), + onConfirm: onConfirm, + onSelect: onSelect, + onTripleClick: onTripleClick, + path: path, + selectedPaths: selectedPaths }, + node.label + ) ); } const hasFlatChildren = node.children.every(child => child.type === 'LEAF'); return ( // $FlowIgnore - - {node.children.map((child, i) => { + _react.createElement( + NestedTreeItem, + { + className: className, + collapsed: false, + hasFlatChildren: hasFlatChildren, + focusedPath: focusedPath, + onConfirm: onConfirm, + onSelect: onSelect, + onTripleClick: onTripleClick, + onCollapse: onCollapse, + onExpand: onExpand, + path: path, + collapsedPaths: collapsedPaths, + selectedPaths: selectedPaths, + label: node.label }, + node.children.map((child, i) => { const childPath = path.concat([i]); - return ( - - ); - })} - + return _react.createElement(AbstractTreeItem, { + className: className, + collapsedPaths: collapsedPaths, + focusedPath: focusedPath, + key: childPath.join('.'), + node: child, + onConfirm: onConfirm, + onSelect: onSelect, + onTripleClick: onTripleClick, + onCollapse: onCollapse, + onExpand: onExpand, + path: childPath, + selectedPaths: selectedPaths + }); + }) + ) ); } -type TreeItemProps = {| - children?: React.Node, - className?: ?string, - isFocused: boolean, - onSelect: (path: NodePath) => mixed, - onConfirm: (path: NodePath) => mixed, - onTripleClick: (path: NodePath) => mixed, - path: NodePath, - selectedPaths: Array, -|}; - -class TreeItem extends React.Component { - _liNode: ?HTMLLIElement; - _handleClick = (e: SyntheticMouseEvent<>) => { - const {onSelect, onConfirm, onTripleClick} = this.props; - - const numberOfClicks = e.detail; - switch (numberOfClicks) { - case 1: - onSelect && onSelect(this.props.path); - break; - case 2: - onConfirm && onConfirm(this.props.path); - break; - case 3: - onTripleClick && onTripleClick(this.props.path); - break; - default: - break; - } - }; +class TreeItem extends _react.Component { + constructor(...args) { + var _temp2; + + return _temp2 = super(...args), this._handleClick = e => { + const { onSelect, onConfirm, onTripleClick } = this.props; + + const numberOfClicks = e.detail; + switch (numberOfClicks) { + case 1: + onSelect && onSelect(this.props.path); + break; + case 2: + onConfirm && onConfirm(this.props.path); + break; + case 3: + onTripleClick && onTripleClick(this.props.path); + break; + default: + break; + } + }, _temp2; + } scrollIntoView() { if (this._liNode != null) { - scrollIntoView(this._liNode); + (0, (_scrollIntoView || _load_scrollIntoView()).scrollIntoView)(this._liNode); } } render() { - const {className, isFocused, path, selectedPaths, children} = this.props; - const isSelected = selectedPaths.some(selectedPath => - shallowEqual(path, selectedPath), - ); - - return ( -
  • (this._liNode = liNode)} - role="treeitem"> - {isSelected && typeof children === 'string' ? ( - // String children must be wrapped to receive correct styles when selected. - {children} - ) : ( - children - )} -
  • + const { className, isFocused, path, selectedPaths, children } = this.props; + const isSelected = selectedPaths.some(selectedPath => (0, (_shallowequal || _load_shallowequal()).default)(path, selectedPath)); + + return _react.createElement( + 'li', + { + 'aria-activedescendant': isFocused, + 'aria-selected': isSelected, + className: (0, (_classnames || _load_classnames()).default)('list-item', className, { + selected: isSelected + }), + onClick: this._handleClick, + ref: liNode => this._liNode = liNode, + role: 'treeitem' }, + isSelected && typeof children === 'string' ? + // String children must be wrapped to receive correct styles when selected. + _react.createElement( + 'span', + null, + children + ) : children ); } } -type NestedTreeItemProps = { - label?: React.Node, - children?: React.Node, - className?: ?string, - hasFlatChildren?: boolean, // passthrough to inner TreeList - focusedPath: NodePath, - onSelect: (path: NodePath) => mixed, - onConfirm: (path: NodePath) => mixed, - onTripleClick: (path: NodePath) => mixed, - onCollapse: (path: NodePath) => mixed, - onExpand: (path: NodePath) => mixed, - path: NodePath, - selectedPaths: Array, - collapsedPaths: Array, -}; - -class NestedTreeItem extends React.Component { - _itemNode: ?HTMLDivElement; - _subscriptions: UniversalDisposable; - - _handleClick = (e: SyntheticMouseEvent<>) => { - const itemNode = this._itemNode; - if (itemNode == null) { - return; - } +class NestedTreeItem extends _react.Component { + constructor(...args) { + var _temp3; - invariant(e.target instanceof Element); - if (e.target.closest('.list-item') !== itemNode) { - // this was a click on a descendant node in the inner list - return; - } + return _temp3 = super(...args), this._handleClick = e => { + const itemNode = this._itemNode; + if (itemNode == null) { + return; + } - // TODO: This is gross. It assumes that the expand chevron is present in the - // `before` pseudoelement (as is with most themes), and measures the space - // it occupies using computed style properties, not actual measurements. - // The toggle chevron should be reimplemented as a true dom node instead, - // bypassing themes. Though this is more visually consistent, it's probably - // not worth the hassle. - const beforeStyle = window.getComputedStyle(this._itemNode, ':before'); - const itemStyle = window.getComputedStyle(this._itemNode); - const chevronWidth = - parsePx(itemStyle.paddingLeft) + - parsePx(beforeStyle.paddingLeft) + - parsePx(beforeStyle.paddingRight) + - parsePx(beforeStyle.marginLeft) + - parsePx(beforeStyle.marginRight) + - parsePx(beforeStyle.width) + - parsePx(beforeStyle.left); - - const {path, collapsedPaths} = this.props; - invariant(e.nativeEvent instanceof MouseEvent); - if (e.nativeEvent.offsetX <= chevronWidth) { - if ( - collapsedPaths.some(collapsedPath => arrayEqual(path, collapsedPath)) - ) { - this.props.onExpand(path); - } else { - this.props.onCollapse(path); + if (!(e.target instanceof Element)) { + throw new Error('Invariant violation: "e.target instanceof Element"'); } - return; - } - const {onSelect, onConfirm, onTripleClick} = this.props; - const numberOfClicks = e.detail; - if (numberOfClicks === 1 && onSelect != null) { - onSelect(path); - } else if (numberOfClicks === 2 && onConfirm != null) { - onConfirm(path); - } else if (numberOfClicks === 3 && onTripleClick != null) { - onTripleClick(path); - } - }; + if (e.target.closest('.list-item') !== itemNode) { + // this was a click on a descendant node in the inner list + return; + } + + // TODO: This is gross. It assumes that the expand chevron is present in the + // `before` pseudoelement (as is with most themes), and measures the space + // it occupies using computed style properties, not actual measurements. + // The toggle chevron should be reimplemented as a true dom node instead, + // bypassing themes. Though this is more visually consistent, it's probably + // not worth the hassle. + const beforeStyle = window.getComputedStyle(this._itemNode, ':before'); + const itemStyle = window.getComputedStyle(this._itemNode); + const chevronWidth = parsePx(itemStyle.paddingLeft) + parsePx(beforeStyle.paddingLeft) + parsePx(beforeStyle.paddingRight) + parsePx(beforeStyle.marginLeft) + parsePx(beforeStyle.marginRight) + parsePx(beforeStyle.width) + parsePx(beforeStyle.left); + + const { path, collapsedPaths } = this.props; + + if (!(e.nativeEvent instanceof MouseEvent)) { + throw new Error('Invariant violation: "e.nativeEvent instanceof MouseEvent"'); + } + + if (e.nativeEvent.offsetX <= chevronWidth) { + if (collapsedPaths.some(collapsedPath => (0, (_collection || _load_collection()).arrayEqual)(path, collapsedPath))) { + this.props.onExpand(path); + } else { + this.props.onCollapse(path); + } + return; + } + + const { onSelect, onConfirm, onTripleClick } = this.props; + const numberOfClicks = e.detail; + if (numberOfClicks === 1 && onSelect != null) { + onSelect(path); + } else if (numberOfClicks === 2 && onConfirm != null) { + onConfirm(path); + } else if (numberOfClicks === 3 && onTripleClick != null) { + onTripleClick(path); + } + }, _temp3; + } render() { const { @@ -445,56 +388,55 @@ class NestedTreeItem extends React.Component { collapsedPaths, path, label, - children, + children } = this.props; - const isFocused = focusedPath && arrayEqual(path, focusedPath); - const isSelected = selectedPaths.some(selectedPath => - shallowEqual(path, selectedPath), - ); - const isCollapsed = collapsedPaths.some(collapsedPath => - shallowEqual(path, collapsedPath), - ); - - return ( -
  • (0, (_shallowequal || _load_shallowequal()).default)(path, selectedPath)); + const isCollapsed = collapsedPaths.some(collapsedPath => (0, (_shallowequal || _load_shallowequal()).default)(path, collapsedPath)); + + return _react.createElement( + 'li', + { + 'aria-activedescendant': isFocused, + 'aria-selected': isSelected, + 'aria-expanded': !isCollapsed, + className: (0, (_classnames || _load_classnames()).default)('list-nested-item', className, { collapsed: isCollapsed, - selected: isSelected, - })} - onClick={this._handleClick} - role="treeitem"> - {label == null ? null : ( -
    (this._itemNode = node)}> - {label} -
    - )} - {children} -
  • + selected: isSelected + }), + onClick: this._handleClick, + role: 'treeitem' }, + label == null ? null : _react.createElement( + 'div', + { className: 'list-item', ref: node => this._itemNode = node }, + label + ), + _react.createElement( + (_Tree || _load_Tree()).TreeList, + { hasFlatChildren: hasFlatChildren }, + children + ) ); } } -function selectNodeAtPath(roots: Array, path: NodePath): ?TreeNode { +function selectNodeAtPath(roots, path) { if (path.length === 0) { return; } let node = roots[path[0]]; for (let i = 1; i < path.length; i++) { - invariant(node.type === 'NESTED'); + if (!(node.type === 'NESTED')) { + throw new Error('Invariant violation: "node.type === \'NESTED\'"'); + } + node = node.children[path[i]]; } return node; } -function getNextNodePath( - roots: Array, - path: NodePath, - collapsedPaths: Array, -): ?NodePath { +function getNextNodePath(roots, path, collapsedPaths) { if (path.length === 0) { return null; } @@ -504,18 +446,13 @@ function getNextNodePath( return; } - if ( - currentNode.type === 'NESTED' && - currentNode.children.length > 0 && - // don't traverse children of collapsed nodes - !collapsedPaths.find(collapsedPath => arrayEqual(collapsedPath, path)) - ) { + if (currentNode.type === 'NESTED' && currentNode.children.length > 0 && + // don't traverse children of collapsed nodes + !collapsedPaths.find(collapsedPath => (0, (_collection || _load_collection()).arrayEqual)(collapsedPath, path))) { // 'down' was pressed on a nested item. most of the time we want go to its // first child, but we need to make sure it's not hidden (eg filtered by // a search) first - const firstVisibleChildIndex = currentNode.children.findIndex( - n => !n.hidden, - ); + const firstVisibleChildIndex = currentNode.children.findIndex(n => !n.hidden); if (firstVisibleChildIndex >= 0) { return path.concat([firstVisibleChildIndex]); } @@ -524,11 +461,7 @@ function getNextNodePath( return findNextSibling(roots, path, collapsedPaths); } -function findNextSibling( - roots: Array, - path: NodePath, - collapsedPaths: Array, -): ?NodePath { +function findNextSibling(roots, path, collapsedPaths) { if (path.length === 0) { return null; } @@ -549,11 +482,7 @@ function findNextSibling( return findNextSibling(roots, leadingIndexes, collapsedPaths); } -function getPrevNodePath( - roots: Array, - path: NodePath, - collapsedPaths: Array, -): ?NodePath { +function getPrevNodePath(roots, path, collapsedPaths) { if (path.length === 0) { return null; } @@ -567,21 +496,13 @@ function getPrevNodePath( return getPrevNodePath(roots, prevSiblingPath, collapsedPaths); } - if ( - prevSibling.type === 'NESTED' && - prevSibling.children.length > 0 && - // don't traverse children of collapsed nodes - !collapsedPaths.find(collapsedPath => - arrayEqual(collapsedPath, prevSiblingPath), - ) - ) { + if (prevSibling.type === 'NESTED' && prevSibling.children.length > 0 && + // don't traverse children of collapsed nodes + !collapsedPaths.find(collapsedPath => (0, (_collection || _load_collection()).arrayEqual)(collapsedPath, prevSiblingPath))) { // pressed 'up' on a node just after an expanded nested item. Normally this // should take us to the last item inside the expanded node, but some may // be hidden. Find the last in the list that's visible. - const lastVisibleChildIndex = arrayFindLastIndex( - prevSibling.children, - n => !n.hidden, - ); + const lastVisibleChildIndex = (0, (_collection || _load_collection()).arrayFindLastIndex)(prevSibling.children, n => !n.hidden); if (lastVisibleChildIndex >= 0) { return prevSiblingPath.concat([lastVisibleChildIndex]); } @@ -596,6 +517,6 @@ function getPrevNodePath( } } -function parsePx(px: string): number { +function parsePx(px) { return px.length === 0 ? 0 : Number(px.replace('px', '')); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SettingsCheckbox.js b/modules/nuclide-commons-ui/SettingsCheckbox.js index 1c941e74..45a7274d 100644 --- a/modules/nuclide-commons-ui/SettingsCheckbox.js +++ b/modules/nuclide-commons-ui/SettingsCheckbox.js @@ -1,50 +1,70 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {SettingsPropsDefault} from './SettingsUtils'; - -import {normalizeIdentifier} from './SettingsUtils'; -import * as React from 'react'; - -type Props = SettingsPropsDefault & { - value: boolean, -}; - -export default class SettingsCheckbox extends React.Component { - _handleChange = (event: SyntheticEvent<>) => { - const isChecked = ((event.target: any): HTMLInputElement).checked; - this.props.onChange(isChecked); - }; - - render(): React.Node { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _SettingsUtils; + +function _load_SettingsUtils() { + return _SettingsUtils = require('./SettingsUtils'); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +class SettingsCheckbox extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._handleChange = event => { + const isChecked = event.target.checked; + this.props.onChange(isChecked); + }, _temp; + } + + render() { const keyPath = this.props.keyPath; - const id = normalizeIdentifier(keyPath); + const id = (0, (_SettingsUtils || _load_SettingsUtils()).normalizeIdentifier)(keyPath); const title = this.props.title; const description = this.props.description; const value = this.props.value; - return ( -
    - -
    {description}
    -
    + return _react.createElement( + 'div', + { className: 'checkbox' }, + _react.createElement( + 'label', + { htmlFor: id }, + _react.createElement('input', { + checked: value, + id: id, + onChange: this._handleChange, + type: 'checkbox' + }), + _react.createElement( + 'div', + { className: 'setting-title' }, + title + ) + ), + _react.createElement( + 'div', + { className: 'setting-description' }, + description + ) ); } } +exports.default = SettingsCheckbox; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SettingsControl.js b/modules/nuclide-commons-ui/SettingsControl.js index 2984011d..b11bc3ec 100644 --- a/modules/nuclide-commons-ui/SettingsControl.js +++ b/modules/nuclide-commons-ui/SettingsControl.js @@ -1,3 +1,34 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = SettingsControl; + +var _SettingsCheckbox; + +function _load_SettingsCheckbox() { + return _SettingsCheckbox = _interopRequireDefault(require('./SettingsCheckbox')); +} + +var _SettingsInput; + +function _load_SettingsInput() { + return _SettingsInput = _interopRequireDefault(require('./SettingsInput')); +} + +var _SettingsSelect; + +function _load_SettingsSelect() { + return _SettingsSelect = _interopRequireDefault(require('./SettingsSelect')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,80 +37,73 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import SettingsCheckbox from './SettingsCheckbox'; -import SettingsInput from './SettingsInput'; -import SettingsSelect from './SettingsSelect'; -import invariant from 'assert'; -import * as React from 'react'; - -type Props = { - keyPath: string, - schema: atom$ConfigSchema, - value: any, - onChange: (value: any) => mixed, -}; - -export default function SettingsControl(props: Props): ?React.Element { - const {keyPath, value, onChange, schema} = props; - const {description, title} = schema; +function SettingsControl(props) { + const { keyPath, value, onChange, schema } = props; + const { description, title } = schema; if (schema) { if (schema.enum) { return ( // $FlowFixMe(>=0.53.0) Flow suppress - + _react.createElement((_SettingsSelect || _load_SettingsSelect()).default, { + description: description, + keyPath: keyPath, + onChange: onChange, + title: title, + value: value + }) ); } else if (schema.type === 'color') { - invariant(false); // Not implemented. + if (!false) { + throw new Error('Invariant violation: "false"'); + } // Not implemented. + } else if (isBoolean(value) || schema.type === 'boolean') { return ( // $FlowFixMe(>=0.53.0) Flow suppress - + _react.createElement((_SettingsCheckbox || _load_SettingsCheckbox()).default, { + description: description, + keyPath: keyPath, + onChange: onChange, + title: title, + value: value + }) ); } else if (Array.isArray(value) || schema.type === 'array') { if (isEditableArray(value)) { return ( // $FlowFixMe(>=0.53.0) Flow suppress - + _react.createElement((_SettingsInput || _load_SettingsInput()).default, { + description: description, + keyPath: keyPath, + onChange: onChange, + title: title, + value: value, + type: 'array' + }) ); } } else if (isObject(value) || schema.type === 'object') { - invariant(false); // Not implemented. + if (!false) { + throw new Error('Invariant violation: "false"'); + } // Not implemented. + } else { const type = isNumber(value) ? 'number' : 'string'; return ( // $FlowFixMe(>=0.53.0) Flow suppress - + _react.createElement((_SettingsInput || _load_SettingsInput()).default, { + description: description, + keyPath: keyPath, + onChange: onChange, + title: title, + value: value, + type: type + }) ); } } @@ -88,9 +112,7 @@ export default function SettingsControl(props: Props): ?React.Element { } function isBoolean(obj) { - return ( - obj === true || obj === false || toString.call(obj) === '[object Boolean]' - ); + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; } function isNumber(obj) { @@ -99,10 +121,10 @@ function isNumber(obj) { function isObject(obj) { const type = typeof obj; - return type === 'function' || (type === 'object' && Boolean(obj)); + return type === 'function' || type === 'object' && Boolean(obj); } -function isEditableArray(array): boolean { +function isEditableArray(array) { for (let i = 0, len = array.length; i < len; i++) { const item = array[i]; if (typeof item !== 'string') { @@ -110,4 +132,4 @@ function isEditableArray(array): boolean { } } return true; -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SettingsInput.js b/modules/nuclide-commons-ui/SettingsInput.js index c503d41a..650af6ee 100644 --- a/modules/nuclide-commons-ui/SettingsInput.js +++ b/modules/nuclide-commons-ui/SettingsInput.js @@ -1,81 +1,80 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {SettingsPropsDefault} from './SettingsUtils'; - -import invariant from 'assert'; -import {AtomInput} from './AtomInput'; -import * as React from 'react'; -import { - isDefaultConfigValue, - getDefaultConfigValueString, - normalizeIdentifier, - parseValue, - valueToString, -} from './SettingsUtils'; - -type Props = SettingsPropsDefault & { - type: string, - value: number | string | Array, -}; - -export default class SettingsInput extends React.Component { - _ignoreInputCallback: boolean; - _input: ?AtomInput; - - constructor(props: Object) { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _AtomInput; + +function _load_AtomInput() { + return _AtomInput = require('./AtomInput'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _SettingsUtils; + +function _load_SettingsUtils() { + return _SettingsUtils = require('./SettingsUtils'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +class SettingsInput extends _react.Component { + + constructor(props) { super(props); + + this._handleChange = newValue_ => { + let newValue = newValue_; + if (this._ignoreInputCallback) { + return; + } + + newValue = (0, (_SettingsUtils || _load_SettingsUtils()).parseValue)(this.props.type, newValue); + this.props.onChange(newValue); + }; + + this._onFocus = () => { + const keyPath = this.props.keyPath; + const input = this._input; + + if (!(input != null)) { + throw new Error('Invariant violation: "input != null"'); + } + + if ((0, (_SettingsUtils || _load_SettingsUtils()).isDefaultConfigValue)(keyPath)) { + const defaultValue = (0, (_SettingsUtils || _load_SettingsUtils()).getDefaultConfigValueString)(keyPath); + this._updateInput(input, defaultValue); + } + }; + + this._onBlur = () => { + const keyPath = this.props.keyPath; + const input = this._input; + + if (!(input != null)) { + throw new Error('Invariant violation: "input != null"'); + } + + if ((0, (_SettingsUtils || _load_SettingsUtils()).isDefaultConfigValue)(keyPath, input.getText())) { + this._updateInput(input, ''); + } + }; + this._ignoreInputCallback = false; } - _updateInput(input: AtomInput, newValue: string) { + _updateInput(input, newValue) { this._ignoreInputCallback = true; input.setText(newValue); this._ignoreInputCallback = false; } - _handleChange = (newValue_: string) => { - let newValue = newValue_; - if (this._ignoreInputCallback) { - return; - } - - newValue = parseValue(this.props.type, newValue); - this.props.onChange(newValue); - }; - - _onFocus = () => { - const keyPath = this.props.keyPath; - const input = this._input; - invariant(input != null); - if (isDefaultConfigValue(keyPath)) { - const defaultValue = getDefaultConfigValueString(keyPath); - this._updateInput(input, defaultValue); - } - }; + _getValue() { + let value = (0, (_SettingsUtils || _load_SettingsUtils()).valueToString)(this.props.value); - _onBlur = () => { - const keyPath = this.props.keyPath; - const input = this._input; - invariant(input != null); - if (isDefaultConfigValue(keyPath, input.getText())) { - this._updateInput(input, ''); - } - }; - - _getValue(): string { - let value = valueToString(this.props.value); - - const defaultValue = getDefaultConfigValueString(this.props.keyPath); + const defaultValue = (0, (_SettingsUtils || _load_SettingsUtils()).getDefaultConfigValueString)(this.props.keyPath); if (defaultValue === value) { value = ''; } @@ -83,53 +82,84 @@ export default class SettingsInput extends React.Component { return value; } - _getPlaceholder(): string { - const defaultValue = getDefaultConfigValueString(this.props.keyPath); + _getPlaceholder() { + const defaultValue = (0, (_SettingsUtils || _load_SettingsUtils()).getDefaultConfigValueString)(this.props.keyPath); return defaultValue ? 'Default: ' + defaultValue : ''; } - componentDidUpdate(prevProps: Props): void { + componentDidUpdate(prevProps) { const input = this._input; - invariant(input != null); + + if (!(input != null)) { + throw new Error('Invariant violation: "input != null"'); + } + const value = this._getValue(); if (input.getText() !== value) { this._updateInput(input, value); } } - render(): React.Node { + render() { const keyPath = this.props.keyPath; - const id = normalizeIdentifier(keyPath); + const id = (0, (_SettingsUtils || _load_SettingsUtils()).normalizeIdentifier)(keyPath); const title = this.props.title; const description = this.props.description; const value = this._getValue(); const placeholder = this._getPlaceholder(); - return ( -
    - -
    -
    - - { - this._input = input; - }} - text={value} - /> - -
    -
    -
    + return _react.createElement( + 'div', + null, + _react.createElement( + 'label', + { className: 'control-label' }, + _react.createElement( + 'div', + { className: 'setting-title' }, + title + ), + _react.createElement( + 'div', + { className: 'setting-description' }, + description + ) + ), + _react.createElement( + 'div', + { className: 'controls' }, + _react.createElement( + 'div', + { className: 'editor-container' }, + _react.createElement( + 'subview', + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + className: id, + initialValue: value, + onDidChange: this._handleChange, + onFocus: this._onFocus, + onBlur: this._onBlur, + placeholderText: placeholder, + ref: input => { + this._input = input; + }, + text: value + }) + ) + ) + ) ); } } +exports.default = SettingsInput; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SettingsSelect.js b/modules/nuclide-commons-ui/SettingsSelect.js index 30edf8ab..eb1374c6 100644 --- a/modules/nuclide-commons-ui/SettingsSelect.js +++ b/modules/nuclide-commons-ui/SettingsSelect.js @@ -1,3 +1,27 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _featureConfig; + +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); +} + +var _SettingsUtils; + +function _load_SettingsUtils() { + return _SettingsUtils = require('./SettingsUtils'); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,63 +30,69 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {SettingsPropsDefault} from './SettingsUtils'; +class SettingsSelect extends _react.Component { + constructor(...args) { + var _temp; -import featureConfig from 'nuclide-commons-atom/feature-config'; -import {normalizeIdentifier} from './SettingsUtils'; -import * as React from 'react'; - -type Props = SettingsPropsDefault & { - value: number, -}; - -export default class SettingsSelect extends React.Component { - _handleChange = (event: SyntheticEvent<>) => { - const value = ((event.target: any): HTMLInputElement).value; - this.props.onChange(value); - }; + return _temp = super(...args), this._handleChange = event => { + const value = event.target.value; + this.props.onChange(value); + }, _temp; + } - render(): React.Node { + render() { const keyPath = this.props.keyPath; - const id = normalizeIdentifier(keyPath); + const id = (0, (_SettingsUtils || _load_SettingsUtils()).normalizeIdentifier)(keyPath); const title = this.props.title; const description = this.props.description; const value = this.props.value; - const options = featureConfig.getSchema(keyPath); + const options = (_featureConfig || _load_featureConfig()).default.getSchema(keyPath); const optionElements = []; if (options.enum) { options.enum.forEach((option, i) => { const optionValue = typeof option === 'object' ? option.value : option; - const optionDescription = - typeof option === 'object' ? option.description : option; - optionElements.push( - , - ); + const optionDescription = typeof option === 'object' ? option.description : option; + optionElements.push(_react.createElement( + 'option', + { value: optionValue, key: i }, + optionDescription + )); }); } - return ( -
    - - -
    + return _react.createElement( + 'div', + null, + _react.createElement( + 'label', + { className: 'control-label' }, + _react.createElement( + 'div', + { className: 'setting-title' }, + title + ), + _react.createElement( + 'div', + { className: 'setting-description' }, + description + ) + ), + _react.createElement( + 'select', + { + className: 'form-control', + id: id, + onChange: this._handleChange, + value: value }, + optionElements + ) ); } } +exports.default = SettingsSelect; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SettingsUtils.js b/modules/nuclide-commons-ui/SettingsUtils.js index d670a692..eadea605 100644 --- a/modules/nuclide-commons-ui/SettingsUtils.js +++ b/modules/nuclide-commons-ui/SettingsUtils.js @@ -1,34 +1,43 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import featureConfig from 'nuclide-commons-atom/feature-config'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.normalizeIdentifier = normalizeIdentifier; +exports.isDefaultConfigValue = isDefaultConfigValue; +exports.getDefaultConfigValue = getDefaultConfigValue; +exports.getDefaultConfigValueString = getDefaultConfigValueString; +exports.parseValue = parseValue; +exports.valueToString = valueToString; -export type SettingsPropsDefault = { - title: string, - description: string, - keyPath: string, - onChange: (value: any) => mixed, -}; +var _featureConfig; -function getConfigValueString(keyPath: string): string { - const value = featureConfig.get(keyPath); - return valueToString(value); +function _load_featureConfig() { + return _featureConfig = _interopRequireDefault(require('nuclide-commons-atom/feature-config')); } -export function normalizeIdentifier(id: string): string { +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function getConfigValueString(keyPath) { + const value = (_featureConfig || _load_featureConfig()).default.get(keyPath); + return valueToString(value); +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function normalizeIdentifier(id) { return id.replace(/[^A-Za-z0-9_-]/g, '_'); } -export function isDefaultConfigValue(keyPath: string, value_: ?any): boolean { +function isDefaultConfigValue(keyPath, value_) { let value = value_; const defaultValue = getDefaultConfigValueString(keyPath); if (value) { @@ -39,16 +48,16 @@ export function isDefaultConfigValue(keyPath: string, value_: ?any): boolean { return !value || defaultValue === value; } -export function getDefaultConfigValue(keyPath: string): mixed { - const params = {excludeSources: [atom.config.getUserConfigPath()]}; - return featureConfig.get(keyPath, params); +function getDefaultConfigValue(keyPath) { + const params = { excludeSources: [atom.config.getUserConfigPath()] }; + return (_featureConfig || _load_featureConfig()).default.get(keyPath, params); } -export function getDefaultConfigValueString(keyPath: string): string { +function getDefaultConfigValueString(keyPath) { return valueToString(getDefaultConfigValue(keyPath)); } -export function parseValue(type: string, value: any): any { +function parseValue(type, value) { let result = value; if (value === '') { result = undefined; @@ -64,10 +73,10 @@ export function parseValue(type: string, value: any): any { return result; } -export function valueToString(value: any): string { +function valueToString(value) { if (Array.isArray(value)) { return value.join(', '); } else { return value != null ? value.toString() : ''; } -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/SimpleValueComponent.js b/modules/nuclide-commons-ui/SimpleValueComponent.js index efab921e..8280c314 100644 --- a/modules/nuclide-commons-ui/SimpleValueComponent.js +++ b/modules/nuclide-commons-ui/SimpleValueComponent.js @@ -1,3 +1,26 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.STRING_REGEX = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _ValueComponentClassNames; + +function _load_ValueComponentClassNames() { + return _ValueComponentClassNames = require('./ValueComponentClassNames'); +} + +var _TextRenderer; + +function _load_TextRenderer() { + return _TextRenderer = require('./TextRenderer'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,102 +29,93 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ // TODO @jxg export debugger typedefs from main module. (t11406963) -import type {EvaluationResult} from './TextRenderer'; - -import * as React from 'react'; -import {ValueComponentClassNames} from './ValueComponentClassNames'; -import {TextRenderer} from './TextRenderer'; - -type Props = { - expression: ?string, - evaluationResult: EvaluationResult, -}; - const booleanRegex = /^true|false$/i; -export const STRING_REGEX = /^(['"]).*\1$/; - -function renderNullish( - evaluationResult: EvaluationResult, -): ?React.Element { - const {type} = evaluationResult; - return type === 'undefined' || type === 'null' ? ( - {type} +const STRING_REGEX = exports.STRING_REGEX = /^(['"]).*\1$/; + +function renderNullish(evaluationResult) { + const { type } = evaluationResult; + return type === 'undefined' || type === 'null' ? _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.nullish }, + type ) : null; } -function renderString(evaluationResult: EvaluationResult): ?React.Element { - const {type, value} = evaluationResult; +function renderString(evaluationResult) { + const { type, value } = evaluationResult; if (value == null) { return null; } if (STRING_REGEX.test(value)) { - return {value}; + return _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.string }, + value + ); } else if (type === 'string') { - return ( - - " - {value} - " - + return _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.string }, + _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.stringOpeningQuote }, + '"' + ), + value, + _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.stringClosingQuote }, + '"' + ) ); } else { return null; } } -function renderNumber(evaluationResult: EvaluationResult): ?React.Element { - const {type, value} = evaluationResult; +function renderNumber(evaluationResult) { + const { type, value } = evaluationResult; if (value == null) { return null; } - return type === 'number' || !isNaN(Number(value)) ? ( - {String(value)} + return type === 'number' || !isNaN(Number(value)) ? _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.number }, + String(value) ) : null; } -function renderBoolean( - evaluationResult: EvaluationResult, -): ?React.Element { - const {type, value} = evaluationResult; +function renderBoolean(evaluationResult) { + const { type, value } = evaluationResult; if (value == null) { return null; } - return type === 'boolean' || booleanRegex.test(value) ? ( - {String(value)} + return type === 'boolean' || booleanRegex.test(value) ? _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.boolean }, + String(value) ) : null; } -function renderDefault(evaluationResult: EvaluationResult): ?string { +function renderDefault(evaluationResult) { return evaluationResult.value; } -const valueRenderers = [ - TextRenderer, - renderString, - renderNumber, - renderNullish, - renderBoolean, - renderDefault, -]; - -export default class SimpleValueComponent extends React.Component { - shouldComponentUpdate(nextProps: Props): boolean { - const {expression, evaluationResult} = this.props; - return ( - expression !== nextProps.expression || - evaluationResult.type !== nextProps.evaluationResult.type || - evaluationResult.value !== nextProps.evaluationResult.value || - evaluationResult.description !== nextProps.evaluationResult.description - ); +const valueRenderers = [(_TextRenderer || _load_TextRenderer()).TextRenderer, renderString, renderNumber, renderNullish, renderBoolean, renderDefault]; + +class SimpleValueComponent extends _react.Component { + shouldComponentUpdate(nextProps) { + const { expression, evaluationResult } = this.props; + return expression !== nextProps.expression || evaluationResult.type !== nextProps.evaluationResult.type || evaluationResult.value !== nextProps.evaluationResult.value || evaluationResult.description !== nextProps.evaluationResult.description; } - render(): React.Node { - const {expression, evaluationResult} = this.props; + render() { + const { expression, evaluationResult } = this.props; let displayValue; for (const renderer of valueRenderers) { displayValue = renderer(evaluationResult); @@ -114,22 +128,26 @@ export default class SimpleValueComponent extends React.Component { displayValue = evaluationResult.description || '(N/A)'; } if (expression == null) { - return ( - - {displayValue} - + return _react.createElement( + 'span', + { tabIndex: -1, className: 'native-key-bindings' }, + displayValue ); } // TODO @jxg use a text editor to apply proper syntax highlighting for expressions // (t11408154) - const renderedExpression = ( - {expression} + const renderedExpression = _react.createElement( + 'span', + { className: (_ValueComponentClassNames || _load_ValueComponentClassNames()).ValueComponentClassNames.identifier }, + expression ); - return ( - - {renderedExpression} - : {displayValue} - + return _react.createElement( + 'span', + { tabIndex: -1, className: 'native-key-bindings' }, + renderedExpression, + ': ', + displayValue ); } } +exports.default = SimpleValueComponent; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/StyleSheet.js b/modules/nuclide-commons-ui/StyleSheet.js index 857ddc99..49504457 100644 --- a/modules/nuclide-commons-ui/StyleSheet.js +++ b/modules/nuclide-commons-ui/StyleSheet.js @@ -1,52 +1,52 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import * as React from 'react'; - -type Props = { - sourcePath: string, - priority: number, - css: string, -}; - -export default class StyleSheet extends React.PureComponent { - _styleSheet: IDisposable; - - componentWillUnmount(): void { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +class StyleSheet extends _react.PureComponent { + + componentWillUnmount() { if (this._styleSheet != null) { this._styleSheet.dispose(); } } - componentDidMount(): void { + componentDidMount() { this._updateStyleSheet(); } - componentDidUpdate(): void { + componentDidUpdate() { this._updateStyleSheet(); } - render(): ?React.Element { + render() { return null; } - _updateStyleSheet(): void { + _updateStyleSheet() { if (this._styleSheet != null) { this._styleSheet.dispose(); } this._styleSheet = atom.styles.addStyleSheet(this.props.css, { sourcePath: this.props.sourcePath, - priority: this.props.priority, + priority: this.props.priority }); } } +exports.default = StyleSheet; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/TabbableContainer.example.js b/modules/nuclide-commons-ui/TabbableContainer.example.js index dc501117..d04ec2fb 100644 --- a/modules/nuclide-commons-ui/TabbableContainer.example.js +++ b/modules/nuclide-commons-ui/TabbableContainer.example.js @@ -1,3 +1,46 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TabbableContainerExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _AtomInput; + +function _load_AtomInput() { + return _AtomInput = require('./AtomInput'); +} + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); +} + +var _RadioGroup; + +function _load_RadioGroup() { + return _RadioGroup = _interopRequireDefault(require('./RadioGroup')); +} + +var _TabbableContainer; + +function _load_TabbableContainer() { + return _TabbableContainer = _interopRequireDefault(require('./TabbableContainer')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,111 +49,119 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import * as React from 'react'; -import {AtomInput} from './AtomInput'; -import {Block} from './Block'; -import {Button} from './Button'; -import RadioGroup from './RadioGroup'; -import TabbableContainer from './TabbableContainer'; - const labels = ['radio 1', 'radio 2', 'radio 3']; -class FormExample extends React.Component { - constructor(props: any) { +class FormExample extends _react.Component { + constructor(props) { super(props); + + this.onSelectedChange = selectedIndex => { + this.setState({ + selectedIndex + }); + }; + this.state = { - selectedIndex: 0, + selectedIndex: 0 }; } - onSelectedChange = (selectedIndex: number): void => { - this.setState({ - selectedIndex, - }); - }; - - render(): React.Node { - return ( -
    - - - - - - - - - - - - - - - - - - - - -
    + render() { + return _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + disabled: false, + initialValue: 'input field 1', + placeholderText: 'placeholder text' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + disabled: false, + initialValue: 'input field 2', + placeholderText: 'placeholder text' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + disabled: false, + initialValue: 'input field 3', + placeholderText: 'placeholder text' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_RadioGroup || _load_RadioGroup()).default, { + selectedIndex: this.state.selectedIndex, + optionLabels: labels, + onSelectedChange: this.onSelectedChange + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + disabled: false, + initialValue: 'input field 4', + placeholderText: 'placeholder text' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', size: 'SMALL' }, + 'button 1' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', size: 'SMALL' }, + 'button 2' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { className: 'inline-block', size: 'SMALL' }, + 'button 3' + ) + ) ); } } -const ContainedTabbableContainerExample = (): React.Element => ( - - - +const ContainedTabbableContainerExample = () => _react.createElement( + (_TabbableContainer || _load_TabbableContainer()).default, + { contained: true }, + _react.createElement(FormExample, null) ); -const UncontainedTabbableContainerExample = (): React.Element => ( - - - +const UncontainedTabbableContainerExample = () => _react.createElement( + (_TabbableContainer || _load_TabbableContainer()).default, + { contained: false }, + _react.createElement(FormExample, null) ); -export const TabbableContainerExamples = { +const TabbableContainerExamples = exports.TabbableContainerExamples = { sectionName: 'TabbableContainer', - description: - 'Allows tabbing and shift-tabbing to change the focus of the inputs.', - examples: [ - { - title: 'Contained (focus will be contained in this section)', - component: ContainedTabbableContainerExample, - }, - { - title: 'Uncontained', - component: UncontainedTabbableContainerExample, - }, - ], -}; + description: 'Allows tabbing and shift-tabbing to change the focus of the inputs.', + examples: [{ + title: 'Contained (focus will be contained in this section)', + component: ContainedTabbableContainerExample + }, { + title: 'Uncontained', + component: UncontainedTabbableContainerExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/TabbableContainer.js b/modules/nuclide-commons-ui/TabbableContainer.js index ffbe187d..2f163305 100644 --- a/modules/nuclide-commons-ui/TabbableContainer.js +++ b/modules/nuclide-commons-ui/TabbableContainer.js @@ -1,3 +1,39 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireDefault(require('react')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _tabbable; + +function _load_tabbable() { + return _tabbable = _interopRequireDefault(require('tabbable')); +} + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const TABBABLE_CLASS_NAME = 'nuclide-tabbable'; + +/** + * Enables focusing between inputs with tab and shift-tab. Can also be used to + * trap focus within the container by using the contained property. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,102 +42,77 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ /* eslint-env browser */ -import React from 'react'; -import invariant from 'assert'; -import {Observable} from 'rxjs'; -import tabbable from 'tabbable'; -import classnames from 'classnames'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; - -type DefaultProps = { - contained: boolean, -}; - -type Props = { - children?: React$Node, - contained: boolean, - className?: string, -}; - -const TABBABLE_CLASS_NAME = 'nuclide-tabbable'; - -/** - * Enables focusing between inputs with tab and shift-tab. Can also be used to - * trap focus within the container by using the contained property. - */ -export default class TabbableContainer extends React.Component { - _disposables: UniversalDisposable; - _rootNode: ?HTMLDivElement; - - static defaultProps: DefaultProps = { - contained: false, - autoFocus: false, - }; +class TabbableContainer extends _react.default.Component { componentDidMount() { const rootNode = this._rootNode; - invariant(rootNode != null); + + if (!(rootNode != null)) { + throw new Error('Invariant violation: "rootNode != null"'); + } // If focus has been deliberately set inside the container, don't try // to override it + + if (!rootNode.contains(document.activeElement)) { - const tabbableElements = tabbable(rootNode); + const tabbableElements = (0, (_tabbable || _load_tabbable()).default)(rootNode); const firstTabbableElement = tabbableElements[0]; if (firstTabbableElement != null) { firstTabbableElement.focus(); } } - this._disposables = new UniversalDisposable( - Observable.fromEvent(rootNode, 'keydown').subscribe( - (event: KeyboardEvent) => { - if (event.altKey || event.ctrlKey || event.metaKey) { - return; - } - - if (event.key === 'Tab') { - if (event.shiftKey) { - focusPrevious(); - } else { - focusNext(); - } - event.preventDefault(); - event.stopPropagation(); - } - }, - ), - ); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(_rxjsBundlesRxMinJs.Observable.fromEvent(rootNode, 'keydown').subscribe(event => { + if (event.altKey || event.ctrlKey || event.metaKey) { + return; + } + + if (event.key === 'Tab') { + if (event.shiftKey) { + focusPrevious(); + } else { + focusNext(); + } + event.preventDefault(); + event.stopPropagation(); + } + })); } componentWillUnmount() { this._disposables.dispose(); } - render(): React$Node { - return ( -
    (this._rootNode = node)}> - {this.props.children} -
    + render() { + return _react.default.createElement( + 'div', + { + className: (0, (_classnames || _load_classnames()).default)(TABBABLE_CLASS_NAME, this.props.className), + 'data-contained': this.props.contained, + ref: node => this._rootNode = node }, + this.props.children ); } } -function focusNext(): void { +exports.default = TabbableContainer; +TabbableContainer.defaultProps = { + contained: false, + autoFocus: false +}; +function focusNext() { const currentElement = getFocusedElement(); if (!(currentElement instanceof HTMLElement)) { return; } - const focusedTabIndex = - currentElement.tabIndex >= 0 ? currentElement.tabIndex : -Infinity; + const focusedTabIndex = currentElement.tabIndex >= 0 ? currentElement.tabIndex : -Infinity; let nextElement = null; let nextTabIndex = Infinity; @@ -111,34 +122,27 @@ function focusNext(): void { let container = findParentElement(currentElement, element => { return element.classList.contains(TABBABLE_CLASS_NAME); }); - if ( - container instanceof HTMLElement && - container.dataset.contained === 'false' - ) { + if (container instanceof HTMLElement && container.dataset.contained === 'false') { container = null; } - eachTabIndexedElement( - currentElement, - false /* reverse */, - (element, tabIndex) => { - if (tabIndex < lowestTabIndex) { - lowestTabIndex = tabIndex; - lowestElement = element; - } + eachTabIndexedElement(currentElement, false /* reverse */ + , (element, tabIndex) => { + if (tabIndex < lowestTabIndex) { + lowestTabIndex = tabIndex; + lowestElement = element; + } - if (focusedTabIndex <= tabIndex && tabIndex < nextTabIndex) { - nextTabIndex = tabIndex; - nextElement = element; - if (focusedTabIndex === tabIndex || focusedTabIndex + 1 === tabIndex) { - return true; // doneSearching - } + if (focusedTabIndex <= tabIndex && tabIndex < nextTabIndex) { + nextTabIndex = tabIndex; + nextElement = element; + if (focusedTabIndex === tabIndex || focusedTabIndex + 1 === tabIndex) { + return true; // doneSearching } + } - return false; // doneSearching - }, - container, - ); + return false; // doneSearching + }, container); if (nextElement) { nextElement.focus(); @@ -147,13 +151,12 @@ function focusNext(): void { } } -function focusPrevious(): void { +function focusPrevious() { const currentElement = getFocusedElement(); if (!(currentElement instanceof HTMLElement)) { return; } - const focusedTabIndex = - currentElement.tabIndex >= 0 ? currentElement.tabIndex : Infinity; + const focusedTabIndex = currentElement.tabIndex >= 0 ? currentElement.tabIndex : Infinity; let previousElement = null; let previousTabIndex = -Infinity; @@ -163,34 +166,27 @@ function focusPrevious(): void { let container = findParentElement(currentElement, element => { return element.classList.contains(TABBABLE_CLASS_NAME); }); - if ( - container instanceof HTMLElement && - container.dataset.contained === 'false' - ) { + if (container instanceof HTMLElement && container.dataset.contained === 'false') { container = null; } - eachTabIndexedElement( - currentElement, - true /* reverse */, - (element, tabIndex) => { - if (tabIndex > highestTabIndex) { - highestTabIndex = tabIndex; - highestElement = element; - } + eachTabIndexedElement(currentElement, true /* reverse */ + , (element, tabIndex) => { + if (tabIndex > highestTabIndex) { + highestTabIndex = tabIndex; + highestElement = element; + } - if (focusedTabIndex >= tabIndex && tabIndex > previousTabIndex) { - previousTabIndex = tabIndex; - previousElement = element; - if (focusedTabIndex === tabIndex || focusedTabIndex - 1 === tabIndex) { - return true; // doneSearching - } + if (focusedTabIndex >= tabIndex && tabIndex > previousTabIndex) { + previousTabIndex = tabIndex; + previousElement = element; + if (focusedTabIndex === tabIndex || focusedTabIndex - 1 === tabIndex) { + return true; // doneSearching } + } - return false; // doneSearching - }, - container, - ); + return false; // doneSearching + }, container); if (previousElement) { previousElement.focus(); @@ -210,25 +206,14 @@ function focusPrevious(): void { * container is where all of the focusable elements are searched. * Default value is document. */ -function eachTabIndexedElement( - currentElement: Element, - reverse: boolean, - updateNextCandidate: (element: Element, tabIndex: number) => boolean, - container: ?Element, -): void { - const elements = (container || document).querySelectorAll( - 'a, input, button, [tabindex]', - ); +function eachTabIndexedElement(currentElement, reverse, updateNextCandidate, container) { + const elements = (container || document).querySelectorAll('a, input, button, [tabindex]'); let index = Array.from(elements).indexOf(currentElement); const increment = reverse ? -1 : 1; for (let i = 1; i < elements.length; ++i) { index = (index + elements.length + increment) % elements.length; const element = elements[index]; - if ( - element.disabled === true || - element.tabIndex == null || - element.tabIndex === -1 - ) { + if (element.disabled === true || element.tabIndex == null || element.tabIndex === -1) { continue; } if (updateNextCandidate(element, element.tabIndex)) { @@ -237,17 +222,14 @@ function eachTabIndexedElement( } } -function getFocusedElement(): ?Element { +function getFocusedElement() { // Some inputs have a hidden-input with tabindex = -1 that gets focused, so // activeElement is actually not what we want. In these cases, we must find // the parent tag that has the actual tabindex to use. An example is the // atom-text-editor. let currentElement = document.activeElement; if (currentElement && currentElement.classList.contains('hidden-input')) { - currentElement = findParentElement( - currentElement.parentElement, - element => element instanceof HTMLElement && element.tabIndex >= 0, - ); + currentElement = findParentElement(currentElement.parentElement, element => element instanceof HTMLElement && element.tabIndex >= 0); } return currentElement; } @@ -255,13 +237,10 @@ function getFocusedElement(): ?Element { /** * Finds a parent of currentElement that satisfies the condition. */ -function findParentElement( - currentElement: ?Element, - condition: (element: Element) => boolean, -): ?Element { +function findParentElement(currentElement, condition) { let element = currentElement; while (element && !condition(element)) { element = element.parentElement; } return element; -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Table.example.js b/modules/nuclide-commons-ui/Table.example.js index d1e37db8..0e74d5cd 100644 --- a/modules/nuclide-commons-ui/Table.example.js +++ b/modules/nuclide-commons-ui/Table.example.js @@ -1,127 +1,125 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import * as React from 'react'; -import {Block} from './Block'; -import {Table} from './Table'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TableExamples = undefined; -const Highlight42Component = (props: {data: ?number}): ?React.Element => ( -
    {props.data}
    -); +var _react = _interopRequireWildcard(require('react')); -const TableExample = (): React.Element => { - const columns = [ - { - title: 'first column', - key: 'first', - }, - { - title: 'second column', - key: 'second', - component: Highlight42Component, - }, - { - title: 'third column', - key: 'third', - }, - { - title: 'fourth column', - key: 'fourth', - }, - { - title: 'fifth column', - key: 'fifth', - }, - ]; - const rows = [ - { - data: { - first: 1, - second: 2, - third: 3, - fourth: 33, - fifth: 123, - }, - }, - { - className: 'this-is-an-optional-classname', - data: { - first: 4, - second: 42, - third: 6, - fourth: 66, - fifth: 123, - }, - }, - { - data: { - first: 7, - second: 42, - third: undefined, - fourth: 66, - fifth: 123, - }, - }, - ]; - return ( - -
    - +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Table; + +function _load_Table() { + return _Table = require('./Table'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const Highlight42Component = props => _react.createElement( + 'div', + { style: props.data === 42 ? { fontWeight: 'bold' } : {} }, + props.data +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const TableExample = () => { + const columns = [{ + title: 'first column', + key: 'first' + }, { + title: 'second column', + key: 'second', + component: Highlight42Component + }, { + title: 'third column', + key: 'third' + }, { + title: 'fourth column', + key: 'fourth' + }, { + title: 'fifth column', + key: 'fifth' + }]; + const rows = [{ + data: { + first: 1, + second: 2, + third: 3, + fourth: 33, + fifth: 123 + } + }, { + className: 'this-is-an-optional-classname', + data: { + first: 4, + second: 42, + third: 6, + fourth: 66, + fifth: 123 + } + }, { + data: { + first: 7, + second: 42, + third: undefined, + fourth: 66, + fifth: 123 + } + }]; + return _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Table || _load_Table()).Table, { columns: columns, rows: rows, selectable: true }) ); }; -class SortableTableExample extends React.Component< - mixed, - { - rows: Array, - sortDescending: boolean, - sortedColumn: ?string, - }, -> { - constructor(props: mixed) { +class SortableTableExample extends _react.Component { + constructor(props) { super(props); - const rows = [ - { - data: { - first: 1, - second: 3, - third: 300, - }, - }, - { - data: { - first: 2, - second: 5, - third: 200, - }, - }, - { - className: 'nuclide-ui-custom-classname-example', - data: { - first: 3, - second: 4, - third: 100, - }, - }, - ]; + const rows = [{ + data: { + first: 1, + second: 3, + third: 300 + } + }, { + data: { + first: 2, + second: 5, + third: 200 + } + }, { + className: 'nuclide-ui-custom-classname-example', + data: { + first: 3, + second: 4, + third: 100 + } + }]; this.state = { sortDescending: false, sortedColumn: null, - rows, + rows }; - (this: any)._handleSort = this._handleSort.bind(this); + this._handleSort = this._handleSort.bind(this); } - _handleSort(sortedColumn: ?string, sortDescending: boolean): void { + _handleSort(sortedColumn, sortDescending) { const sortedRows = this.state.rows.sort((obj1, obj2) => { const order = sortDescending ? -1 : 1; return order * (obj1.data[sortedColumn] - obj2.data[sortedColumn]); @@ -129,81 +127,71 @@ class SortableTableExample extends React.Component< this.setState({ rows: sortedRows, sortedColumn, - sortDescending, + sortDescending }); } - render(): React.Node { - const columns = [ - { - title: 'first', - key: 'first', - }, - { - title: 'second', - key: 'second', - }, - { - title: 'third', - key: 'third', - }, - ]; - return ( - -
    ( -
    An optional, custom "empty message" component.
    - )} - columns={columns} - rows={this.state.rows} - sortable={true} - onSort={this._handleSort} - sortedColumn={this.state.sortedColumn} - sortDescending={this.state.sortDescending} - /> - + render() { + const columns = [{ + title: 'first', + key: 'first' + }, { + title: 'second', + key: 'second' + }, { + title: 'third', + key: 'third' + }]; + return _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Table || _load_Table()).Table, { + emptyComponent: () => _react.createElement( + 'div', + null, + 'An optional, custom "empty message" component.' + ), + columns: columns, + rows: this.state.rows, + sortable: true, + onSort: this._handleSort, + sortedColumn: this.state.sortedColumn, + sortDescending: this.state.sortDescending + }) ); } } -const EmptyTableExample = (): React.Element => { - const columns = [ - { - title: 'first column', - key: 'first', - }, - { - title: 'second column', - key: 'second', - }, - { - title: 'third column', - key: 'third', - }, - ]; +const EmptyTableExample = () => { + const columns = [{ + title: 'first column', + key: 'first' + }, { + title: 'second column', + key: 'second' + }, { + title: 'third column', + key: 'third' + }]; const rows = []; - return ( - -
    - + return _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_Table || _load_Table()).Table, { columns: columns, rows: rows }) ); }; -export const TableExamples = { +const TableExamples = exports.TableExamples = { sectionName: 'Table', description: '', - examples: [ - { - title: 'Simple Table', - component: TableExample, - }, - { - title: 'Sortable Table', - component: SortableTableExample, - }, - { - title: 'Empty Table', - component: EmptyTableExample, - }, - ], -}; + examples: [{ + title: 'Simple Table', + component: TableExample + }, { + title: 'Sortable Table', + component: SortableTableExample + }, { + title: 'Empty Table', + component: EmptyTableExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Table.js b/modules/nuclide-commons-ui/Table.js index 79c5ecfd..2b63d26e 100644 --- a/modules/nuclide-commons-ui/Table.js +++ b/modules/nuclide-commons-ui/Table.js @@ -1,188 +1,88 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import invariant from 'assert'; -import nullthrows from 'nullthrows'; -import classnames from 'classnames'; -import * as React from 'react'; -import {Observable, Subject} from 'rxjs'; -import shallowEqual from 'shallowequal'; -import {Icon} from './Icon'; -import { - areSetsEqual, - objectMapValues, - objectFromPairs, - arrayEqual, -} from 'nuclide-commons/collection'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import {ResizeObservable} from './observable-dom'; -import {scrollIntoViewIfNeeded} from './scrollIntoView'; - -type SelectionEvent = SyntheticEvent<*> | Event; - -const DEFAULT_MIN_COLUMN_WIDTH = 40; - -const DefaultEmptyComponent = () => ( -
    Empty table
    -); +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Table = undefined; +exports._calculateColumnWidths = _calculateColumnWidths; +exports._calculatePreferredColumnWidths = _calculatePreferredColumnWidths; + +var _nullthrows; + +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _shallowequal; + +function _load_shallowequal() { + return _shallowequal = _interopRequireDefault(require('shallowequal')); +} + +var _Icon; + +function _load_Icon() { + return _Icon = require('./Icon'); +} + +var _collection; -export type Column = { - title: string, - key: $Keys, - // Percentage. The `width`s of all columns must add up to 1. - width?: number, - // Optional React component for rendering cell contents. - // The component receives the cell value via `props.data`. - component?: React.ComponentType, - shouldRightAlign?: boolean, - // A class to add to the cell. This will be added to both the header and body; you can - // differentiate between them with `.nuclide-ui-table-header-cell` and - // `.nuclide-ui-table-body-cell`. - cellClassName?: string, - // A minimum width (in pixels) for the column. - minWidth?: number, -}; - -export type Row = { - className?: string, - data: T, - rowAttributes?: Object, -}; - -type PercentageWidthMap = {[key: $Keys]: number}; +function _load_collection() { + return _collection = require('nuclide-commons/collection'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _observableDom; + +function _load_observableDom() { + return _observableDom = require('./observable-dom'); +} + +var _scrollIntoView; + +function _load_scrollIntoView() { + return _scrollIntoView = require('./scrollIntoView'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const DEFAULT_MIN_COLUMN_WIDTH = 40; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const DefaultEmptyComponent = () => _react.createElement( + 'div', + { className: 'nuclide-ui-table-empty-message' }, + 'Empty table' +); // Same shape; the separate type is just used for documentation--Flow doesn't recognize a // difference. -type PixelWidthMap = {[key: $Keys]: number}; - -type Props = { - /** - * Optional classname for the entire table. - */ - className?: string, - /** - * Optional max-height for the body container. - * Useful for making the table scrollable while keeping the header fixed. - */ - maxBodyHeight?: string, - columns: Array>, - rows: Array>, - /** - * Whether to shade even and odd items differently. Default behavior is `true`. - */ - alternateBackground?: number, - /** - * Whether column widths can be resized interactively via drag&drop. Default behavior is `true`. - */ - resizable?: boolean, - children?: React.Element, - /** - * Whether columns can be sorted. - * If specified, `onSort`, `sortedColumn`, and `sortDescending` must also be specified. - */ - sortable?: boolean, - onSort?: (sortedBy: $Keys, sortDescending: boolean) => void, - sortedColumn?: ?$Keys, - sortDescending?: boolean, - /** - * Whether items can be selected. - * If specified, `onSelect` must also be specified. - */ - selectable?: boolean | ((row: T) => boolean), - selectedIndex?: ?number, - /** - * Handler to be called upon selection. Called iff `selectable` is `true`. We pass along the event - * because some consumers may want to take different action depending on it. For example, if you - * click on a row in the diagnostics table, we know you want to go to that diagnostic; if you - * select it with the keyboard, you may just be doing so incidentally while moving the selection - * to another row. - */ - onSelect?: ( - selectedItem: any, - selectedIndex: number, - event: SelectionEvent, - ) => mixed, - /** - * Callback to be invoked before calling onSelect. Called iff `selectable` is `true`. - * If this callback returns false, row selection is canceled. - */ - onWillSelect?: ( - selectedItem: any, - selectedIndex: number, - event: SelectionEvent, - ) => boolean, - - /** - * Called when a row selection is confirmed. Currently, this is done either by triggering - * "core:confirm" while an item is selected or by single clicking (which selects and confirms). - * In the future, we may consider moving single click to select-only and requiring double click - * for confirmation. - */ - onConfirm?: (selectedItem: any, selectedIndex: number) => mixed, - - onBodyBlur?: (event: SyntheticEvent<*>) => mixed, - onBodyFocus?: (event: SyntheticEvent<*>) => mixed, - - /** - * Optional React Component to override the default message when zero rows are provided. - * Useful for showing loading spinners and custom messages. - */ - emptyComponent?: React.ComponentType, - /** - * Whether a table row will be collapsed if its content is too large - */ - collapsable?: boolean, - /** - * Whether there's a header title spanning all cells instead of the column titles. - * It disables the 'sortable' prop. - */ - headerTitle?: string, - /** - * Optional HTMLElement to render a custom table header. Takes precedence over - * headerTitle. - */ - headerElement?: React.Node, - - /** - * Should keyboard navigation be enabled? This option exists for historical purposes. Ideally it - * would always be enabled, however, some locations require the "native-key-bindings" class-- - * usually to enable copying to the clipboard--which prevents Atom commands from firing. - * TODO: Find an alternative means of enabling copying in those locations, always enable keyboard - * navigation, and remove this prop. - */ - enableKeyboardNavigation?: ?boolean, -}; - -type ResizeOffset = {| - deltaPx: number, // In pixels - resizerLocation: number, // The column after which the resizer is located. -|}; - -type State = {| - tableWidth: number, - - // The user's preferred column distributions. These do not take into account the minimum widths. - preferredColumnWidths: PercentageWidthMap, - - // During a drag operation, specifies the change the user desires in the column size (and to which - // column). This is kept as a separate piece of state from the calculated widths and only combined - // with them in `render()` so that we can recalculate widths if the table changes size. We could - // also support cancelation of the resize (though we don't yet). - resizeOffset: ?ResizeOffset, - - // It's awkward to have hover styling when you're using keyboard navigation and the mouse just - // happens to be over a row. Therefore, we'll keep track of when you use keyboard navigation and - // will disable the hover state until you move the mouse again. - usingKeyboard: boolean, -|}; + /** * Design concerns: @@ -211,134 +111,108 @@ type State = {| * our table may behave a little strangely when the available area is less than the sum of the * minimum widths of the columns. (Ideally, the table would scroll horizontally in this case.) */ -export class Table extends React.Component, State> { - _mouseMoveDisposable: ?IDisposable; - _rootNode: ?HTMLDivElement; - _disposables: UniversalDisposable; - _tableBody: ?HTMLElement; - - _resizeStarts: Subject<{ - event: SyntheticMouseEvent<*>, - resizerLocation: number, - }>; - - constructor(props: Props) { +class Table extends _react.Component { + + constructor(props) { super(props); - this._resizeStarts = new Subject(); + this._resizeStarts = new _rxjsBundlesRxMinJs.Subject(); this.state = { preferredColumnWidths: getInitialPreferredColumnWidths(props.columns), resizeOffset: null, tableWidth: 0, - usingKeyboard: false, + usingKeyboard: false }; } - shouldComponentUpdate(nextProps: Props, nextState: State): boolean { + shouldComponentUpdate(nextProps, nextState) { // If the state changed, we need to re-render. - if (!shallowEqual(nextState, this.state)) { + if (!(0, (_shallowequal || _load_shallowequal()).default)(nextState, this.state)) { return true; } - if (!shallowEqual(nextProps, this.props, compareCheapProps)) { + if (!(0, (_shallowequal || _load_shallowequal()).default)(nextProps, this.props, compareCheapProps)) { return true; } - if (!arrayEqual(nextProps.columns, this.props.columns, shallowEqual)) { + if (!(0, (_collection || _load_collection()).arrayEqual)(nextProps.columns, this.props.columns, (_shallowequal || _load_shallowequal()).default)) { return true; } - if (!arrayEqual(nextProps.rows, this.props.rows)) { + if (!(0, (_collection || _load_collection()).arrayEqual)(nextProps.rows, this.props.rows)) { return true; } return false; } - componentDidMount(): void { - const el = nullthrows(this._rootNode); - - this._disposables = new UniversalDisposable( - // Update the column widths when the table is resized. - new ResizeObservable(el) - .startWith((null: any)) - .map(() => el.offsetWidth) - .filter(tableWidth => tableWidth > 0) - .subscribe(tableWidth => { - this.setState({tableWidth}); - }), - this._resizeStarts - .switchMap(({event: startEvent, resizerLocation}) => { - const startX = startEvent.pageX; - return Observable.fromEvent(document, 'mousemove') - .takeUntil(Observable.fromEvent(document, 'mouseup')) - .map(event => ({ - deltaPx: event.pageX - startX, - resizerLocation, - })) - .concat(Observable.of(null)); - }) - .subscribe(resizeOffset => { - if (resizeOffset == null) { - // Finalize the resize by updating the user's preferred column widths to account for - // their action. Note that these preferences are only updated when columns are resized - // (NOT when the table is). This is important so that, if the user resizes the table - // such that a column is at its minimum width and then resizes the table back to its - // orignal size, their original column widths are restored. - const preferredColumnWidths = _calculatePreferredColumnWidths({ - currentWidths: this._calculateColumnWidths(), - tableWidth: this.state.tableWidth, - minWidths: getMinWidths(this.props.columns), - }); - - // Update the preferred distributions and end the resize. - this.setState({preferredColumnWidths, resizeOffset: null}); - } else { - this.setState({resizeOffset}); - } - }), - atom.commands.add(el, { - 'core:move-up': event => { - this.setState({usingKeyboard: true}); - this._moveSelection(-1, event); - }, - 'core:move-down': event => { - this.setState({usingKeyboard: true}); - this._moveSelection(1, event); - }, - 'core:confirm': event => { - this.setState({usingKeyboard: true}); - const {rows, selectedIndex, onConfirm} = this.props; - if (onConfirm == null || selectedIndex == null) { - return; - } - const selectedRow = rows[selectedIndex]; - const selectedItem = selectedRow && selectedRow.data; - if (selectedItem != null) { - onConfirm(selectedItem, selectedIndex); - } - }, - }), - () => { - if (this._mouseMoveDisposable != null) { - this._mouseMoveDisposable.dispose(); - } + componentDidMount() { + const el = (0, (_nullthrows || _load_nullthrows()).default)(this._rootNode); + + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default( + // Update the column widths when the table is resized. + new (_observableDom || _load_observableDom()).ResizeObservable(el).startWith(null).map(() => el.offsetWidth).filter(tableWidth => tableWidth > 0).subscribe(tableWidth => { + this.setState({ tableWidth }); + }), this._resizeStarts.switchMap(({ event: startEvent, resizerLocation }) => { + const startX = startEvent.pageX; + return _rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mousemove').takeUntil(_rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mouseup')).map(event => ({ + deltaPx: event.pageX - startX, + resizerLocation + })).concat(_rxjsBundlesRxMinJs.Observable.of(null)); + }).subscribe(resizeOffset => { + if (resizeOffset == null) { + // Finalize the resize by updating the user's preferred column widths to account for + // their action. Note that these preferences are only updated when columns are resized + // (NOT when the table is). This is important so that, if the user resizes the table + // such that a column is at its minimum width and then resizes the table back to its + // orignal size, their original column widths are restored. + const preferredColumnWidths = _calculatePreferredColumnWidths({ + currentWidths: this._calculateColumnWidths(), + tableWidth: this.state.tableWidth, + minWidths: getMinWidths(this.props.columns) + }); + + // Update the preferred distributions and end the resize. + this.setState({ preferredColumnWidths, resizeOffset: null }); + } else { + this.setState({ resizeOffset }); + } + }), atom.commands.add(el, { + 'core:move-up': event => { + this.setState({ usingKeyboard: true }); + this._moveSelection(-1, event); }, - ); + 'core:move-down': event => { + this.setState({ usingKeyboard: true }); + this._moveSelection(1, event); + }, + 'core:confirm': event => { + this.setState({ usingKeyboard: true }); + const { rows, selectedIndex, onConfirm } = this.props; + if (onConfirm == null || selectedIndex == null) { + return; + } + const selectedRow = rows[selectedIndex]; + const selectedItem = selectedRow && selectedRow.data; + if (selectedItem != null) { + onConfirm(selectedItem, selectedIndex); + } + } + }), () => { + if (this._mouseMoveDisposable != null) { + this._mouseMoveDisposable.dispose(); + } + }); } - componentWillUnmount(): void { + componentWillUnmount() { this._disposables.dispose(); } - componentDidUpdate(prevProps: Props, prevState: State): void { - if ( - this._tableBody != null && - this.props.selectedIndex != null && - this.props.selectedIndex !== prevProps.selectedIndex - ) { + componentDidUpdate(prevProps, prevState) { + if (this._tableBody != null && this.props.selectedIndex != null && this.props.selectedIndex !== prevProps.selectedIndex) { const selectedRow = this._tableBody.children[this.props.selectedIndex]; if (selectedRow != null) { - scrollIntoViewIfNeeded(selectedRow); + (0, (_scrollIntoView || _load_scrollIntoView()).scrollIntoViewIfNeeded)(selectedRow); } } if (this.state.usingKeyboard !== prevState.usingKeyboard) { @@ -346,18 +220,14 @@ export class Table extends React.Component, State> { this._mouseMoveDisposable.dispose(); } if (this.state.usingKeyboard) { - this._mouseMoveDisposable = new UniversalDisposable( - Observable.fromEvent(document, 'mousemove') - .take(1) - .subscribe(() => { - this.setState({usingKeyboard: false}); - }), - ); + this._mouseMoveDisposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(_rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mousemove').take(1).subscribe(() => { + this.setState({ usingKeyboard: false }); + })); } } } - focus(): void { + focus() { if (this._tableBody == null) { return; } @@ -372,46 +242,34 @@ export class Table extends React.Component, State> { this._tableBody.focus(); } - componentWillReceiveProps(nextProps: Props): void { + componentWillReceiveProps(nextProps) { // Did the columns change? If so, we need to recalculate the widths. const currentColumns = this.props.columns; const nextColumns = nextProps.columns; - if ( - nextColumns.length !== currentColumns.length || - // If the columns just changed order, we want to keep their widths. - !areSetsEqual( - new Set(currentColumns.map(column => column.key)), - new Set(nextColumns.map(column => column.key)), - ) - ) { + if (nextColumns.length !== currentColumns.length || + // If the columns just changed order, we want to keep their widths. + !(0, (_collection || _load_collection()).areSetsEqual)(new Set(currentColumns.map(column => column.key)), new Set(nextColumns.map(column => column.key)))) { this.setState({ - preferredColumnWidths: getInitialPreferredColumnWidths(nextColumns), + preferredColumnWidths: getInitialPreferredColumnWidths(nextColumns) }); } } - _moveSelection(offset: -1 | 1, event: SelectionEvent): void { - const {selectedIndex} = this.props; + _moveSelection(offset, event) { + const { selectedIndex } = this.props; if (selectedIndex == null) { return; } - const nextSelectedIndex = Math.max( - 0, - Math.min(this.props.rows.length - 1, selectedIndex + offset), - ); + const nextSelectedIndex = Math.max(0, Math.min(this.props.rows.length - 1, selectedIndex + offset)); if (nextSelectedIndex === selectedIndex) { return; } - this._selectRow({index: nextSelectedIndex, event}); + this._selectRow({ index: nextSelectedIndex, event }); } - _selectRow(options: {| - index: number, - event: SelectionEvent, - confirm?: boolean, - |}): void { - const {index: selectedIndex, event, confirm} = options; - const {onSelect, onWillSelect, rows} = this.props; + _selectRow(options) { + const { index: selectedIndex, event, confirm } = options; + const { onSelect, onWillSelect, rows } = this.props; if (onSelect == null) { return; } @@ -428,45 +286,40 @@ export class Table extends React.Component, State> { } } - _handleSortByColumn(sortedBy: $Keys): void { - const {onSort, sortDescending, sortedColumn} = this.props; + _handleSortByColumn(sortedBy) { + const { onSort, sortDescending, sortedColumn } = this.props; if (onSort == null) { return; } - onSort( - sortedBy, - sortDescending == null || sortedBy !== sortedColumn - ? false - : !sortDescending, - ); + onSort(sortedBy, sortDescending == null || sortedBy !== sortedColumn ? false : !sortDescending); } // Just a bound version of the `_calculateColumnWidths` function for convenience. - _calculateColumnWidths(): PercentageWidthMap { + _calculateColumnWidths() { return _calculateColumnWidths({ preferredWidths: this.state.preferredColumnWidths, minWidths: getMinWidths(this.props.columns), tableWidth: this.state.tableWidth, columnOrder: this.props.columns.map(column => column.key), - resizeOffset: this.state.resizeOffset, + resizeOffset: this.state.resizeOffset }); } - _renderEmptyCellContent(): React.Element { - return
    ; + _renderEmptyCellContent() { + return _react.createElement('div', null); } - render(): React.Node { - return ( -
    (this._rootNode = rootNode)}> - {this._renderContents()} -
    + render() { + return _react.createElement( + 'div', + { + className: this.props.className, + ref: rootNode => this._rootNode = rootNode }, + this._renderContents() ); } - _renderContents(): React.Node { + _renderContents() { if (this.state.tableWidth === 0) { // We don't have the table width yet so we can't render the columns. return null; @@ -483,85 +336,80 @@ export class Table extends React.Component, State> { selectedIndex, sortable, sortedColumn, - sortDescending, + sortDescending } = this.props; const columnWidths = this._calculateColumnWidths(); - const header = - headerElement != null || headerTitle != null ? ( -
    - {headerElement != null ? headerElement : headerTitle} -
    - ) : ( - columns.map((column, i) => { - const {title, key, shouldRightAlign, cellClassName} = column; - let resizer; - if (i < columns.length - 1) { - resizer = ( -
    { - this._resizeStarts.next({event, resizerLocation: i}); - }} - onClick={(e: SyntheticMouseEvent<>) => { - // Prevent sortable column header click event from firing. - e.stopPropagation(); - }} - /> - ); - } - const width = columnWidths[key]; - const optionalHeaderCellProps = {}; - if (width != null) { - optionalHeaderCellProps.style = {width: `${width * 100}%`}; - } - let sortIndicator; - let titleOverlay = title; - if (sortable) { - optionalHeaderCellProps.onClick = () => { - this._handleSortByColumn(key); - }; - titleOverlay += ' – click to sort'; - if (sortedColumn === key) { - sortIndicator = ( - - - - ); - } + const header = headerElement != null || headerTitle != null ? _react.createElement( + 'div', + { className: 'nuclide-ui-table-header-cell nuclide-ui-table-full-header' }, + headerElement != null ? headerElement : headerTitle + ) : columns.map((column, i) => { + const { title, key, shouldRightAlign, cellClassName } = column; + let resizer; + if (i < columns.length - 1) { + resizer = _react.createElement('div', { + className: 'nuclide-ui-table-header-resize-handle', + onMouseDown: event => { + this._resizeStarts.next({ event, resizerLocation: i }); + }, + onClick: e => { + // Prevent sortable column header click event from firing. + e.stopPropagation(); } - return ( -
    - {title} - {sortIndicator} - {resizer} -
    + }); + } + const width = columnWidths[key]; + const optionalHeaderCellProps = {}; + if (width != null) { + optionalHeaderCellProps.style = { width: `${width * 100}%` }; + } + let sortIndicator; + let titleOverlay = title; + if (sortable) { + optionalHeaderCellProps.onClick = () => { + this._handleSortByColumn(key); + }; + titleOverlay += ' – click to sort'; + if (sortedColumn === key) { + sortIndicator = _react.createElement( + 'span', + { className: 'nuclide-ui-table-sort-indicator' }, + _react.createElement((_Icon || _load_Icon()).Icon, { + icon: sortDescending ? 'triangle-down' : 'triangle-up' + }) ); - }) + } + } + return _react.createElement( + 'div', + Object.assign({ + className: (0, (_classnames || _load_classnames()).default)(cellClassName, { + 'nuclide-ui-table-cell-text-align-right': shouldRightAlign, + 'nuclide-ui-table-header-cell': true, + 'nuclide-ui-table-header-cell-sortable': sortable + }), + title: titleOverlay, + key: key + }, optionalHeaderCellProps), + title, + sortIndicator, + resizer ); + }); let body = rows.map((row, i) => { - const {className: rowClassName, data, rowAttributes} = row; + const { className: rowClassName, data, rowAttributes } = row; const renderedRow = columns.map((column, j) => { const { key, cellClassName, component: Component, - shouldRightAlign, + shouldRightAlign } = column; let datum = data[key]; if (Component != null) { - datum = ; + datum = _react.createElement(Component, { data: datum }); } else if (datum == null) { datum = this._renderEmptyCellContent(); } @@ -570,127 +418,123 @@ export class Table extends React.Component, State> { if (width != null) { cellStyle.width = `${width * 100}%`; } - return ( -
    - {datum} -
    + 'nuclide-ui-table-cell-text-align-right': shouldRightAlign + }), + key: j, + style: cellStyle, + title: typeof datum !== 'object' ? String(datum) : null + }, rowAttributes), + datum ); }); - const selectableRow = - typeof selectable === 'function' ? selectable(row.data) : selectable; - const rowProps = selectableRow - ? { - onClick: event => { - switch (event.detail) { - // This (`event.detail === 0`) shouldn't happen normally but does when the click is - // triggered by the integration test. - case 0: - case 1: - this._selectRow({index: i, event}); - return; - case 2: - // We need to check `event.detail` (instead of using `onDoubleClick`) because - // (for some reason) `onDoubleClick` is only firing sporadically. - // TODO: Figure out why. Repros in the diagnostic table with React 16.0.0 and - // Atom 1.22.0-beta1 (Chrome 56.0.2924.87). This may be because we're swapping out - // the component on the click so a different one is receiving the second? - this._selectRow({index: i, event, confirm: true}); - return; - } - }, + const selectableRow = typeof selectable === 'function' ? selectable(row.data) : selectable; + const rowProps = selectableRow ? { + onClick: event => { + switch (event.detail) { + // This (`event.detail === 0`) shouldn't happen normally but does when the click is + // triggered by the integration test. + case 0: + case 1: + this._selectRow({ index: i, event }); + return; + case 2: + // We need to check `event.detail` (instead of using `onDoubleClick`) because + // (for some reason) `onDoubleClick` is only firing sporadically. + // TODO: Figure out why. Repros in the diagnostic table with React 16.0.0 and + // Atom 1.22.0-beta1 (Chrome 56.0.2924.87). This may be because we're swapping out + // the component on the click so a different one is receiving the second? + this._selectRow({ index: i, event, confirm: true }); + return; } - : {}; + } + } : {}; const isSelectedRow = selectedIndex != null && i === selectedIndex; - return ( -
    - {renderedRow} -
    + 'nuclide-ui-table-row-alternate': alternateBackground !== false && i % 2 === 1, + 'nuclide-ui-table-collapsed-row': this.props.collapsable && !isSelectedRow + }), + 'data-row-index': i, + key: i + }, rowProps), + renderedRow ); }); if (rows.length === 0) { const EmptyComponent = this.props.emptyComponent || DefaultEmptyComponent; - body = ; + body = _react.createElement(EmptyComponent, null); } const scrollableBodyStyle = {}; if (maxBodyHeight != null) { scrollableBodyStyle.maxHeight = maxBodyHeight; scrollableBodyStyle.overflowY = 'auto'; } - const bodyClassNames = classnames( - 'nuclide-ui-table', - 'nuclide-ui-table-body', + const bodyClassNames = (0, (_classnames || _load_classnames()).default)('nuclide-ui-table', 'nuclide-ui-table-body', { + // Using native-key-bindings prevents the up and down arrows from being captured. + 'native-key-bindings': !this.props.enableKeyboardNavigation, + // Only enable text selection if the rows aren't selectable as these two things conflict. + // TODO: Add the ability to copy text that doesn't involve text selection within selections. + 'nuclide-ui-table-body-selectable-text': !this.props.selectable + }); + return [_react.createElement( + 'div', + { key: 'header', className: 'nuclide-ui-table' }, + _react.createElement( + 'div', + { className: 'nuclide-ui-table-header' }, + header + ) + ), _react.createElement( + 'div', { - // Using native-key-bindings prevents the up and down arrows from being captured. - 'native-key-bindings': !this.props.enableKeyboardNavigation, - // Only enable text selection if the rows aren't selectable as these two things conflict. - // TODO: Add the ability to copy text that doesn't involve text selection within selections. - 'nuclide-ui-table-body-selectable-text': !this.props.selectable, - }, - ); - return [ -
    -
    {header}
    -
    , -
    { + key: 'body', + style: scrollableBodyStyle, + onFocus: event => { if (this.props.onBodyFocus != null) { this.props.onBodyFocus(event); } - }} - onBlur={event => { + }, + onBlur: event => { if (this.props.onBodyBlur != null) { this.props.onBodyBlur(event); } - }}> -
    { + } }, + _react.createElement( + 'div', + { + ref: el => { this._tableBody = el; - }} - className={bodyClassNames} - tabIndex="-1"> - {body} -
    -
    , - ]; + }, + className: bodyClassNames, + tabIndex: '-1' }, + body + ) + )]; } } -/** - * Get the initial size of each column as a percentage of the total. - */ -function getInitialPreferredColumnWidths( - columns: Array>, -): PercentageWidthMap { +exports.Table = Table; /** + * Get the initial size of each column as a percentage of the total. + */ + +function getInitialPreferredColumnWidths(columns) { const columnWidthRatios = {}; let assignedWidth = 0; const unresolvedColumns = []; columns.forEach(column => { - const {key, width} = column; + const { key, width } = column; if (width != null) { columnWidthRatios[key] = width; assignedWidth += width; @@ -705,11 +549,10 @@ function getInitialPreferredColumnWidths( return columnWidthRatios; } -function getMinWidths(columns: Array>): PixelWidthMap { +function getMinWidths(columns) { const minWidths = {}; columns.forEach(column => { - minWidths[column.key] = - column.minWidth == null ? DEFAULT_MIN_COLUMN_WIDTH : column.minWidth; + minWidths[column.key] = column.minWidth == null ? DEFAULT_MIN_COLUMN_WIDTH : column.minWidth; }); return minWidths; } @@ -718,21 +561,15 @@ function getMinWidths(columns: Array>): PixelWidthMap { * Calculate widths, taking into account the preferred and minimum widths. Exported for testing * only. */ -export function _calculateColumnWidths(options: { - preferredWidths: PercentageWidthMap, - minWidths: PixelWidthMap, - tableWidth: number, - columnOrder: Array<$Keys>, - resizeOffset: ?ResizeOffset, -}): PercentageWidthMap { +function _calculateColumnWidths(options) { const { preferredWidths, minWidths: minWidthsPx, tableWidth, columnOrder, - resizeOffset: resizeOffset_, + resizeOffset: resizeOffset_ } = options; - const resizeOffset = resizeOffset_ || {deltaPx: 0, resizerLocation: 0}; + const resizeOffset = resizeOffset_ || { deltaPx: 0, resizerLocation: 0 }; const widthsPx = {}; // Calculate the pixel widths of each column given its desired percentage width and minimum pixel @@ -742,16 +579,12 @@ export function _calculateColumnWidths(options: { let widthToAllocate = tableWidth; let columnsToAllocate = columnOrder; while (columnsToAllocate.length > 0 && widthToAllocate > 0) { - const remainingPct = columnsToAllocate - .map(columnName => preferredWidths[columnName]) - .reduce((a, b) => a + b, 0); - const desiredWidthsPx = objectFromPairs( - columnsToAllocate.map(columnName => { - const desiredPct = preferredWidths[columnName] / remainingPct; - const desiredPx = Math.round(desiredPct * widthToAllocate); - return [columnName, desiredPx]; - }), - ); + const remainingPct = columnsToAllocate.map(columnName => preferredWidths[columnName]).reduce((a, b) => a + b, 0); + const desiredWidthsPx = (0, (_collection || _load_collection()).objectFromPairs)(columnsToAllocate.map(columnName => { + const desiredPct = preferredWidths[columnName] / remainingPct; + const desiredPx = Math.round(desiredPct * widthToAllocate); + return [columnName, desiredPx]; + })); // Allocate widths for the columns who want less than their minimum width. let remainingPx = widthToAllocate; @@ -782,14 +615,11 @@ export function _calculateColumnWidths(options: { { // Adjust the column widths according to the resized column. - const {deltaPx, resizerLocation} = resizeOffset; + const { deltaPx, resizerLocation } = resizeOffset; const leftColumns = columnOrder.slice(0, resizerLocation + 1); const rightColumns = columnOrder.slice(resizerLocation + 1); - const [shrinkingColumns, growingColumn] = - deltaPx < 0 - ? [leftColumns.reverse(), rightColumns[0]] - : [rightColumns, leftColumns[leftColumns.length - 1]]; + const [shrinkingColumns, growingColumn] = deltaPx < 0 ? [leftColumns.reverse(), rightColumns[0]] : [rightColumns, leftColumns[leftColumns.length - 1]]; const targetChange = Math.abs(deltaPx); let cumulativeChange = 0; @@ -832,13 +662,9 @@ export function _calculateColumnWidths(options: { * Given the current (percentage) widths of each column, determines what user-preferred distribution * this represents. Exported for testing only. */ -export function _calculatePreferredColumnWidths(options: { - currentWidths: PercentageWidthMap, - tableWidth: number, - minWidths: PixelWidthMap, -}): PercentageWidthMap { - const {currentWidths, tableWidth, minWidths: minWidthsPx} = options; - const currentWidthsPx = objectMapValues(currentWidths, w => w * tableWidth); +function _calculatePreferredColumnWidths(options) { + const { currentWidths, tableWidth, minWidths: minWidthsPx } = options; + const currentWidthsPx = (0, (_collection || _load_collection()).objectMapValues)(currentWidths, w => w * tableWidth); // If any column is at its minimum width, we take that to mean that the user wants the column // remain at its minimum if the table is resized (as opposed to maintaining the same percentage). @@ -850,7 +676,10 @@ export function _calculatePreferredColumnWidths(options: { let remainingPx = 0; // The width that isn't accounted for after minWidth. const columnsNotAtMinimum = []; for (const [columnName, widthPx] of Object.entries(currentWidthsPx)) { - invariant(typeof widthPx === 'number'); + if (!(typeof widthPx === 'number')) { + throw new Error('Invariant violation: "typeof widthPx === \'number\'"'); + } + const minWidthPx = minWidthsPx[columnName]; if (Math.floor(widthPx) <= minWidthPx) { // Keep it at its min-width. @@ -882,7 +711,7 @@ export function _calculatePreferredColumnWidths(options: { * checks and assumes that the rows and columns are equal. (They can be checked separatedly iff * necessary.) */ -function compareCheapProps(a: mixed, b: mixed, key: ?string): ?boolean { +function compareCheapProps(a, b, key) { switch (key) { case undefined: // This is a magic way of telling `shallowEqual()` to use the default comparison for the @@ -895,4 +724,4 @@ function compareCheapProps(a: mixed, b: mixed, key: ?string): ?boolean { default: return a === b; } -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/TextEditorBanner.js b/modules/nuclide-commons-ui/TextEditorBanner.js index ad52cfa7..9c4896b8 100644 --- a/modules/nuclide-commons-ui/TextEditorBanner.js +++ b/modules/nuclide-commons-ui/TextEditorBanner.js @@ -1,3 +1,30 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Notice = exports.TextEditorBanner = undefined; + +var _Message; + +function _load_Message() { + return _Message = require('./Message'); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,64 +33,47 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {AtomTextEditor} from './AtomTextEditor'; -import type {MessageType} from './Message'; -import {Message} from './Message'; - -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import invariant from 'assert'; +class TextEditorBanner { -export class TextEditorBanner { - _disposables: UniversalDisposable; - _editor: atom$TextEditor | AtomTextEditor; - _element: HTMLElement; - _editorElement: HTMLElement; - _marker: ?atom$Marker; - - constructor(editor: atom$TextEditor | AtomTextEditor) { + constructor(editor) { this._editor = editor; const editorElement = editor.getElement().firstChild; this._element = document.createElement('div'); this._element.className = 'nuclide-ui-text-editor-banner-container'; - invariant( - editorElement instanceof HTMLElement && editorElement.parentNode != null, - ); + if (!(editorElement instanceof HTMLElement && editorElement.parentNode != null)) { + throw new Error('Invariant violation: "editorElement instanceof HTMLElement && editorElement.parentNode != null"'); + } editorElement.parentNode.insertBefore(this._element, editorElement); this._editorElement = editorElement; - this._disposables = new UniversalDisposable( - () => { - ReactDOM.unmountComponentAtNode(this._element); - this._element.replaceWith(editorElement); - }, - atom.workspace.observeActiveTextEditor(activeEditor => { - if (activeEditor == null) { - return; - } - if (activeEditor.getElement().contains(editor.getElement())) { - // This is needed for situations where the editor was rendered while - // display: none so _updateTextEditorElement wasn't able to properly - // measure at that time. - editor.getElement().measureDimensions(); - } - }), - ); + this._disposables = new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { + _reactDom.default.unmountComponentAtNode(this._element); + this._element.replaceWith(editorElement); + }, atom.workspace.observeActiveTextEditor(activeEditor => { + if (activeEditor == null) { + return; + } + if (activeEditor.getElement().contains(editor.getElement())) { + // This is needed for situations where the editor was rendered while + // display: none so _updateTextEditorElement wasn't able to properly + // measure at that time. + editor.getElement().measureDimensions(); + } + })); } - dispose(): void { + dispose() { this._disposables.dispose(); } - _updateTextEditorElement(editorContainerRef: ?React.ElementRef<'div'>) { - const editorContainerNode = ReactDOM.findDOMNode(editorContainerRef); + _updateTextEditorElement(editorContainerRef) { + const editorContainerNode = _reactDom.default.findDOMNode(editorContainerRef); if (editorContainerNode == null) { return; } @@ -79,25 +89,23 @@ export class TextEditorBanner { // Fix for Hyperclicking a read-only file. // Restore the scroll position in the editor. - this._editor - .getElement() - .getModel() - .scrollToCursorPosition(); + this._editor.getElement().getModel().scrollToCursorPosition(); } - render(reactElement: React.Element) { - ReactDOM.render( -
    -
    - {reactElement} -
    -
    this._updateTextEditorElement(ref)} - className="nuclide-ui-text-editor-banner-editor" - /> -
    , - this._element, - ); + render(reactElement) { + _reactDom.default.render(_react.createElement( + 'div', + { className: 'nuclide-ui-text-editor-banner' }, + _react.createElement( + 'div', + { className: 'nuclide-ui-text-editor-banner-element' }, + reactElement + ), + _react.createElement('div', { + ref: ref => this._updateTextEditorElement(ref), + className: 'nuclide-ui-text-editor-banner-editor' + }) + ), this._element); } hide() { @@ -105,21 +113,22 @@ export class TextEditorBanner { } } -type NoticeProps = { - messageType: MessageType, - children: React.Node, -}; - -export class Notice extends React.Component { +exports.TextEditorBanner = TextEditorBanner; +class Notice extends _react.Component { render() { - return ( -
    - -
    - {this.props.children} -
    -
    -
    + return _react.createElement( + 'div', + { className: 'nuclide-ui-text-editor-banner-notice' }, + _react.createElement( + (_Message || _load_Message()).Message, + { type: this.props.messageType }, + _react.createElement( + 'div', + { className: 'nuclide-ui-text-editor-banner-notice-content' }, + this.props.children + ) + ) ); } } +exports.Notice = Notice; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/TextInputs.example.js b/modules/nuclide-commons-ui/TextInputs.example.js index 466153f3..600251c7 100644 --- a/modules/nuclide-commons-ui/TextInputs.example.js +++ b/modules/nuclide-commons-ui/TextInputs.example.js @@ -1,125 +1,162 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import {TextBuffer} from 'atom'; -import * as React from 'react'; -import {Block} from './Block'; -import {AtomInput} from './AtomInput'; -import {AtomTextEditor} from './AtomTextEditor'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TextInputExamples = undefined; -const AtomInputExample = (): React.Element => ( -
    - - - - - - - - - - - - - - - - - - - - - -
    -); +var _atom = require('atom'); + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _AtomInput; -const buffer1 = new TextBuffer({ - text: '/**\n * Hi!\n */\n\n// I am a TextBuffer.\nconst a = 42;', +function _load_AtomInput() { + return _AtomInput = require('./AtomInput'); +} + +var _AtomTextEditor; + +function _load_AtomTextEditor() { + return _AtomTextEditor = require('./AtomTextEditor'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const AtomInputExample = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + disabled: false, + initialValue: 'atom input', + placeholderText: 'placeholder text' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + disabled: true, + initialValue: 'disabled atom input', + placeholderText: 'placeholder text' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + initialValue: 'xs atom input', + placeholderText: 'placeholder text', + size: 'xs' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + initialValue: 'sm atom input', + placeholderText: 'placeholder text', + size: 'sm' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + initialValue: 'lg atom input', + placeholderText: 'placeholder text', + size: 'lg' + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + initialValue: 'unstyled atom input', + placeholderText: 'placeholder text', + unstyled: true + }) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement((_AtomInput || _load_AtomInput()).AtomInput, { + initialValue: 'atom input with custom width', + placeholderText: 'placeholder text', + width: 200 + }) + ) +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const buffer1 = new _atom.TextBuffer({ + text: '/**\n * Hi!\n */\n\n// I am a TextBuffer.\nconst a = 42;' }); -const buffer2 = new TextBuffer({ - text: - '/**\n * Hi!\n */\n\n// I am a read-only, gutter-less TextBuffer.\nconst a = 42;', +const buffer2 = new _atom.TextBuffer({ + text: '/**\n * Hi!\n */\n\n// I am a read-only, gutter-less TextBuffer.\nconst a = 42;' }); const editorWrapperStyle = { display: 'flex', flexGrow: 1, height: '12em', - boxShadow: '0 0 20px 0 rgba(0, 0, 0, 0.3)', + boxShadow: '0 0 20px 0 rgba(0, 0, 0, 0.3)' }; -const AtomTextEditorExample = (): React.Element => ( - -
    - -
    -
    - -
    -
    +const AtomTextEditorExample = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + 'div', + { style: editorWrapperStyle }, + _react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { + gutterHidden: false, + readOnly: false, + syncTextContents: false, + autoGrow: false, + path: 'aJavaScriptFile.js', + textBuffer: buffer1 + }) + ), + _react.createElement( + 'div', + { style: Object.assign({}, editorWrapperStyle, { marginTop: '2em' }) }, + _react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { + gutterHidden: true, + readOnly: true, + syncTextContents: false, + autoGrow: false, + path: 'aJavaScriptFile.js', + textBuffer: buffer2 + }) + ) ); -export const TextInputExamples = { +const TextInputExamples = exports.TextInputExamples = { sectionName: 'Text Inputs', description: '', - examples: [ - { - title: 'AtomInput', - component: AtomInputExample, - }, - { - title: 'AtomTextEditor', - component: AtomTextEditorExample, - }, - ], -}; + examples: [{ + title: 'AtomInput', + component: AtomInputExample + }, { + title: 'AtomTextEditor', + component: AtomTextEditorExample + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/TextRenderer.js b/modules/nuclide-commons-ui/TextRenderer.js index 2a33a4ca..dc8dae4c 100644 --- a/modules/nuclide-commons-ui/TextRenderer.js +++ b/modules/nuclide-commons-ui/TextRenderer.js @@ -1,35 +1,34 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TextRenderer = TextRenderer; -/* Evaluation & values */ -export type EvaluationResult = { - type: string, - // Either: - value?: string, - // Or: - description?: string, - objectId?: string, - subtype?: string, -}; +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } -export function TextRenderer( - evaluationResult: EvaluationResult, -): ?React.Element { - const {type, value} = evaluationResult; +/* Evaluation & values */ +function TextRenderer(evaluationResult) { + const { type, value } = evaluationResult; if (type === 'text') { - return {value}; + return _react.createElement( + 'span', + null, + value + ); } else { return null; } -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Toggle.js b/modules/nuclide-commons-ui/Toggle.js index c95516af..a4d3bffa 100644 --- a/modules/nuclide-commons-ui/Toggle.js +++ b/modules/nuclide-commons-ui/Toggle.js @@ -1,70 +1,81 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Toggle = undefined; -import * as React from 'react'; -import classnames from 'classnames'; +var _react = _interopRequireWildcard(require('react')); -import ignoreTextSelectionEvents from './ignoreTextSelectionEvents'; +var _classnames; -type DefaultProps = { - disabled: boolean, - onClick: (event: SyntheticEvent<>) => mixed, -}; +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _ignoreTextSelectionEvents; -type Props = { - className?: string, - toggled: boolean, - disabled: boolean, - label: ?string, - onChange: (isToggled: boolean) => mixed, - onClick: (event: SyntheticEvent<>) => mixed, -}; +function _load_ignoreTextSelectionEvents() { + return _ignoreTextSelectionEvents = _interopRequireDefault(require('./ignoreTextSelectionEvents')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } /** * A toggle component with an input toggle and a label. We restrict the label to a string * to ensure this component is pure. */ -export class Toggle extends React.Component { - static defaultProps: DefaultProps = { - disabled: false, - onClick(event) {}, - }; +class Toggle extends _react.Component { + constructor(...args) { + var _temp; - _onChange = (event: SyntheticEvent<>) => { - const isToggled = ((event.target: any): HTMLInputElement).checked; - this.props.onChange.call(null, isToggled); - }; + return _temp = super(...args), this._onChange = event => { + const isToggled = event.target.checked; + this.props.onChange.call(null, isToggled); + }, _temp; + } - render(): React.Node { - const {className, disabled, label, onClick, toggled} = this.props; - const text = - label === '' ? null : ( - {label} - ); - return ( - + render() { + const { className, disabled, label, onClick, toggled } = this.props; + const text = label === '' ? null : _react.createElement( + 'span', + { className: 'nuclide-ui-toggle-label-text' }, + ' ', + label + ); + return _react.createElement( + 'label', + { + className: (0, (_classnames || _load_classnames()).default)(className, 'nuclide-ui-toggle-label', { + 'nuclide-ui-toggle-disabled': disabled + }), + onClick: onClick && (0, (_ignoreTextSelectionEvents || _load_ignoreTextSelectionEvents()).default)(onClick) }, + _react.createElement('input', { + checked: toggled, + className: 'input-toggle', + disabled: disabled, + onChange: this._onChange, + type: 'checkbox' + }), + text ); } } +exports.Toggle = Toggle; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +Toggle.defaultProps = { + disabled: false, + onClick(event) {} +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Toolbar.example.js b/modules/nuclide-commons-ui/Toolbar.example.js index f8093874..e6f25057 100644 --- a/modules/nuclide-commons-ui/Toolbar.example.js +++ b/modules/nuclide-commons-ui/Toolbar.example.js @@ -1,97 +1,187 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import * as React from 'react'; -import {Block} from './Block'; -import {Toolbar} from './Toolbar'; -import {ToolbarCenter} from './ToolbarCenter'; -import {ToolbarLeft} from './ToolbarLeft'; -import {ToolbarRight} from './ToolbarRight'; -import {Button} from './Button'; - -const ToolbarExampleLeft = (): React.Element => ( -
    - - - -
    a toolbar can have multiple children,
    - -
    -
    -
    - -
    - Be sure to use {', , and '} as - children. -
    -
    -
    -); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ToolbarExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Toolbar; + +function _load_Toolbar() { + return _Toolbar = require('./Toolbar'); +} + +var _ToolbarCenter; + +function _load_ToolbarCenter() { + return _ToolbarCenter = require('./ToolbarCenter'); +} + +var _ToolbarLeft; + +function _load_ToolbarLeft() { + return _ToolbarLeft = require('./ToolbarLeft'); +} + +var _ToolbarRight; + +function _load_ToolbarRight() { + return _ToolbarRight = require('./ToolbarRight'); +} + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const ToolbarExampleLeft = () => _react.createElement( + 'div', + null, + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Toolbar || _load_Toolbar()).Toolbar, + { location: 'top' }, + _react.createElement( + (_ToolbarLeft || _load_ToolbarLeft()).ToolbarLeft, + null, + _react.createElement( + 'div', + null, + 'a toolbar can have multiple children,' + ), + _react.createElement( + (_Button || _load_Button()).Button, + null, + 'such as this button.' + ) + ) + ) + ), + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + 'div', + null, + 'Be sure to use ', + ', , and ', + ' as children.' + ) + ) +); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -const ToolbarExampleCenter = (): React.Element => ( - - - -
    Example of {''}.
    -
    -
    -
    +const ToolbarExampleCenter = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Toolbar || _load_Toolbar()).Toolbar, + { location: 'top' }, + _react.createElement( + (_ToolbarCenter || _load_ToolbarCenter()).ToolbarCenter, + null, + _react.createElement( + 'div', + null, + 'Example of ', + '', + '.' + ) + ) + ) ); -const ToolbarExampleRight = (): React.Element => ( - - - -
    Example of {''}
    -
    -
    -
    +const ToolbarExampleRight = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Toolbar || _load_Toolbar()).Toolbar, + { location: 'top' }, + _react.createElement( + (_ToolbarRight || _load_ToolbarRight()).ToolbarRight, + null, + _react.createElement( + 'div', + null, + 'Example of ', + '' + ) + ) + ) ); -const ToolbarExampleMultiple = (): React.Element => ( - - - -
    You can combine
    -
    - -
    the various kinds
    -
    - -
    of aligners.
    -
    -
    -
    +const ToolbarExampleMultiple = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Toolbar || _load_Toolbar()).Toolbar, + { location: 'top' }, + _react.createElement( + (_ToolbarLeft || _load_ToolbarLeft()).ToolbarLeft, + null, + _react.createElement( + 'div', + null, + 'You can combine' + ) + ), + _react.createElement( + (_ToolbarCenter || _load_ToolbarCenter()).ToolbarCenter, + null, + _react.createElement( + 'div', + null, + 'the various kinds' + ) + ), + _react.createElement( + (_ToolbarRight || _load_ToolbarRight()).ToolbarRight, + null, + _react.createElement( + 'div', + null, + 'of aligners.' + ) + ) + ) ); -export const ToolbarExamples = { +const ToolbarExamples = exports.ToolbarExamples = { sectionName: 'Toolbar', description: '', - examples: [ - { - title: 'Left Toolbar', - component: ToolbarExampleLeft, - }, - { - title: 'Center Toolbar', - component: ToolbarExampleCenter, - }, - { - title: 'Right Toolbar', - component: ToolbarExampleRight, - }, - { - title: 'Combining Toolbar aligners', - component: ToolbarExampleMultiple, - }, - ], -}; + examples: [{ + title: 'Left Toolbar', + component: ToolbarExampleLeft + }, { + title: 'Center Toolbar', + component: ToolbarExampleCenter + }, { + title: 'Right Toolbar', + component: ToolbarExampleRight + }, { + title: 'Combining Toolbar aligners', + component: ToolbarExampleMultiple + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Toolbar.js b/modules/nuclide-commons-ui/Toolbar.js index 8c1579c3..b885d3e0 100644 --- a/modules/nuclide-commons-ui/Toolbar.js +++ b/modules/nuclide-commons-ui/Toolbar.js @@ -1,37 +1,49 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import classnames from 'classnames'; -import * as React from 'react'; -import {maybeToString} from 'nuclide-commons/string'; - -type Props = { - children?: mixed, - className?: string, - location?: 'top' | 'bottom', -}; - -export const Toolbar = (props: Props) => { - const className = classnames( - 'nuclide-ui-toolbar', - { - [`nuclide-ui-toolbar--${maybeToString(props.location)}`]: - props.location != null, - }, - props.className, - ); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Toolbar = undefined; + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _string; + +function _load_string() { + return _string = require('nuclide-commons/string'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const Toolbar = exports.Toolbar = props => { + const className = (0, (_classnames || _load_classnames()).default)('nuclide-ui-toolbar', { + [`nuclide-ui-toolbar--${(0, (_string || _load_string()).maybeToString)(props.location)}`]: props.location != null + }, props.className); return ( // $FlowFixMe(>=0.53.0) Flow suppress -
    {props.children}
    + _react.createElement( + 'div', + { className: className }, + props.children + ) ); -}; +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ToolbarCenter.js b/modules/nuclide-commons-ui/ToolbarCenter.js index 757092d8..5ee7932b 100644 --- a/modules/nuclide-commons-ui/ToolbarCenter.js +++ b/modules/nuclide-commons-ui/ToolbarCenter.js @@ -1,24 +1,31 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +"use strict"; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ToolbarCenter = undefined; -type Props = { - children?: mixed, -}; +var _react = _interopRequireWildcard(require("react")); -export const ToolbarCenter = (props: Props) => { +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const ToolbarCenter = exports.ToolbarCenter = props => { return ( // $FlowFixMe(>=0.53.0) Flow suppress -
    {props.children}
    + _react.createElement( + "div", + { className: "nuclide-ui-toolbar__center" }, + props.children + ) ); -}; +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ToolbarLeft.js b/modules/nuclide-commons-ui/ToolbarLeft.js index 47b489cb..79e4808b 100644 --- a/modules/nuclide-commons-ui/ToolbarLeft.js +++ b/modules/nuclide-commons-ui/ToolbarLeft.js @@ -1,24 +1,31 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +"use strict"; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ToolbarLeft = undefined; -type Props = { - children?: mixed, -}; +var _react = _interopRequireWildcard(require("react")); -export const ToolbarLeft = (props: Props) => { +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const ToolbarLeft = exports.ToolbarLeft = props => { return ( // $FlowFixMe(>=0.53.0) Flow suppress -
    {props.children}
    + _react.createElement( + "div", + { className: "nuclide-ui-toolbar__left" }, + props.children + ) ); -}; +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ToolbarRight.js b/modules/nuclide-commons-ui/ToolbarRight.js index 1f6af83e..6152cdf6 100644 --- a/modules/nuclide-commons-ui/ToolbarRight.js +++ b/modules/nuclide-commons-ui/ToolbarRight.js @@ -1,24 +1,31 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +"use strict"; -import * as React from 'react'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ToolbarRight = undefined; -type Props = { - children?: mixed, -}; +var _react = _interopRequireWildcard(require("react")); -export const ToolbarRight = (props: Props) => { +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const ToolbarRight = exports.ToolbarRight = props => { return ( // $FlowFixMe(>=0.53.0) Flow suppress -
    {props.children}
    + _react.createElement( + "div", + { className: "nuclide-ui-toolbar__right" }, + props.children + ) ); -}; +}; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/ToolbarUtils.js b/modules/nuclide-commons-ui/ToolbarUtils.js index a96402c6..a7d18519 100644 --- a/modules/nuclide-commons-ui/ToolbarUtils.js +++ b/modules/nuclide-commons-ui/ToolbarUtils.js @@ -1,32 +1,41 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import humanizeKeystroke from 'nuclide-commons/humanizeKeystroke'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.makeToolbarButtonSpec = makeToolbarButtonSpec; -export function makeToolbarButtonSpec( - options: toolbar$ButtonSpec, -): toolbar$ButtonSpec { +var _humanizeKeystroke; + +function _load_humanizeKeystroke() { + return _humanizeKeystroke = _interopRequireDefault(require('nuclide-commons/humanizeKeystroke')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function makeToolbarButtonSpec(options) { const command = options.callback; if (typeof command === 'string') { const [keyBinding] = atom.keymaps.findKeyBindings({ command, - target: atom.views.getView(atom.workspace), + target: atom.views.getView(atom.workspace) }); const tooltipStr = options.tooltip; if (keyBinding != null && tooltipStr != null) { - const keyString = humanizeKeystroke(keyBinding.keystrokes, null); + const keyString = (0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)(keyBinding.keystrokes, null); options.tooltip = `${tooltipStr} (${keyString})`; } } - return {...options}; -} + return Object.assign({}, options); +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Tree.example.js b/modules/nuclide-commons-ui/Tree.example.js index 88a41a26..c3dc8a50 100644 --- a/modules/nuclide-commons-ui/Tree.example.js +++ b/modules/nuclide-commons-ui/Tree.example.js @@ -1,3 +1,32 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TreeExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Block; + +function _load_Block() { + return _Block = require('./Block'); +} + +var _Icon; + +function _load_Icon() { + return _Icon = require('./Icon'); +} + +var _Tree; + +function _load_Tree() { + return _Tree = require('./Tree'); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,88 +35,166 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import * as React from 'react'; -import {Block} from './Block'; -import {Icon} from './Icon'; -import {TreeList, TreeItem, NestedTreeItem} from './Tree'; - -const BasicTreeExample = (): React.Element => ( -
    - Trees - - - TreeItem 1 - TreeItem 2 - NestedTreeItem 1 -- click me!} - onSelect={handleSelect} - onConfirm={handleConfirm} - onTripleClick={handleTripleClick} - selected={true}> - TreeItem 3 - TreeItem 4 - - NestedTreeItem 2} - collapsed={true} - /> - - -
    +const BasicTreeExample = () => _react.createElement( + 'div', + null, + 'Trees', + _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Tree || _load_Tree()).TreeList, + null, + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + 'TreeItem 1' + ), + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + 'TreeItem 2' + ), + _react.createElement( + (_Tree || _load_Tree()).NestedTreeItem, + { + title: _react.createElement( + 'span', + null, + 'NestedTreeItem 1 -- click me!' + ), + onSelect: handleSelect, + onConfirm: handleConfirm, + onTripleClick: handleTripleClick, + selected: true }, + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + 'TreeItem 3' + ), + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + 'TreeItem 4' + ) + ), + _react.createElement((_Tree || _load_Tree()).NestedTreeItem, { + title: _react.createElement( + 'span', + null, + 'NestedTreeItem 2' + ), + collapsed: true + }) + ) + ) ); -const AtomStyleguideTreeExample = (): React.Element => ( - - - A Directory}> - Nested Directory}> - - File one - - - Collapsed Nested Directory}> - - File one - - - - File one - - - File three .selected! - - - - .icon-file-text - - - .icon-file-symlink-file - - - +const AtomStyleguideTreeExample = () => _react.createElement( + (_Block || _load_Block()).Block, + null, + _react.createElement( + (_Tree || _load_Tree()).TreeList, + { showArrows: true }, + _react.createElement( + (_Tree || _load_Tree()).NestedTreeItem, + { title: _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-directory' }, + 'A Directory' + ) }, + _react.createElement( + (_Tree || _load_Tree()).NestedTreeItem, + { + collapsed: false, + title: _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-directory' }, + 'Nested Directory' + ) }, + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-text' }, + 'File one' + ) + ) + ), + _react.createElement( + (_Tree || _load_Tree()).NestedTreeItem, + { + collapsed: true, + title: _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-directory' }, + 'Collapsed Nested Directory' + ) }, + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-text' }, + 'File one' + ) + ) + ), + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-text' }, + 'File one' + ) + ), + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + { selected: true }, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-text' }, + 'File three .selected!' + ) + ) + ), + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-text' }, + '.icon-file-text' + ) + ), + _react.createElement( + (_Tree || _load_Tree()).TreeItem, + null, + _react.createElement( + (_Icon || _load_Icon()).Icon, + { icon: 'file-symlink-file' }, + '.icon-file-symlink-file' + ) + ) + ) ); -export const TreeExamples = { +const TreeExamples = exports.TreeExamples = { sectionName: 'Trees', description: 'Expandable, hierarchical lists.', - examples: [ - { - title: 'Basic Tree', - component: BasicTreeExample, - }, - { - title: 'Reproducing the Atom style guide example:', - component: AtomStyleguideTreeExample, - }, - ], + examples: [{ + title: 'Basic Tree', + component: BasicTreeExample + }, { + title: 'Reproducing the Atom style guide example:', + component: AtomStyleguideTreeExample + }] }; function handleSelect() { @@ -98,4 +205,4 @@ function handleConfirm() { } function handleTripleClick() { atom.notifications.addInfo('triple clicked!'); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/Tree.js b/modules/nuclide-commons-ui/Tree.js index 5db9e9db..a0df2d57 100644 --- a/modules/nuclide-commons-ui/Tree.js +++ b/modules/nuclide-commons-ui/Tree.js @@ -1,57 +1,64 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TreeList = exports.NestedTreeItem = exports.TreeItem = undefined; +exports.Tree = Tree; + +var _react = _interopRequireWildcard(require('react')); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _scrollIntoView; + +function _load_scrollIntoView() { + return _scrollIntoView = require('./scrollIntoView'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ /* eslint-env browser */ -import * as React from 'react'; -import classnames from 'classnames'; -import invariant from 'assert'; -import {scrollIntoView} from './scrollIntoView'; - -export function Tree({className, style, ...props}: Object) { - return ( -
      - ); +function Tree(_ref) { + let { className, style } = _ref, + props = _objectWithoutProperties(_ref, ['className', 'style']); + + return _react.createElement('ol', Object.assign({ + className: (0, (_classnames || _load_classnames()).default)('list-tree', className), + role: 'tree', + style: Object.assign({ position: 'relative' }, style) + }, props)); } -type TreeItemProps = {| - children?: React.Node, - className?: string, - // handled below in `handleClick` - /* eslint-disable react/no-unused-prop-types */ - onSelect?: (e: SyntheticMouseEvent<>) => mixed, - onConfirm?: (e: SyntheticMouseEvent<>) => mixed, - onTripleClick?: (e: SyntheticMouseEvent<>) => mixed, - /* eslint-enable react/no-unused-prop-types */ - selected?: boolean, - onMouseDown?: (e: SyntheticMouseEvent<>) => mixed, - onMouseEnter?: (e: SyntheticMouseEvent<>) => mixed, - onMouseLeave?: (e: SyntheticMouseEvent<>) => mixed, - path?: string, - name?: string, -|}; - -export class TreeItem extends React.Component { - _liNode: ?HTMLLIElement; - _handleClick = handleClick.bind(this); +class TreeItem extends _react.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._handleClick = handleClick.bind(this), _temp; + } scrollIntoView() { if (this._liNode != null) { - scrollIntoView(this._liNode); + (0, (_scrollIntoView || _load_scrollIntoView()).scrollIntoView)(this._liNode); } } @@ -64,67 +71,56 @@ export class TreeItem extends React.Component { onMouseEnter, onMouseLeave, path, - name, + name } = this.props; - return ( -
    1. (this._liNode = liNode)} - role="treeitem" - tabIndex={selected ? '0' : '-1'}> - {selected && typeof children === 'string' ? ( - // String children must be wrapped to receive correct styles when selected. - {children} - ) : ( - children - )} -
    2. + return _react.createElement( + 'li', + { + 'aria-selected': selected, + className: (0, (_classnames || _load_classnames()).default)(className, { + selected + }, 'list-item'), + onMouseDown: onMouseDown, + onMouseEnter: onMouseEnter, + onMouseLeave: onMouseLeave, + 'data-path': path, + 'data-name': name, + onClick: this._handleClick, + ref: liNode => this._liNode = liNode, + role: 'treeitem', + tabIndex: selected ? '0' : '-1' }, + selected && typeof children === 'string' ? + // String children must be wrapped to receive correct styles when selected. + _react.createElement( + 'span', + null, + children + ) : children ); } } -type NestedTreeItemProps = {| - title?: React.Node, - children?: mixed, - className?: string, - hasFlatChildren?: boolean, // passthrough to inner TreeList - selected?: boolean, - collapsed?: boolean, - // handled below in `handleClick` - /* eslint-disable react/no-unused-prop-types */ - onSelect?: (e: SyntheticMouseEvent<>) => mixed, - onConfirm?: (e: SyntheticMouseEvent<>) => mixed, - onTripleClick?: (e: SyntheticMouseEvent<>) => mixed, - /* eslint-disable react/no-unused-prop-types */ -|}; - -export class NestedTreeItem extends React.Component { - _itemNode: ?HTMLDivElement; - _handleClick = (e: SyntheticMouseEvent<>) => { - const itemNode = this._itemNode; - if (itemNode == null) { - return; - } - - invariant(e.target instanceof Element); - if (e.target.closest('.list-item') === itemNode) { - handleClick.call(this, e); - } - }; +exports.TreeItem = TreeItem; +class NestedTreeItem extends _react.Component { + constructor(...args) { + var _temp2; + + return _temp2 = super(...args), this._handleClick = e => { + const itemNode = this._itemNode; + if (itemNode == null) { + return; + } + + if (!(e.target instanceof Element)) { + throw new Error('Invariant violation: "e.target instanceof Element"'); + } + + if (e.target.closest('.list-item') === itemNode) { + handleClick.call(this, e); + } + }, _temp2; + } render() { const { @@ -133,63 +129,54 @@ export class NestedTreeItem extends React.Component { selected, collapsed, title, - children, + children } = this.props; - return ( -
    3. - {title == null ? null : ( -
      (this._itemNode = node)}> - {title} -
      - )} - {children} -
    4. + return _react.createElement( + 'li', + { + 'aria-selected': selected, + 'aria-expanded': !collapsed, + className: (0, (_classnames || _load_classnames()).default)(className, { + selected, + collapsed + }, 'list-nested-item'), + onClick: this._handleClick, + role: 'treeitem', + tabIndex: selected ? '0' : '-1' }, + title == null ? null : _react.createElement( + 'div', + { + tabIndex: -1, + className: 'native-key-bindings list-item', + ref: node => this._itemNode = node }, + title + ), + _react.createElement( + TreeList, + { hasFlatChildren: hasFlatChildren }, + children + ) ); } } -type TreeListProps = { - className?: string, - /* typically, instances of TreeItem or NestedTreeItem. */ - children?: mixed, - showArrows?: boolean, - hasFlatChildren?: boolean, -}; -export const TreeList = (props: TreeListProps) => ( - // $FlowFixMe(>=0.53.0) Flow suppress -
        - {props.children} -
      +exports.NestedTreeItem = NestedTreeItem; +const TreeList = exports.TreeList = props => +// $FlowFixMe(>=0.53.0) Flow suppress +_react.createElement( + 'ul', + { + className: (0, (_classnames || _load_classnames()).default)(props.className, { + 'has-collapsable-children': props.showArrows, + 'has-flat-children': props.hasFlatChildren + }, 'list-tree'), + role: 'group' }, + props.children ); -function handleClick(e: SyntheticMouseEvent<>): void { - const {onSelect, onConfirm, onTripleClick} = this.props; +function handleClick(e) { + const { onSelect, onConfirm, onTripleClick } = this.props; const numberOfClicks = e.detail; switch (numberOfClicks) { @@ -205,4 +192,4 @@ function handleClick(e: SyntheticMouseEvent<>): void { default: break; } -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/TruncatedButton.js b/modules/nuclide-commons-ui/TruncatedButton.js index 1f0e7a23..cae1cd51 100644 --- a/modules/nuclide-commons-ui/TruncatedButton.js +++ b/modules/nuclide-commons-ui/TruncatedButton.js @@ -1,40 +1,52 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import {Button} from './Button'; -import classnames from 'classnames'; -import * as React from 'react'; - -type Props = { - className?: string, - // $FlowFixMe(>=0.53.0) Flow suppress - children?: React.Children, - label?: string, -}; - -export default class TruncatedButton extends React.Component { - render(): React.Node { - const {children, className, label, ...props} = this.props; - return ( - +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); +} + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _react = _interopRequireWildcard(require('react')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class TruncatedButton extends _react.Component { + render() { + const _props = this.props, + { children, className, label } = _props, + props = _objectWithoutProperties(_props, ['children', 'className', 'label']); + return _react.createElement( + (_Button || _load_Button()).Button, + Object.assign({ + className: (0, (_classnames || _load_classnames()).default)('btn-block', 'nuclide-ui-truncated-button', className), + title: label + }, props), + children || label ); } } +exports.default = TruncatedButton; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/UnstyledButton.js b/modules/nuclide-commons-ui/UnstyledButton.js index ef54921a..de9c4376 100644 --- a/modules/nuclide-commons-ui/UnstyledButton.js +++ b/modules/nuclide-commons-ui/UnstyledButton.js @@ -1,37 +1,55 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import React from 'react'; -import classnames from 'classnames'; -import nullthrows from 'nullthrows'; - -type Props = { - className?: string, -}; - -export default class UnstyledButton extends React.Component { - props: Props; - _node: ?HTMLButtonElement; - - focus(): void { - nullthrows(this._node).focus(); +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = _interopRequireDefault(require('react')); + +var _classnames; + +function _load_classnames() { + return _classnames = _interopRequireDefault(require('classnames')); +} + +var _nullthrows; + +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class UnstyledButton extends _react.default.Component { + constructor(...args) { + var _temp; + + return _temp = super(...args), this._setRef = node => this._node = node, _temp; } - _setRef = (node: ?HTMLButtonElement) => (this._node = node); + focus() { + (0, (_nullthrows || _load_nullthrows()).default)(this._node).focus(); + } - render(): React$Element { - const {className, ...props} = this.props; - const classes = classnames('nuclide-ui-unstyled-button', className); + render() { + const _props = this.props, + { className } = _props, + props = _objectWithoutProperties(_props, ['className']); + const classes = (0, (_classnames || _load_classnames()).default)('nuclide-ui-unstyled-button', className); // eslint-disable-next-line rulesdir/use-nuclide-ui-components - return ; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ModalExamples = undefined; + +var _react = _interopRequireWildcard(require('react')); + +var _Button; + +function _load_Button() { + return _Button = require('./Button'); } +var _showModal; + +function _load_showModal() { + return _showModal = _interopRequireDefault(require('./showModal')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function ModalButton() { + return _react.createElement( + (_Button || _load_Button()).Button, + { onClick: showExampleModal }, + 'Show Modal' + ); +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + function showExampleModal() { - showModal(({dismiss}) => { - return ( -
      -
      - I'm a modal. You can add any content you like. I have all the standard - behavior, like obeying the "core:cancel" command! -
      - -
      + (0, (_showModal || _load_showModal()).default)(({ dismiss }) => { + return _react.createElement( + 'div', + null, + _react.createElement( + 'div', + null, + 'I\'m a modal. You can add any content you like. I have all the standard behavior, like obeying the "core:cancel" command!' + ), + _react.createElement( + (_Button || _load_Button()).Button, + { onClick: dismiss }, + 'Hide Modal' + ) ); }); } -export const ModalExamples = { +const ModalExamples = exports.ModalExamples = { sectionName: 'Modal', description: 'Overlays that cover the entire screen. ', - examples: [ - { - title: 'Click the button to toggle a modal:', - component: ModalButton, - }, - ], -}; + examples: [{ + title: 'Click the button to toggle a modal:', + component: ModalButton + }] +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/showModal.js b/modules/nuclide-commons-ui/showModal.js index 26b42bd0..8936c210 100644 --- a/modules/nuclide-commons-ui/showModal.js +++ b/modules/nuclide-commons-ui/showModal.js @@ -1,3 +1,48 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = showModal; + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('nuclide-commons/UniversalDisposable')); +} + +var _TabbableContainer; + +function _load_TabbableContainer() { + return _TabbableContainer = _interopRequireDefault(require('./TabbableContainer')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +/** + * Shows a modal dialog that renders a React element as its content. + * The modal is automatically hidden when the user clicks outside of it, and on core:cancel (esc). + * The modal panel unmounts its React component and destroys the panel as soon as it is hidden; + * you may not hide the panel and then re-show it later. + * Returns a disposable that you may use to hide and destroy the modal. + */ + + +/** + * Given a function to dismiss the modal, return a React element for the content. + * Call the function when e.g. the user clicks a Cancel or Submit button. + */ + + +/** Wrap options in an object so we can add new ones later without an explosion of params */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,161 +51,106 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ /* global Node */ /* global HTMLElement */ -import invariant from 'assert'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import {Observable} from 'rxjs'; -import UniversalDisposable from 'nuclide-commons/UniversalDisposable'; - -import TabbableContainer from './TabbableContainer'; - -/** - * Given a function to dismiss the modal, return a React element for the content. - * Call the function when e.g. the user clicks a Cancel or Submit button. - */ -type ContentFactory = ({ - dismiss(): void, - element: Element, -}) => React.Node; - -/** Wrap options in an object so we can add new ones later without an explosion of params */ -type Options = {| - /** Called when the modal is dismissed (just before it is destroyed). */ - onDismiss?: () => mixed, - onOpen?: () => mixed, - /** - * Called when the user clicks outside the modal, return false to prevent dismissal. - * If unspecified the modal will be dismissed if the user clicks outside the modal. - */ - shouldDismissOnClickOutsideModal?: () => boolean, - /** - * Called when the user presses the escape key, return false to prevent dismissal. - * If unspecified the modal will be dismissed if the user presses escape. - */ - shouldDismissOnPressEscape?: () => boolean, - /** Passed to atom's underlying addModalPanel function. */ - priority?: number, - /** Passed to atom's underlying addModalPanel function. */ - className?: string, -|}; - -/** - * Shows a modal dialog that renders a React element as its content. - * The modal is automatically hidden when the user clicks outside of it, and on core:cancel (esc). - * The modal panel unmounts its React component and destroys the panel as soon as it is hidden; - * you may not hide the panel and then re-show it later. - * Returns a disposable that you may use to hide and destroy the modal. - */ -export default function showModal( - contentFactory: ContentFactory, - options: Options = defaults, -): IDisposable { +function showModal(contentFactory, options = defaults) { const hostElement = document.createElement('div'); const atomPanel = atom.workspace.addModalPanel({ item: hostElement, priority: options.priority, - className: options.className, + className: options.className }); - const shouldDismissOnClickOutsideModal = - options.shouldDismissOnClickOutsideModal || (() => true); - const shouldDismissOnPressEscape = - options.shouldDismissOnPressEscape || (() => true); + const shouldDismissOnClickOutsideModal = options.shouldDismissOnClickOutsideModal || (() => true); + const shouldDismissOnPressEscape = options.shouldDismissOnPressEscape || (() => true); const element = atomPanel.getElement(); const previouslyFocusedElement = document.activeElement; - const disposable = new UniversalDisposable( - Observable.fromEvent(document, 'mousedown').subscribe(({target}) => { - if (!shouldDismissOnClickOutsideModal()) { - return; - } - invariant(target instanceof Node); - if ( - !atomPanel.getItem().contains(target) && - // don't count clicks on notifications or tooltips as clicks 'outside' - target.closest('atom-notifications, .tooltip') == null - ) { - atomPanel.hide(); - } - }), - atomPanel.onDidChangeVisible(visible => { - if (!visible) { - disposable.dispose(); - } - }), - atom.commands.add('atom-workspace', 'core:cancel', () => { - if (shouldDismissOnPressEscape()) { - disposable.dispose(); - } - }), - () => { - // Call onDismiss before unmounting the component and destroying the panel: - if (options.onDismiss) { - options.onDismiss(); - } - ReactDOM.unmountComponentAtNode(hostElement); - atomPanel.destroy(); - if ( - document.activeElement === document.body && - previouslyFocusedElement != null - ) { - previouslyFocusedElement.focus(); - } - }, - ); - - ReactDOM.render( - - {contentFactory({dismiss: disposable.dispose.bind(disposable), element})} - , - hostElement, - () => { - if (options.onOpen) { - options.onOpen(); - } - }, - ); + const disposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(_rxjsBundlesRxMinJs.Observable.fromEvent(document, 'mousedown').subscribe(({ target }) => { + if (!shouldDismissOnClickOutsideModal()) { + return; + } + + if (!(target instanceof Node)) { + throw new Error('Invariant violation: "target instanceof Node"'); + } + + if (!atomPanel.getItem().contains(target) && + // don't count clicks on notifications or tooltips as clicks 'outside' + target.closest('atom-notifications, .tooltip') == null) { + atomPanel.hide(); + } + }), atomPanel.onDidChangeVisible(visible => { + if (!visible) { + disposable.dispose(); + } + }), atom.commands.add('atom-workspace', 'core:cancel', () => { + if (shouldDismissOnPressEscape()) { + disposable.dispose(); + } + }), () => { + // Call onDismiss before unmounting the component and destroying the panel: + if (options.onDismiss) { + options.onDismiss(); + } + _reactDom.default.unmountComponentAtNode(hostElement); + atomPanel.destroy(); + if (document.activeElement === document.body && previouslyFocusedElement != null) { + previouslyFocusedElement.focus(); + } + }); + + _reactDom.default.render(_react.createElement( + ModalContainer, + null, + contentFactory({ dismiss: disposable.dispose.bind(disposable), element }) + ), hostElement, () => { + if (options.onOpen) { + options.onOpen(); + } + }); return disposable; } /** Flow makes {} an unsealed object (eyeroll) */ -const defaults: Options = Object.freeze({}); - -type Props = { - children?: any, -}; +const defaults = Object.freeze({}); /** * Just exists to provide a div that we can focus on mount. This ensures we steal focus from any * editors or other panes while the modal is present. */ -class ModalContainer extends React.Component { - render(): React.Node { - return ( -
      - - {this.props.children} - -
      +class ModalContainer extends _react.Component { + render() { + return _react.createElement( + 'div', + { tabIndex: '-1' }, + _react.createElement( + (_TabbableContainer || _load_TabbableContainer()).default, + { contained: true }, + this.props.children + ) ); } - componentDidMount(): void { - const node = ReactDOM.findDOMNode(this); - invariant(node instanceof HTMLElement); + componentDidMount() { + const node = _reactDom.default.findDOMNode(this); + + if (!(node instanceof HTMLElement)) { + throw new Error('Invariant violation: "node instanceof HTMLElement"'); + } // Steal the focus away from any active editor or pane, setting it on the modal; // but don't steal focus away from a descendant. This can happen if a React element focuses // during its componentDidMount. For example, does this since the underlying // does not support the autofocus attribute. + + if (!node.contains(document.activeElement)) { node.focus(); } } -} +} \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/AtomInput-spec.js b/modules/nuclide-commons-ui/spec/AtomInput-spec.js index 741fc0c2..bacf9509 100644 --- a/modules/nuclide-commons-ui/spec/AtomInput-spec.js +++ b/modules/nuclide-commons-ui/spec/AtomInput-spec.js @@ -1,3 +1,27 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _promise; + +function _load_promise() { + return _promise = require('nuclide-commons/promise'); +} + +var _AtomInput; + +function _load_AtomInput() { + return _AtomInput = require('../AtomInput'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,51 +30,39 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import {sleep} from 'nuclide-commons/promise'; -import {AtomInput} from '../AtomInput'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; +let reactElement; -let reactElement: any; - -function createWithProps(props: any): any { +function createWithProps(props) { const hostEl = document.createElement('div'); - return ReactDOM.render(, hostEl); + return _reactDom.default.render(_react.createElement((_AtomInput || _load_AtomInput()).AtomInput, props), hostEl); } describe('AtomInput', () => { afterEach(() => { if (reactElement) { - ReactDOM.unmountComponentAtNode( - // $FlowFixMe - ReactDOM.findDOMNode(reactElement).parentNode, - ); + _reactDom.default.unmountComponentAtNode( + // $FlowFixMe + _reactDom.default.findDOMNode(reactElement).parentNode); } reactElement = null; }); it('honors the initialValue param', () => { - reactElement = createWithProps({initialValue: 'some text'}); + reactElement = createWithProps({ initialValue: 'some text' }); expect(reactElement.getText()).toBe('some text'); expect(reactElement.getTextEditor().getText()).toBe('some text'); }); it('focus() focuses the end of the line', () => { const initialValue = 'some text'; - reactElement = createWithProps({initialValue}); - expect(reactElement.getTextEditor().getCursorBufferPosition()).toEqual([ - 0, - 0, - ]); + reactElement = createWithProps({ initialValue }); + expect(reactElement.getTextEditor().getCursorBufferPosition()).toEqual([0, 0]); reactElement.focus(); - expect(reactElement.getTextEditor().getCursorBufferPosition()).toEqual([ - 0, - initialValue.length, - ]); + expect(reactElement.getTextEditor().getCursorBufferPosition()).toEqual([0, initialValue.length]); }); it('onDidChange() does not fire initially', () => { @@ -58,7 +70,7 @@ describe('AtomInput', () => { const onDidChange = jasmine.createSpy('onDidChange'); reactElement = createWithProps({ initialValue, - onDidChange, + onDidChange }); expect(onDidChange).not.toHaveBeenCalled(); @@ -66,7 +78,7 @@ describe('AtomInput', () => { it('onDidChange() is fired when the text changes', () => { const initialValue = 'some text'; - reactElement = createWithProps({initialValue}); + reactElement = createWithProps({ initialValue }); const onDidChange = jasmine.createSpy('onDidChange'); const disposable = reactElement.onDidChange(onDidChange); @@ -84,16 +96,15 @@ describe('AtomInput', () => { it('updates will stop firing when the component is unmounted', () => { const initialValue = 'some text'; const onDidChange = jasmine.createSpy('onDidChange'); - reactElement = createWithProps({initialValue, onDidChange}); + reactElement = createWithProps({ initialValue, onDidChange }); const textEditor = reactElement.getTextEditor(); textEditor.setText('the new text'); expect(onDidChange.calls.length).toBe(1); - ReactDOM.unmountComponentAtNode( - // $FlowFixMe - ReactDOM.findDOMNode(reactElement).parentNode, - ); + _reactDom.default.unmountComponentAtNode( + // $FlowFixMe + _reactDom.default.findDOMNode(reactElement).parentNode); reactElement = null; textEditor.setText('even more new text'); @@ -101,17 +112,17 @@ describe('AtomInput', () => { }); it('does not leak TextEditorComponent', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { jasmine.useRealClock(); const hostEl = document.createElement('div'); - const component = ReactDOM.render(, hostEl); + const component = _reactDom.default.render(_react.createElement((_AtomInput || _load_AtomInput()).AtomInput, null), hostEl); const textEditor = component.getTextEditor(); const element = textEditor.getElement(); - ReactDOM.unmountComponentAtNode(hostEl); + _reactDom.default.unmountComponentAtNode(hostEl); // Cleanup occurs during the next tick. - await sleep(0); + yield (0, (_promise || _load_promise()).sleep)(0); expect(element.component).toBe(null); - }); + })); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/AtomTextEditor-spec.js b/modules/nuclide-commons-ui/spec/AtomTextEditor-spec.js index b82b6639..a9d5f609 100644 --- a/modules/nuclide-commons-ui/spec/AtomTextEditor-spec.js +++ b/modules/nuclide-commons-ui/spec/AtomTextEditor-spec.js @@ -1,21 +1,32 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import {sleep} from 'nuclide-commons/promise'; -import {AtomTextEditor} from '../AtomTextEditor'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; -import invariant from 'assert'; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _promise; + +function _load_promise() { + return _promise = require('nuclide-commons/promise'); +} + +var _AtomTextEditor; + +function _load_AtomTextEditor() { + return _AtomTextEditor = require('../AtomTextEditor'); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _testUtils; + +function _load_testUtils() { + return _testUtils = _interopRequireDefault(require('react-dom/test-utils')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('nuclide-ui-atom-text-editor', () => { describe('when its `path` is set', () => { @@ -34,9 +45,7 @@ describe('nuclide-ui-atom-text-editor', () => { it('loads the desired `Grammar`', () => { // $FlowIgnore - const element: AtomTextEditor = TestUtils.renderIntoDocument( - , - ); + const element = (_testUtils || _load_testUtils()).default.renderIntoDocument(_react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { path: '.test' })); expect(element.getModel().getGrammar().scopeName).toEqual('text.test'); }); }); @@ -51,34 +60,40 @@ describe('nuclide-ui-atom-text-editor', () => { }); afterEach(() => { - invariant(grammar1 != null); + if (!(grammar1 != null)) { + throw new Error('Invariant violation: "grammar1 != null"'); + } + atom.grammars.removeGrammarForScopeName(grammar1.scopeName); - invariant(grammar2 != null); + + if (!(grammar2 != null)) { + throw new Error('Invariant violation: "grammar2 != null"'); + } + atom.grammars.removeGrammarForScopeName(grammar2.scopeName); }); it('updates the underlying models grammar', () => { // $FlowIgnore - const element: AtomTextEditor = TestUtils.renderIntoDocument( - , - ); + const element = (_testUtils || _load_testUtils()).default.renderIntoDocument(_react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { path: '.test', grammar: grammar2 })); expect(element.getModel().getGrammar().scopeName).toEqual('text.test2'); }); }); describe('when `readOnly`', () => { - let element: AtomTextEditor; + let element; describe('is true', () => { beforeEach(() => { // $FlowIgnore - element = TestUtils.renderIntoDocument( - , - ); + element = (_testUtils || _load_testUtils()).default.renderIntoDocument(_react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, { readOnly: true })); }); it('allows copying', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('fraggle'); model.selectAll(); @@ -87,7 +102,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('disallows inserting', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('foobar'); model.insertNewline(); @@ -95,7 +113,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('disallows pasting', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); atom.clipboard.write('foo bar baz'); model.pasteText(); @@ -103,7 +124,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('disallows deleting text', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('balloon'); model.selectAll(); @@ -112,7 +136,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('disallows backspace', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('foobar'); model.moveToEndOfLine(); @@ -124,11 +151,14 @@ describe('nuclide-ui-atom-text-editor', () => { describe('is undefined', () => { beforeEach(() => { // $FlowIgnore - element = TestUtils.renderIntoDocument(); + element = (_testUtils || _load_testUtils()).default.renderIntoDocument(_react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, null)); }); it('allows copying', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('fraggle'); model.selectAll(); @@ -137,7 +167,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('allows inserting', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('foobar'); model.insertNewline(); @@ -145,7 +178,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('allows pasting', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); atom.clipboard.write('foo bar baz'); model.pasteText(); @@ -153,7 +189,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('allows deleting text', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('balloon'); model.selectAll(); @@ -162,7 +201,10 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('allows backspace', () => { - invariant(element); + if (!element) { + throw new Error('Invariant violation: "element"'); + } + const model = element.getModel(); model.setText('foobar'); model.moveToEndOfLine(); @@ -173,17 +215,27 @@ describe('nuclide-ui-atom-text-editor', () => { }); it('does not leak TextEditorComponent', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { jasmine.useRealClock(); const hostEl = document.createElement('div'); - const component = ReactDOM.render(, hostEl); + const component = _reactDom.default.render(_react.createElement((_AtomTextEditor || _load_AtomTextEditor()).AtomTextEditor, null), hostEl); const textEditor = component.getModel(); const element = textEditor.getElement(); - ReactDOM.unmountComponentAtNode(hostEl); + _reactDom.default.unmountComponentAtNode(hostEl); // Cleanup occurs during the next tick. - await sleep(0); + yield (0, (_promise || _load_promise()).sleep)(0); expect(element.component).toBe(null); - }); + })); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/Checkbox-spec.js b/modules/nuclide-commons-ui/spec/Checkbox-spec.js index 8563b77a..629e8fdf 100644 --- a/modules/nuclide-commons-ui/spec/Checkbox-spec.js +++ b/modules/nuclide-commons-ui/spec/Checkbox-spec.js @@ -1,25 +1,45 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import {Checkbox} from '../Checkbox'; -import nullthrows from 'nullthrows'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -let hostEl; +'use strict'; + +var _Checkbox; + +function _load_Checkbox() { + return _Checkbox = require('../Checkbox'); +} + +var _nullthrows; + +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _testUtils; + +function _load_testUtils() { + return _testUtils = _interopRequireDefault(require('react-dom/test-utils')); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +let hostEl; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ function createWithProps(props) { - return ReactDOM.render(, nullthrows(hostEl)); + return _reactDom.default.render(_react.createElement((_Checkbox || _load_Checkbox()).Checkbox, props), (0, (_nullthrows || _load_nullthrows()).default)(hostEl)); } describe('Checkbox', () => { @@ -28,7 +48,7 @@ describe('Checkbox', () => { }); afterEach(() => { - ReactDOM.unmountComponentAtNode(hostEl); + _reactDom.default.unmountComponentAtNode(hostEl); hostEl = null; }); @@ -37,14 +57,12 @@ describe('Checkbox', () => { const reactElement = createWithProps({ checked: false, label: 'click me!', - onChange, + onChange }); - const inputEl = nullthrows( - TestUtils.findRenderedDOMComponentWithTag(reactElement, 'input'), - ); + const inputEl = (0, (_nullthrows || _load_nullthrows()).default)((_testUtils || _load_testUtils()).default.findRenderedDOMComponentWithTag(reactElement, 'input')); // Unfortunately, TestUtils does not seem to turn a click into a change event for a checkbox. - TestUtils.Simulate.change(inputEl); + (_testUtils || _load_testUtils()).default.Simulate.change(inputEl); expect(onChange.callCount).toBe(1); // Nor does it seem to change the state of the checkbox, as the following fails: @@ -57,13 +75,11 @@ describe('Checkbox', () => { checked: false, indeterminate: true, label: 'click me!', - onChange() {}, + onChange() {} }); - const inputEl = nullthrows( - TestUtils.findRenderedDOMComponentWithTag(reactElement, 'input'), - ); + const inputEl = (0, (_nullthrows || _load_nullthrows()).default)((_testUtils || _load_testUtils()).default.findRenderedDOMComponentWithTag(reactElement, 'input')); // $FlowFixMe(>=0.66.0) Flow suppress expect(inputEl.indeterminate).toBe(true); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/ClickOutsideBoundry-spec.js b/modules/nuclide-commons-ui/spec/ClickOutsideBoundry-spec.js index 65bcbb54..6f0e4cc2 100644 --- a/modules/nuclide-commons-ui/spec/ClickOutsideBoundry-spec.js +++ b/modules/nuclide-commons-ui/spec/ClickOutsideBoundry-spec.js @@ -1,3 +1,31 @@ +'use strict'; + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = require('react-dom'); + +var _ClickOutsideBoundary; + +function _load_ClickOutsideBoundary() { + return _ClickOutsideBoundary = _interopRequireDefault(require('../ClickOutsideBoundary')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +const clickId = id => { + const node = document.getElementById(id); + + if (!(node != null)) { + throw new Error(`node ${id} should be present in the DOM`); + } + + node.click(); +}; + +// A component which removes itself from the DOM when clicked. +// $FlowFixMe(>=0.53.0) Flow suppress /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,38 +34,26 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import * as React from 'react'; -import invariant from 'assert'; -import {render} from 'react-dom'; -import ClickOutsideBoundary from '../ClickOutsideBoundary'; - -const clickId = (id: string) => { - const node = document.getElementById(id); - invariant(node != null, `node ${id} should be present in the DOM`); - node.click(); -}; - -// A component which removes itself from the DOM when clicked. -// $FlowFixMe(>=0.53.0) Flow suppress -class ClickAway extends React.Component<$FlowFixMeProps, $FlowFixMeState> { +class ClickAway extends _react.Component { constructor(props) { super(props); - this.state = {visible: true}; - } - handleClick = () => { - this.setState({visible: false}); - }; + this.handleClick = () => { + this.setState({ visible: false }); + }; + + this.state = { visible: true }; + } render() { - return this.state.visible ? ( - - Click to dismiss - + return this.state.visible ? _react.createElement( + 'span', + Object.assign({}, this.props, { onClick: this.handleClick }), + 'Click to dismiss' ) : null; } } @@ -58,28 +74,30 @@ describe('ClickOutsideBoundary - onClickOutside handler', () => { describe('_is_ called for an external click', () => { it('on a parent', () => { - render( -
      - -
      - -
      , - app, - ); + (0, _reactDom.render)(_react.createElement( + 'div', + { id: 'container' }, + _react.createElement( + (_ClickOutsideBoundary || _load_ClickOutsideBoundary()).default, + { onClickOutside: onClickOutside }, + _react.createElement('div', { id: 'target' }) + ) + ), app); clickId('container'); expect(onClickOutside).toHaveBeenCalled(); }); it('on a sibling', () => { - render( -
      - -
      - -
      -
      , - app, - ); + (0, _reactDom.render)(_react.createElement( + 'div', + null, + _react.createElement( + (_ClickOutsideBoundary || _load_ClickOutsideBoundary()).default, + { onClickOutside: onClickOutside }, + _react.createElement('div', { id: 'target' }) + ), + _react.createElement('div', { id: 'sibling' }) + ), app); clickId('sibling'); expect(onClickOutside).toHaveBeenCalled(); }); @@ -87,15 +105,16 @@ describe('ClickOutsideBoundary - onClickOutside handler', () => { it('on a sibling that disappears after render', () => { // This would fail if we tool the approach of ignoring all // clicks on elements that were not in the DOM. - render( -
      - -
      - - -
      , - app, - ); + (0, _reactDom.render)(_react.createElement( + 'div', + null, + _react.createElement( + (_ClickOutsideBoundary || _load_ClickOutsideBoundary()).default, + { onClickOutside: onClickOutside }, + _react.createElement('div', { id: 'target' }) + ), + _react.createElement(ClickAway, { id: 'click-away' }) + ), app); clickId('click-away'); expect(onClickOutside).toHaveBeenCalled(); }); @@ -103,12 +122,11 @@ describe('ClickOutsideBoundary - onClickOutside handler', () => { describe('is _not_ called for an internal click', () => { it('under normal conditions', () => { - render( - -
      - , - app, - ); + (0, _reactDom.render)(_react.createElement( + (_ClickOutsideBoundary || _load_ClickOutsideBoundary()).default, + { onClickOutside: onClickOutside }, + _react.createElement('div', { id: 'target' }) + ), app); clickId('target'); expect(onClickOutside).not.toHaveBeenCalled(); }); @@ -116,17 +134,18 @@ describe('ClickOutsideBoundary - onClickOutside handler', () => { it('when the target leaves the DOM before the event reaches window.document', () => { // A simple approach: `this.rootNode.contains(e.target)` would fail this test. const onClickInside = jasmine.createSpy('onClickInside'); - render( - -
      - -
      -
      , - app, - ); + (0, _reactDom.render)(_react.createElement( + (_ClickOutsideBoundary || _load_ClickOutsideBoundary()).default, + { onClickOutside: onClickOutside }, + _react.createElement( + 'div', + { onClick: onClickInside }, + _react.createElement(ClickAway, { id: 'click-away' }) + ) + ), app); clickId('click-away'); expect(onClickInside).toHaveBeenCalled(); expect(onClickOutside).not.toHaveBeenCalled(); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/NuclideRadioGroup-spec.js b/modules/nuclide-commons-ui/spec/NuclideRadioGroup-spec.js index d04bf3f8..34289a63 100644 --- a/modules/nuclide-commons-ui/spec/NuclideRadioGroup-spec.js +++ b/modules/nuclide-commons-ui/spec/NuclideRadioGroup-spec.js @@ -1,67 +1,71 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -/* global Element */ +var _RadioGroup; + +function _load_RadioGroup() { + return _RadioGroup = _interopRequireDefault(require('../RadioGroup')); +} + +var _react = _interopRequireWildcard(require('react')); + +var _reactDom = _interopRequireDefault(require('react-dom')); + +var _testUtils; + +function _load_testUtils() { + return _testUtils = _interopRequireDefault(require('react-dom/test-utils')); +} -import invariant from 'assert'; -import RadioGroup from '../RadioGroup'; -import * as React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const { Simulate, renderIntoDocument, - scryRenderedDOMComponentsWithTag, -} = TestUtils; + scryRenderedDOMComponentsWithTag +} = (_testUtils || _load_testUtils()).default; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +/* global Element */ describe('RadioGroup', () => { it('honors the selectedIndex param', () => { - const component = renderIntoDocument( - , - ); + const component = renderIntoDocument(_react.createElement((_RadioGroup || _load_RadioGroup()).default, { optionLabels: ['foo', 'bar'], selectedIndex: 1 })); expect(component.props.selectedIndex).toBe(1); const radioInputs = scryRenderedDOMComponentsWithTag(component, 'input'); // $FlowFixMe - expect(ReactDOM.findDOMNode(radioInputs[0]).checked).toBe(false); + expect(_reactDom.default.findDOMNode(radioInputs[0]).checked).toBe(false); // $FlowFixMe - expect(ReactDOM.findDOMNode(radioInputs[1]).checked).toBe(true); + expect(_reactDom.default.findDOMNode(radioInputs[1]).checked).toBe(true); }); it('should use the correct, unique radio group name', () => { - const props = {optionLabels: ['foo', 'bar'], selectedIndex: 1}; - const component = renderIntoDocument(); + const props = { optionLabels: ['foo', 'bar'], selectedIndex: 1 }; + const component = renderIntoDocument(_react.createElement((_RadioGroup || _load_RadioGroup()).default, props)); const radioInputs = scryRenderedDOMComponentsWithTag(component, 'input'); // Global uid is `1` as this point, since this is the second RadioGroup component to be created. // $FlowFixMe - expect(ReactDOM.findDOMNode(radioInputs[0]).getAttribute('name')).toEqual( - 'radiogroup-1', - ); + expect(_reactDom.default.findDOMNode(radioInputs[0]).getAttribute('name')).toEqual('radiogroup-1'); // $FlowFixMe - expect(ReactDOM.findDOMNode(radioInputs[1]).getAttribute('name')).toEqual( - 'radiogroup-1', - ); - const component2 = renderIntoDocument(); + expect(_reactDom.default.findDOMNode(radioInputs[1]).getAttribute('name')).toEqual('radiogroup-1'); + const component2 = renderIntoDocument(_react.createElement((_RadioGroup || _load_RadioGroup()).default, props)); const radioInputs2 = scryRenderedDOMComponentsWithTag(component2, 'input'); // $FlowFixMe - expect(ReactDOM.findDOMNode(radioInputs2[0]).getAttribute('name')).toEqual( - 'radiogroup-2', - ); + expect(_reactDom.default.findDOMNode(radioInputs2[0]).getAttribute('name')).toEqual('radiogroup-2'); // $FlowFixMe - expect(ReactDOM.findDOMNode(radioInputs2[1]).getAttribute('name')).toEqual( - 'radiogroup-2', - ); + expect(_reactDom.default.findDOMNode(radioInputs2[1]).getAttribute('name')).toEqual('radiogroup-2'); }); it('calls its onSelectedChange handler when a radio input is changed', () => { @@ -70,16 +74,23 @@ describe('RadioGroup', () => { const props = { optionLabels: ['foo', 'bar'], selectedIndex: 0, - onSelectedChange, + onSelectedChange }; - const component = renderIntoDocument(); + const component = renderIntoDocument(_react.createElement((_RadioGroup || _load_RadioGroup()).default, props)); const radioInputs = scryRenderedDOMComponentsWithTag(component, 'input'); const secondRadioElement = radioInputs[1]; - invariant(secondRadioElement instanceof Element); - const foundRadio = ReactDOM.findDOMNode(secondRadioElement); - invariant(foundRadio instanceof Element); + if (!(secondRadioElement instanceof Element)) { + throw new Error('Invariant violation: "secondRadioElement instanceof Element"'); + } + + const foundRadio = _reactDom.default.findDOMNode(secondRadioElement); + + if (!(foundRadio instanceof Element)) { + throw new Error('Invariant violation: "foundRadio instanceof Element"'); + } + Simulate.change(foundRadio); expect(onSelectedChange.mostRecentCall.args[0]).toEqual(1); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/ReactMountRootElement-spec.js b/modules/nuclide-commons-ui/spec/ReactMountRootElement-spec.js index 028c9b94..afa96786 100644 --- a/modules/nuclide-commons-ui/spec/ReactMountRootElement-spec.js +++ b/modules/nuclide-commons-ui/spec/ReactMountRootElement-spec.js @@ -1,3 +1,5 @@ +'use strict'; + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +8,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -22,4 +24,4 @@ describe('ReactMountRootElement', () => { const createdElement = new element2(); expect(createdElement.constructor.name).toBe('nuclide-react-mount-root'); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/Table-spec.js b/modules/nuclide-commons-ui/spec/Table-spec.js index 5502f8c2..773a86a5 100644 --- a/modules/nuclide-commons-ui/spec/Table-spec.js +++ b/modules/nuclide-commons-ui/spec/Table-spec.js @@ -1,30 +1,21 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +var _Table; -import { - _calculateColumnWidths, - _calculatePreferredColumnWidths, -} from '../Table'; +function _load_Table() { + return _Table = require('../Table'); +} describe('Table', () => { it('correctly distributes widths according to percentage, regardless of min width', () => { - const calculated = _calculateColumnWidths({ - preferredWidths: {a: 0.5, b: 0.5}, - minWidths: {a: 25, b: 50}, + const calculated = (0, (_Table || _load_Table())._calculateColumnWidths)({ + preferredWidths: { a: 0.5, b: 0.5 }, + minWidths: { a: 25, b: 50 }, tableWidth: 100, columnOrder: ['a', 'b'], - resizeOffset: null, + resizeOffset: null }); - expectClose(calculated, {a: 0.5, b: 0.5}); + expectClose(calculated, { a: 0.5, b: 0.5 }); }); it("doesn't change the column widths when a resize is ended", () => { @@ -33,70 +24,82 @@ describe('Table', () => { // all of the column widths MUST be continuous; in other words, the widths calculated from your // new distribution preferences must match the width calculated from your old distribution // preferences at that drag offset. - const minWidths = {a: 25, b: 50}; + const minWidths = { a: 25, b: 50 }; const tableWidth = 100; const columnOrder = ['a', 'b']; - const duringDrag = _calculateColumnWidths({ - preferredWidths: {a: 0.5, b: 0.5}, - resizeOffset: {resizerLocation: 0, deltaPx: -10}, + const duringDrag = (0, (_Table || _load_Table())._calculateColumnWidths)({ + preferredWidths: { a: 0.5, b: 0.5 }, + resizeOffset: { resizerLocation: 0, deltaPx: -10 }, minWidths, tableWidth, - columnOrder, + columnOrder }); - expect(duringDrag).toEqual({a: 0.4, b: 0.6}); - const afterDrag = _calculateColumnWidths({ - preferredWidths: _calculatePreferredColumnWidths({ + expect(duringDrag).toEqual({ a: 0.4, b: 0.6 }); + const afterDrag = (0, (_Table || _load_Table())._calculateColumnWidths)({ + preferredWidths: (0, (_Table || _load_Table())._calculatePreferredColumnWidths)({ currentWidths: duringDrag, minWidths, - tableWidth, + tableWidth }), resizeOffset: null, minWidths, tableWidth, - columnOrder, + columnOrder }); expectClose(afterDrag, duringDrag); }); it("doesn't allow resizing below a column's min width", () => { - const calculated = _calculateColumnWidths({ - preferredWidths: {a: 0.5, b: 0.5}, - minWidths: {a: 25, b: 50}, + const calculated = (0, (_Table || _load_Table())._calculateColumnWidths)({ + preferredWidths: { a: 0.5, b: 0.5 }, + minWidths: { a: 25, b: 50 }, tableWidth: 100, columnOrder: ['a', 'b'], - resizeOffset: {resizerLocation: 0, deltaPx: -50}, + resizeOffset: { resizerLocation: 0, deltaPx: -50 } }); - expectClose(calculated, {a: 0.25, b: 0.75}); + expectClose(calculated, { a: 0.25, b: 0.75 }); }); it('recognizes when a column is at its min width when calculating preferred distributions', () => { - const preferredWidths = _calculatePreferredColumnWidths({ - currentWidths: {a: 0.2, b: 0.2, c: 0.6}, - minWidths: {a: 25, b: 0, c: 0}, - tableWidth: 100, + const preferredWidths = (0, (_Table || _load_Table())._calculatePreferredColumnWidths)({ + currentWidths: { a: 0.2, b: 0.2, c: 0.6 }, + minWidths: { a: 25, b: 0, c: 0 }, + tableWidth: 100 }); // The user prefers "a" to be at its min width, i.e. have a 0 distribution, and the other // columns to have a 1:3 ratio. - expectClose(preferredWidths, {a: 0, b: 0.25, c: 0.75}); + expectClose(preferredWidths, { a: 0, b: 0.25, c: 0.75 }); }); it('shrinks multiple columns to their minimum if it has to in order to accomodate your resize', () => { - const calculated = _calculateColumnWidths({ - preferredWidths: {a: 0.25, b: 0.25, c: 0.25, d: 0.25}, - minWidths: {a: 10, b: 10, c: 10, d: 10}, + const calculated = (0, (_Table || _load_Table())._calculateColumnWidths)({ + preferredWidths: { a: 0.25, b: 0.25, c: 0.25, d: 0.25 }, + minWidths: { a: 10, b: 10, c: 10, d: 10 }, tableWidth: 100, columnOrder: ['a', 'b', 'c', 'd'], - resizeOffset: {resizerLocation: 0, deltaPx: 35}, + resizeOffset: { resizerLocation: 0, deltaPx: 35 } }); - expectClose(calculated, {a: 0.6, b: 0.1, c: 0.1, d: 0.2}); + expectClose(calculated, { a: 0.6, b: 0.1, c: 0.1, d: 0.2 }); }); }); // Because we're dealing with percentages represented as floating point numbers, a little bit of // deviation is expected. (`1 - 0.1 - 0.1 - 0.1 !== 0.7`) +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + const expectClose = (a, b) => { expect(Object.keys(a).length).toBe(Object.keys(b).length); Object.keys(a).forEach(k => { expect(a[k]).toBeCloseTo(b[k], 10); }); -}; +}; \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/highlightText-spec.js b/modules/nuclide-commons-ui/spec/highlightText-spec.js index d3ea886a..04741d7d 100644 --- a/modules/nuclide-commons-ui/spec/highlightText-spec.js +++ b/modules/nuclide-commons-ui/spec/highlightText-spec.js @@ -1,50 +1,56 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import highlightText from '../highlightText'; +'use strict'; + +var _highlightText; + +function _load_highlightText() { + return _highlightText = _interopRequireDefault(require('../highlightText')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('highlightText', () => { it('returns no ranges for no interpolated text', () => { - expect(highlightText`foo bar baz`).toEqual({ + expect((_highlightText || _load_highlightText()).default`foo bar baz`).toEqual({ text: 'foo bar baz', - matchRanges: [], + matchRanges: [] }); }); it('returns ranges to highlight interpolated values', () => { - expect(highlightText`foo ${1 + 2} bar ${'baz'} baz`).toEqual({ + expect((_highlightText || _load_highlightText()).default`foo ${1 + 2} bar ${'baz'} baz`).toEqual({ text: 'foo 3 bar baz baz', - matchRanges: [[4, 5], [10, 13]], + matchRanges: [[4, 5], [10, 13]] }); }); it("highlights the entire string if it's entirely interpolated", () => { - expect(highlightText`${'hello'}`).toEqual({ + expect((_highlightText || _load_highlightText()).default`${'hello'}`).toEqual({ text: 'hello', - matchRanges: [[0, 5]], + matchRanges: [[0, 5]] }); }); it('works with an interpolated value at the beginning', () => { - expect(highlightText`${1 + 2} bar ${'baz'} baz`).toEqual({ + expect((_highlightText || _load_highlightText()).default`${1 + 2} bar ${'baz'} baz`).toEqual({ text: '3 bar baz baz', - matchRanges: [[0, 1], [6, 9]], + matchRanges: [[0, 1], [6, 9]] }); }); it('works with an interpolated value at the end', () => { - expect(highlightText`foo ${1 + 2} bar ${'baz'}`).toEqual({ + expect((_highlightText || _load_highlightText()).default`foo ${1 + 2} bar ${'baz'}`).toEqual({ text: 'foo 3 bar baz', - matchRanges: [[4, 5], [10, 13]], + matchRanges: [[4, 5], [10, 13]] }); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/observable-dom-spec.js b/modules/nuclide-commons-ui/spec/observable-dom-spec.js index 7a08035b..8fce33be 100644 --- a/modules/nuclide-commons-ui/spec/observable-dom-spec.js +++ b/modules/nuclide-commons-ui/spec/observable-dom-spec.js @@ -1,3 +1,17 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _observableDom; + +function _load_observableDom() { + return _observableDom = require('../observable-dom'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,15 +20,10 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import invariant from 'assert'; -import {Observable} from 'rxjs'; - -import {_DOMObserverObservable as DOMObserverObservable} from '../observable-dom'; - describe('new DOMObserverObservable', () => { let observerInstance; @@ -23,16 +32,13 @@ describe('new DOMObserverObservable', () => { }); class MockDOMObserver { - _args: Array; - _callback: Function; - _connected: boolean; constructor(callback) { this._callback = callback; observerInstance = this; } - observe(...args: any[]) { + observe(...args) { this._args = args; this._connected = true; } @@ -44,76 +50,64 @@ describe('new DOMObserverObservable', () => { it('does not construct a DOM Observer until the Rx Observable is subscribed to', () => { // $FlowFixMe(>=0.55.0) Flow suppress - const o = new DOMObserverObservable(MockDOMObserver, 'some', 'additional', { - args: true, + const o = new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserver, 'some', 'additional', { + args: true }); expect(observerInstance).toBe(null); const subscription = o.subscribe(() => {}); - invariant(observerInstance != null); - expect(observerInstance._args).toEqual([ - 'some', - 'additional', - {args: true}, - ]); + + if (!(observerInstance != null)) { + throw new Error('Invariant violation: "observerInstance != null"'); + } + + expect(observerInstance._args).toEqual(['some', 'additional', { args: true }]); expect(observerInstance._connected).toBe(true); subscription.unsubscribe(); }); it('calls disconnect on the underlying DOM Observer when unsubscribe is called', () => { - const o = new DOMObserverObservable(MockDOMObserver, 'some', 'additional', { - args: true, + const o = new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserver, 'some', 'additional', { + args: true }); const subscription = o.subscribe(() => {}); - invariant(observerInstance != null); + if (!(observerInstance != null)) { + throw new Error('Invariant violation: "observerInstance != null"'); + } + expect(observerInstance._connected).toBe(true); subscription.unsubscribe(); expect(observerInstance._connected).toBe(false); }); - it( - 'by default (without a call to .flattenEntries()) creates an observable of ' + - 'the elements emitted from the DOM Observer', - () => { - class MockDOMObserverEmitsArray extends MockDOMObserver { - observe(...args: Array) { - super.observe(...args); - Observable.interval(1) - .mapTo(['foo', 'bar', 'baz']) - .take(2) - .subscribe(this._callback); - } + it('by default (without a call to .flattenEntries()) creates an observable of ' + 'the elements emitted from the DOM Observer', () => { + class MockDOMObserverEmitsArray extends MockDOMObserver { + observe(...args) { + super.observe(...args); + _rxjsBundlesRxMinJs.Observable.interval(1).mapTo(['foo', 'bar', 'baz']).take(2).subscribe(this._callback); } + } - waitsForPromise(async () => { - const output = await new DOMObserverObservable( - MockDOMObserverEmitsArray, - 'arg', - ) - .take(2) - .toArray() - .toPromise(); - expect(output).toEqual([['foo', 'bar', 'baz'], ['foo', 'bar', 'baz']]); - }); - }, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserverEmitsArray, 'arg').take(2).toArray().toPromise(); + expect(output).toEqual([['foo', 'bar', 'baz'], ['foo', 'bar', 'baz']]); + })); + }); describe('multiple subscribers', () => { it('only disconnects the underlying observer when all subscribers have unsubscribed', () => { - const o = new DOMObserverObservable( - MockDOMObserver, - 'some', - 'additional', - { - args: true, - }, - ); + const o = new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserver, 'some', 'additional', { + args: true + }); const subscription = o.subscribe(() => {}); const subscription2 = o.subscribe(() => {}); - invariant(observerInstance != null); + if (!(observerInstance != null)) { + throw new Error('Invariant violation: "observerInstance != null"'); + } + expect(observerInstance._connected).toBe(true); subscription.unsubscribe(); @@ -128,139 +122,95 @@ describe('new DOMObserverObservable', () => { expect(observerInstance._connected).toBe(false); }); - it( - 'creates a new underlying observable and connects it for new' + - 'subscriptions that happen after a disconnect', - () => { - const o = new DOMObserverObservable( - MockDOMObserver, - 'some', - 'additional', - { - args: true, - }, - ); - const subscription = o.subscribe(() => {}); - const subscription2 = o.subscribe(() => {}); - - invariant(observerInstance != null); - const oldObserver = observerInstance; - - subscription.unsubscribe(); - subscription2.unsubscribe(); + it('creates a new underlying observable and connects it for new' + 'subscriptions that happen after a disconnect', () => { + const o = new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserver, 'some', 'additional', { + args: true + }); + const subscription = o.subscribe(() => {}); + const subscription2 = o.subscribe(() => {}); + + if (!(observerInstance != null)) { + throw new Error('Invariant violation: "observerInstance != null"'); + } - expect(observerInstance._connected).toBe(false); - const newSubscription = o.subscribe(() => {}); - // creates a new underlying observer - expect(observerInstance).not.toBe(oldObserver); - expect(observerInstance._connected).toBe(true); - newSubscription.unsubscribe(); - }, - ); + const oldObserver = observerInstance; + + subscription.unsubscribe(); + subscription2.unsubscribe(); + + expect(observerInstance._connected).toBe(false); + const newSubscription = o.subscribe(() => {}); + // creates a new underlying observer + expect(observerInstance).not.toBe(oldObserver); + expect(observerInstance._connected).toBe(true); + newSubscription.unsubscribe(); + }); }); describe('flattenEntries operator', () => { it('implements lift to cause subsequent operators to return DOMObserverObservables', () => { class MockDOMObserverEmitsArray extends MockDOMObserver { - observe(...args: Array) { + observe(...args) { super.observe(...args); - Observable.interval(1) - .mapTo(['foo', 'bar', 'baz']) - .take(2) - .subscribe(this._callback); + _rxjsBundlesRxMinJs.Observable.interval(1).mapTo(['foo', 'bar', 'baz']).take(2).subscribe(this._callback); } } - expect( - new DOMObserverObservable(MockDOMObserverEmitsArray, 'arg') - .flattenEntries() - .map(x => x) instanceof DOMObserverObservable, - ).toBe(true); + expect(new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserverEmitsArray, 'arg').flattenEntries().map(x => x) instanceof (_observableDom || _load_observableDom())._DOMObserverObservable).toBe(true); }); it('creates an observable of the individual elements of the array emitted from the DOM Observer', () => { class MockDOMObserverEmitsArray extends MockDOMObserver { - observe(...args: Array) { + observe(...args) { super.observe(...args); - Observable.interval(1) - .mapTo(['foo', 'bar', 'baz']) - .take(2) - .subscribe(this._callback); + _rxjsBundlesRxMinJs.Observable.interval(1).mapTo(['foo', 'bar', 'baz']).take(2).subscribe(this._callback); } } - waitsForPromise(async () => { - const output = await new DOMObserverObservable( - MockDOMObserverEmitsArray, - 'arg', - ) - .flattenEntries() - .take(6) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserverEmitsArray, 'arg').flattenEntries().take(6).toArray().toPromise(); expect(output).toEqual(['foo', 'bar', 'baz', 'foo', 'bar', 'baz']); - }); + })); }); - it( - 'creates an observable of the individual elements of the array returned ' + - 'from the getEntries method of the entrylist emitted from the DOM Observer', - () => { - class MockDOMObserverEmitsEntryList extends MockDOMObserver { - observe(...args: Array) { - super.observe(...args); - Observable.interval(1) - .mapTo({ - getEntries: () => ['foo', 'bar', 'baz'], - }) - .take(2) - .subscribe(this._callback); - } + it('creates an observable of the individual elements of the array returned ' + 'from the getEntries method of the entrylist emitted from the DOM Observer', () => { + class MockDOMObserverEmitsEntryList extends MockDOMObserver { + observe(...args) { + super.observe(...args); + _rxjsBundlesRxMinJs.Observable.interval(1).mapTo({ + getEntries: () => ['foo', 'bar', 'baz'] + }).take(2).subscribe(this._callback); } + } - waitsForPromise(async () => { - const output = await new DOMObserverObservable( - MockDOMObserverEmitsEntryList, - 'arg', - ) - .flattenEntries() - .take(6) - .toArray() - .toPromise(); - expect(output).toEqual(['foo', 'bar', 'baz', 'foo', 'bar', 'baz']); - }); - }, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserverEmitsEntryList, 'arg').flattenEntries().take(6).toArray().toPromise(); + expect(output).toEqual(['foo', 'bar', 'baz', 'foo', 'bar', 'baz']); + })); + }); it('throws if neither an iterable nor an EntryList is emitted from the DOM Observer', () => { class MockDOMObserverEmitsNonStandard extends MockDOMObserver { - observe(...args: Array) { + observe(...args) { super.observe(...args); - Observable.interval(1) - .take(2) - .subscribe(this._callback); + _rxjsBundlesRxMinJs.Observable.interval(1).take(2).subscribe(this._callback); } } - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await new DOMObserverObservable( - MockDOMObserverEmitsNonStandard, - 'arg', - ) - .flattenEntries() - .take(2) - .toArray() - .toPromise(); + yield new (_observableDom || _load_observableDom())._DOMObserverObservable(MockDOMObserverEmitsNonStandard, 'arg').flattenEntries().take(2).toArray().toPromise(); } catch (e) { error = e; } - invariant(error != null); - expect(error.message).toEqual( - 'Tried to merge DOM Observer entries, but they were not iterable nor were they an EntryList.', - ); - }); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + + expect(error.message).toEqual('Tried to merge DOM Observer entries, but they were not iterable nor were they an EntryList.'); + })); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons-ui/spec/openPreview-spec.js b/modules/nuclide-commons-ui/spec/openPreview-spec.js index 1254fd98..ce921d9a 100644 --- a/modules/nuclide-commons-ui/spec/openPreview-spec.js +++ b/modules/nuclide-commons-ui/spec/openPreview-spec.js @@ -1,18 +1,26 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import openPreview from '../openPreview'; -import fsPromise from 'nuclide-commons/fsPromise'; -import nullthrows from 'nullthrows'; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _openPreview; + +function _load_openPreview() { + return _openPreview = _interopRequireDefault(require('../openPreview')); +} + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('nuclide-commons/fsPromise')); +} + +var _nullthrows; + +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('openPreview', () => { // replace Jasmine's mocked setTimeout with another mock which immediately @@ -31,29 +39,29 @@ describe('openPreview', () => { let file; let fileItem; beforeEach(() => { - waitsForPromise(async () => { - file = await fsPromise.tempfile(); - await fsPromise.writeFile(file, 'foobarbaz\n'.repeat(1000)); - fileItem = await atom.workspace.open(file); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + file = yield (_fsPromise || _load_fsPromise()).default.tempfile(); + yield (_fsPromise || _load_fsPromise()).default.writeFile(file, 'foobarbaz\n'.repeat(1000)); + fileItem = yield atom.workspace.open(file); + })); }); afterEach(() => { - fsPromise.unlink(file); + (_fsPromise || _load_fsPromise()).default.unlink(file); }); it('does not change the cursor position', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { expect(getActiveTextEditor().getURI()).toEqual(file); expect(getActiveTextEditor().getCursorBufferPosition()).toEqual({ row: 0, - column: 0, + column: 0 }); - await openPreview(file, { + yield (0, (_openPreview || _load_openPreview()).default)(file, { line: 700, column: 3, - center: true, + center: true })._promise; // this case shouldn't open any new editors @@ -64,9 +72,9 @@ describe('openPreview', () => { expect(getActiveTextEditor().getURI()).toEqual(file); expect(getActiveTextEditor().getCursorBufferPosition()).toEqual({ row: 0, - column: 0, + column: 0 }); - }); + })); }); }); @@ -75,50 +83,42 @@ describe('openPreview', () => { let previewingFile; beforeEach(() => { - waitsForPromise(async () => { - [startingFile, previewingFile] = await Promise.all([ - fsPromise.tempfile(), - fsPromise.tempfile(), - ]); - await atom.workspace.open(startingFile); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + [startingFile, previewingFile] = yield Promise.all([(_fsPromise || _load_fsPromise()).default.tempfile(), (_fsPromise || _load_fsPromise()).default.tempfile()]); + yield atom.workspace.open(startingFile); + })); }); afterEach(() => { - waitsForPromise(() => - Promise.all([ - fsPromise.unlink(startingFile), - fsPromise.unlink(previewingFile), - ]), - ); + waitsForPromise(() => Promise.all([(_fsPromise || _load_fsPromise()).default.unlink(startingFile), (_fsPromise || _load_fsPromise()).default.unlink(previewingFile)])); }); it('opens a preview pane editor pointed at the previewFile', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { expect(getActiveTextEditor().getURI()).toEqual(startingFile); expect(getActiveTextEditor().getCursorBufferPosition()).toEqual({ row: 0, - column: 0, + column: 0 }); - await openPreview(previewingFile)._promise; + yield (0, (_openPreview || _load_openPreview()).default)(previewingFile)._promise; expect(getActiveTextEditor().getURI()).toBe(previewingFile); // $FlowFixMe expect(getPendingItem().getURI()).toBe(previewingFile); - }); + })); }); it('leaves focus on the starting editor', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { expect(getActiveTextEditor().getURI()).toEqual(startingFile); expect(getActiveTextEditor().getCursorBufferPosition()).toEqual({ row: 0, - column: 0, + column: 0 }); - await openPreview(previewingFile)._promise; + yield (0, (_openPreview || _load_openPreview()).default)(previewingFile)._promise; expect(getActiveTextEditor().getURI()).toEqual(previewingFile); - }); + })); }); }); @@ -128,38 +128,24 @@ describe('openPreview', () => { let secondPreviewingFile; beforeEach(() => { - waitsForPromise(async () => { - [ - startingFile, - firstPreviewingFile, - secondPreviewingFile, - ] = await Promise.all([ - fsPromise.tempfile(), - fsPromise.tempfile(), - fsPromise.tempfile(), - ]); - await atom.workspace.open(startingFile); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + [startingFile, firstPreviewingFile, secondPreviewingFile] = yield Promise.all([(_fsPromise || _load_fsPromise()).default.tempfile(), (_fsPromise || _load_fsPromise()).default.tempfile(), (_fsPromise || _load_fsPromise()).default.tempfile()]); + yield atom.workspace.open(startingFile); + })); }); afterEach(() => { - waitsForPromise(() => - Promise.all([ - fsPromise.unlink(startingFile), - fsPromise.unlink(firstPreviewingFile), - fsPromise.unlink(secondPreviewingFile), - ]), - ); + waitsForPromise(() => Promise.all([(_fsPromise || _load_fsPromise()).default.unlink(startingFile), (_fsPromise || _load_fsPromise()).default.unlink(firstPreviewingFile), (_fsPromise || _load_fsPromise()).default.unlink(secondPreviewingFile)])); }); it('reuses the preview pane when openPreview is called multiple times', () => { - waitsForPromise(async () => { - await openPreview(firstPreviewingFile)._promise; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield (0, (_openPreview || _load_openPreview()).default)(firstPreviewingFile)._promise; const firstPendingItem = getPendingItem(); // $FlowFixMe expect(getPendingItem().getURI()).toBe(firstPreviewingFile); - await openPreview(secondPreviewingFile)._promise; + yield (0, (_openPreview || _load_openPreview()).default)(secondPreviewingFile)._promise; const secondPendingItem = getPendingItem(); // $FlowFixMe expect(getPendingItem().getURI()).toBe(secondPreviewingFile); @@ -170,18 +156,18 @@ describe('openPreview', () => { expect(secondPendingItem.isDestroyed()).toBe(false); expect(getPendingItem()).toBe(secondPendingItem); expect(secondPendingItem).toBe(getActiveTextEditor()); - }); + })); }); it('destroys all previews once an openable is confirmed', () => { - waitsForPromise(async () => { - await openPreview(firstPreviewingFile)._promise; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield (0, (_openPreview || _load_openPreview()).default)(firstPreviewingFile)._promise; const firstPendingItem = getPendingItem(); - const secondOpenable = openPreview(secondPreviewingFile); - await secondOpenable._promise; + const secondOpenable = (0, (_openPreview || _load_openPreview()).default)(secondPreviewingFile); + yield secondOpenable._promise; const secondPendingItem = getPendingItem(); - await secondOpenable.confirm(); + yield secondOpenable.confirm(); // $FlowFixMe expect(firstPendingItem.isDestroyed()).toBe(true); @@ -189,82 +175,85 @@ describe('openPreview', () => { expect(secondPendingItem.isDestroyed()).toBe(false); expect(getPendingItem()).not.toExist(); expect(secondPendingItem).toBe(getActiveTextEditor()); - }); + })); }); }); it('never reuses a non-pending pane', () => { - waitsForPromise(async () => { - const [startingFile, file1, file2] = await Promise.all([ - fsPromise.tempfile(), - fsPromise.tempfile(), - fsPromise.tempfile(), - ]); - await atom.workspace.open(startingFile); - - await openPreview(file1)._promise; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const [startingFile, file1, file2] = yield Promise.all([(_fsPromise || _load_fsPromise()).default.tempfile(), (_fsPromise || _load_fsPromise()).default.tempfile(), (_fsPromise || _load_fsPromise()).default.tempfile()]); + yield atom.workspace.open(startingFile); + + yield (0, (_openPreview || _load_openPreview()).default)(file1)._promise; // Open a preview back in the originating file, which is not pending - await openPreview(startingFile)._promise; + yield (0, (_openPreview || _load_openPreview()).default)(startingFile)._promise; expect(getActiveTextEditor()).not.toBe(getPendingItem()); // ...and make sure requesting a new preview does *not* reuse the original // file's pane item - await openPreview(file2)._promise; + yield (0, (_openPreview || _load_openPreview()).default)(file2)._promise; expect(getActiveTextEditor()).toBe(getPendingItem()); - await Promise.all([ - fsPromise.unlink(startingFile), - fsPromise.unlink(file1), - fsPromise.unlink(file2), - ]); - }); + yield Promise.all([(_fsPromise || _load_fsPromise()).default.unlink(startingFile), (_fsPromise || _load_fsPromise()).default.unlink(file1), (_fsPromise || _load_fsPromise()).default.unlink(file2)]); + })); }); it('throws when trying to confirm a preview that is not the latest', () => { - waitsForPromise(async () => { - const [file1, file2] = await Promise.all([ - fsPromise.tempfile(), - fsPromise.tempfile(), - ]); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const [file1, file2] = yield Promise.all([(_fsPromise || _load_fsPromise()).default.tempfile(), (_fsPromise || _load_fsPromise()).default.tempfile()]); - const preview1 = openPreview(file1); - openPreview(file2); + const preview1 = (0, (_openPreview || _load_openPreview()).default)(file1); + (0, (_openPreview || _load_openPreview()).default)(file2); - expect(() => preview1.confirm()).toThrow(); + expect(function () { + return preview1.confirm(); + }).toThrow(); - await Promise.all([fsPromise.unlink(file1), fsPromise.unlink(file2)]); - }); + yield Promise.all([(_fsPromise || _load_fsPromise()).default.unlink(file1), (_fsPromise || _load_fsPromise()).default.unlink(file2)]); + })); }); it('throws when calling confirm after cancel', () => { - waitsForPromise(async () => { - const file = await fsPromise.tempfile(); - const preview = openPreview(file); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const file = yield (_fsPromise || _load_fsPromise()).default.tempfile(); + const preview = (0, (_openPreview || _load_openPreview()).default)(file); preview.cancel(); - expect(() => preview.confirm()).toThrow(); + expect(function () { + return preview.confirm(); + }).toThrow(); - await fsPromise.unlink(file); - }); + yield (_fsPromise || _load_fsPromise()).default.unlink(file); + })); }); it('throws when calling cancel after confirm', () => { - waitsForPromise(async () => { - const file = await fsPromise.tempfile(); - const preview = openPreview(file); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const file = yield (_fsPromise || _load_fsPromise()).default.tempfile(); + const preview = (0, (_openPreview || _load_openPreview()).default)(file); preview.confirm(); - expect(() => preview.cancel()).toThrow(); + expect(function () { + return preview.cancel(); + }).toThrow(); - await fsPromise.unlink(file); - }); + yield (_fsPromise || _load_fsPromise()).default.unlink(file); + })); }); -}); - -function getActiveTextEditor(): atom$TextEditor { - return nullthrows(atom.workspace.getActiveTextEditor()); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function getActiveTextEditor() { + return (0, (_nullthrows || _load_nullthrows()).default)(atom.workspace.getActiveTextEditor()); } -function getPendingItem(): atom$PaneItem { - return nullthrows( - atom.workspace.paneForItem(getActiveTextEditor()), - ).getPendingItem(); -} +function getPendingItem() { + return (0, (_nullthrows || _load_nullthrows()).default)(atom.workspace.paneForItem(getActiveTextEditor())).getPendingItem(); +} \ No newline at end of file diff --git a/modules/nuclide-commons/BatchProcessedQueue.js b/modules/nuclide-commons/BatchProcessedQueue.js index 962e6570..44e97c7a 100644 --- a/modules/nuclide-commons/BatchProcessedQueue.js +++ b/modules/nuclide-commons/BatchProcessedQueue.js @@ -1,33 +1,22 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); -export type BatchHandler = (batch: Array) => void; // A Queue which will process elements at intervals, only if the // queue contains any elements. -export default class BatchProcessedQueue { - _batchPeriod: number; - _handler: BatchHandler; - _timeoutId: ?TimeoutID; - _items: Array; +class BatchProcessedQueue { - constructor(batchPeriod: number, handler: BatchHandler) { + constructor(batchPeriod, handler) { this._batchPeriod = batchPeriod; this._handler = handler; this._timeoutId = null; this._items = []; } - add(item: T): void { + add(item) { this._items.push(item); // eslint-disable-next-line eqeqeq if (this._timeoutId === null) { @@ -44,7 +33,7 @@ export default class BatchProcessedQueue { this._handler(batch); } - dispose(): void { + dispose() { // eslint-disable-next-line eqeqeq if (this._timeoutId !== null) { clearTimeout(this._timeoutId); @@ -52,3 +41,14 @@ export default class BatchProcessedQueue { } } } +exports.default = BatchProcessedQueue; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/ConfigCache.js b/modules/nuclide-commons/ConfigCache.js index f4ddbddc..fc08e566 100644 --- a/modules/nuclide-commons/ConfigCache.js +++ b/modules/nuclide-commons/ConfigCache.js @@ -1,3 +1,26 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ConfigCache = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _lruCache; + +function _load_lruCache() { + return _lruCache = _interopRequireDefault(require('lru-cache')); +} + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('./fsPromise')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,36 +29,22 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import type {LRUCache} from 'lru-cache'; -import type {NuclideUri} from './nuclideUri'; - -import LRU from 'lru-cache'; -import fsPromise from './fsPromise'; - -export type SearchStrategy = 'nearest' | 'furthest' | 'priority'; - -export class ConfigCache { - _configFileNames: Array; - _searchStrategy: SearchStrategy; - _configCache: LRUCache>; +class ConfigCache { - constructor( - configFileNames: Array, - searchStrategy?: SearchStrategy = 'nearest', - ) { + constructor(configFileNames, searchStrategy = 'nearest') { this._configFileNames = configFileNames; this._searchStrategy = searchStrategy; - this._configCache = LRU({ + this._configCache = (0, (_lruCache || _load_lruCache()).default)({ max: 200, // Want this to exceed the maximum expected number of open files + dirs. - maxAge: 1000 * 30, // 30 seconds + maxAge: 1000 * 30 // 30 seconds }); } - getConfigDir(path: NuclideUri): Promise { + getConfigDir(path) { let result = this._configCache.get(path); if (result == null) { result = this._findConfigDir(path); @@ -44,39 +53,42 @@ export class ConfigCache { return result; } - async _findConfigDir(path: NuclideUri): Promise { - const configDirs = await Promise.all( - this._configFileNames.map(configFile => { - if (this._searchStrategy === 'furthest') { - return fsPromise.findFurthestFile(configFile, path); + _findConfigDir(path) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + const configDirs = yield Promise.all(_this._configFileNames.map(function (configFile) { + if (_this._searchStrategy === 'furthest') { + return (_fsPromise || _load_fsPromise()).default.findFurthestFile(configFile, path); } else { - return fsPromise.findNearestFile(configFile, path); + return (_fsPromise || _load_fsPromise()).default.findNearestFile(configFile, path); } - }), - ); + })); - if (this._searchStrategy === 'nearest') { - // Find the result with the greatest length (the closest match). - return configDirs.filter(Boolean).reduce((previous, configDir) => { - if (previous == null || configDir.length > previous.length) { - return configDir; - } - return previous; - }, null); - } else if (this._searchStrategy === 'furthest') { - return configDirs.filter(Boolean).reduce((previous, configDir) => { - if (previous == null || configDir.length < previous.length) { - return configDir; - } - return previous; - }, null); - } else { - // Find the first match. - return configDirs.find(Boolean); - } + if (_this._searchStrategy === 'nearest') { + // Find the result with the greatest length (the closest match). + return configDirs.filter(Boolean).reduce(function (previous, configDir) { + if (previous == null || configDir.length > previous.length) { + return configDir; + } + return previous; + }, null); + } else if (_this._searchStrategy === 'furthest') { + return configDirs.filter(Boolean).reduce(function (previous, configDir) { + if (previous == null || configDir.length < previous.length) { + return configDir; + } + return previous; + }, null); + } else { + // Find the first match. + return configDirs.find(Boolean); + } + })(); } - dispose(): void { + dispose() { this._configCache.reset(); } } +exports.ConfigCache = ConfigCache; \ No newline at end of file diff --git a/modules/nuclide-commons/Hasher.js b/modules/nuclide-commons/Hasher.js index 5704bc0e..e83e8358 100644 --- a/modules/nuclide-commons/Hasher.js +++ b/modules/nuclide-commons/Hasher.js @@ -1,3 +1,8 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +11,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -29,34 +34,30 @@ * } * } */ -export default class Hasher { - _hashes: WeakMap; - _objectCount: number; +class Hasher { constructor() { this._hashes = new WeakMap(); this._objectCount = 0; } - getHash(item: K): string | number { + getHash(item) { // eslint-disable-next-line eqeqeq if (item === null) { return 'null'; } const type = typeof item; switch (typeof item) { - case 'object': { - let hash = this._hashes.get(item); - if (hash == null) { - hash = `${type}:${this._objectCount}`; - this._hashes.set(item, hash); - this._objectCount = - this._objectCount + 1 === Number.MAX_SAFE_INTEGER - ? Number.MIN_SAFE_INTEGER - : this._objectCount + 1; + case 'object': + { + let hash = this._hashes.get(item); + if (hash == null) { + hash = `${type}:${this._objectCount}`; + this._hashes.set(item, hash); + this._objectCount = this._objectCount + 1 === Number.MAX_SAFE_INTEGER ? Number.MIN_SAFE_INTEGER : this._objectCount + 1; + } + return hash; } - return hash; - } case 'undefined': return 'undefined'; case 'string': @@ -69,3 +70,4 @@ export default class Hasher { } } } +exports.default = Hasher; \ No newline at end of file diff --git a/modules/nuclide-commons/Model.js b/modules/nuclide-commons/Model.js index 6a2d0a52..4b63270e 100644 --- a/modules/nuclide-commons/Model.js +++ b/modules/nuclide-commons/Model.js @@ -1,19 +1,18 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {Observable} from 'rxjs'; +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('./UniversalDisposable')); +} -import {BehaviorSubject} from 'rxjs'; -import UniversalDisposable from './UniversalDisposable'; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Exposes a simple API for a stateful model. This is similar to React's `state`/`setState()` API @@ -52,27 +51,37 @@ import UniversalDisposable from './UniversalDisposable'; * action creators. That's awesome! It means that, should the state grow and require new * capabilities, we can always switch to full-blown Redux without having to refactor a ton of stuff. */ -export default class Model { - _states: BehaviorSubject; +class Model { - constructor(initialState: State) { - this._states = new BehaviorSubject(initialState); + constructor(initialState) { + this._states = new _rxjsBundlesRxMinJs.BehaviorSubject(initialState); } - setState(newState: $Shape): void { - const nextState = {...this.state, ...newState}; + setState(newState) { + const nextState = Object.assign({}, this.state, newState); this._states.next(nextState); } - get state(): State { + get state() { return this._states.getValue(); } - subscribe(cb: (state: State) => mixed): IDisposable { - return new UniversalDisposable(this.toObservable().subscribe({next: cb})); + subscribe(cb) { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(this.toObservable().subscribe({ next: cb })); } - toObservable(): Observable { + toObservable() { return this._states.distinctUntilChanged(); } } +exports.default = Model; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/ObservablePool.js b/modules/nuclide-commons/ObservablePool.js index 3b0807ab..b8d587e6 100644 --- a/modules/nuclide-commons/ObservablePool.js +++ b/modules/nuclide-commons/ObservablePool.js @@ -1,25 +1,10 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import {Observable, Subject} from 'rxjs'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -type Executor = Observable | (() => rxjs$ObservableInput); - -type Request = {tag: mixed, executor: Executor}; - -type Response = { - observer: rxjs$Observer, - unsubscribed: Subject, -}; +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); /** * ObservablePool allows you to execute Observables or functions that return @@ -52,23 +37,20 @@ type Response = { * The output here is 1, 2, then 3. Despite the fact that the third observable * finishes more quickly, its execution is postponed until the first two finish. */ -export default class ObservablePool { - _requests: Subject>; - _responseListeners: Map>; - _subscription: rxjs$ISubscription; +class ObservablePool { - constructor(concurrency: number) { - this._requests = new Subject(); + constructor(concurrency) { + this._requests = new _rxjsBundlesRxMinJs.Subject(); this._responseListeners = new Map(); this._subscription = this._handleEvents(concurrency); } - schedule(executor: Executor): Observable { - return Observable.create(observer => { - const unsubscribed = new Subject(); + schedule(executor) { + return _rxjsBundlesRxMinJs.Observable.create(observer => { + const unsubscribed = new _rxjsBundlesRxMinJs.Subject(); const tag = {}; // Just a unique object. - this._responseListeners.set(tag, {observer, unsubscribed}); - this._requests.next({tag, executor}); + this._responseListeners.set(tag, { observer, unsubscribed }); + this._requests.next({ tag, executor }); return () => { this._responseListeners.delete(tag); unsubscribed.next(); @@ -80,53 +62,55 @@ export default class ObservablePool { * Warning: calling dispose() will error all executing requests. */ dispose() { - this._responseListeners.forEach(({observer}) => { + this._responseListeners.forEach(({ observer }) => { observer.error(Error('ObservablePool was disposed')); }); this._subscription.unsubscribe(); } - _handleEvents(concurrency: number): rxjs$ISubscription { - return this._requests - .mergeMap(event => { - const {executor, tag} = event; - const listener = this._responseListeners.get(tag); - // unsubscribed before we could even get to it! - if (listener == null) { - return Observable.empty(); - } - const {observer, unsubscribed} = listener; - let result; - if (executor instanceof Observable) { - result = executor; - } else { - try { - result = executor(); - } catch (err) { - // Catch errors from executor(). - observer.error(err); - return Observable.empty(); - } - } - if (result instanceof Observable) { - // We can safely forward unsubscriptions! - return ( - result - .takeUntil(unsubscribed) - // $FlowFixMe: Flow doesn't like this. - .do(observer) - .catch(() => Observable.empty()) - ); - } else { - // In the absence of cancellation, assume the worst. - return ( - Observable.from(result) - // $FlowFixMe: Flow doesn't like this. - .do(observer) - .catch(() => Observable.empty()) - ); + _handleEvents(concurrency) { + return this._requests.mergeMap(event => { + const { executor, tag } = event; + const listener = this._responseListeners.get(tag); + // unsubscribed before we could even get to it! + if (listener == null) { + return _rxjsBundlesRxMinJs.Observable.empty(); + } + const { observer, unsubscribed } = listener; + let result; + if (executor instanceof _rxjsBundlesRxMinJs.Observable) { + result = executor; + } else { + try { + result = executor(); + } catch (err) { + // Catch errors from executor(). + observer.error(err); + return _rxjsBundlesRxMinJs.Observable.empty(); } - }, concurrency) - .subscribe(); + } + if (result instanceof _rxjsBundlesRxMinJs.Observable) { + // We can safely forward unsubscriptions! + return result.takeUntil(unsubscribed) + // $FlowFixMe: Flow doesn't like this. + .do(observer).catch(() => _rxjsBundlesRxMinJs.Observable.empty()); + } else { + // In the absence of cancellation, assume the worst. + return _rxjsBundlesRxMinJs.Observable.from(result) + // $FlowFixMe: Flow doesn't like this. + .do(observer).catch(() => _rxjsBundlesRxMinJs.Observable.empty()); + } + }, concurrency).subscribe(); } } +exports.default = ObservablePool; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/SafeStreamMessageReader.js b/modules/nuclide-commons/SafeStreamMessageReader.js index a105eb46..398df0cb 100644 --- a/modules/nuclide-commons/SafeStreamMessageReader.js +++ b/modules/nuclide-commons/SafeStreamMessageReader.js @@ -1,16 +1,14 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import {StreamMessageReader} from 'vscode-jsonrpc'; +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _vscodeJsonrpc; + +function _load_vscodeJsonrpc() { + return _vscodeJsonrpc = require('vscode-jsonrpc'); +} /** * vscode-jsonrpc's StreamMessageReader has a fatal flaw of throwing exceptions! @@ -19,8 +17,8 @@ import {StreamMessageReader} from 'vscode-jsonrpc'; * * https://github.com/Microsoft/vscode-languageserver-node/issues/270 */ -export default class SafeStreamMessageReader extends StreamMessageReader { - onData(data: Buffer | string) { +class SafeStreamMessageReader extends (_vscodeJsonrpc || _load_vscodeJsonrpc()).StreamMessageReader { + onData(data) { try { super.onData(data); } catch (err) { @@ -32,3 +30,14 @@ export default class SafeStreamMessageReader extends StreamMessageReader { } } } +exports.default = SafeStreamMessageReader; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/UniversalDisposable.js b/modules/nuclide-commons/UniversalDisposable.js index 65836a52..092bc561 100644 --- a/modules/nuclide-commons/UniversalDisposable.js +++ b/modules/nuclide-commons/UniversalDisposable.js @@ -1,26 +1,17 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); -export type AnyTeardown = (() => mixed) | rxjs$ISubscription | IDisposable; /** * Like a CompositeDisposable, but in addition to Disposable instances it can * also accept plain functions and Rx subscriptions. */ -export default class UniversalDisposable { - disposed: boolean; - teardowns: Set; +class UniversalDisposable { - constructor(...teardowns: Array) { + constructor(...teardowns) { this.teardowns = new Set(); this.disposed = false; if (teardowns.length) { @@ -28,7 +19,7 @@ export default class UniversalDisposable { } } - add(...teardowns: Array): void { + add(...teardowns) { if (this.disposed) { throw new Error('Cannot add to an already disposed UniversalDisposable!'); } @@ -38,13 +29,13 @@ export default class UniversalDisposable { } } - remove(teardown: AnyTeardown): void { + remove(teardown) { if (!this.disposed) { this.teardowns.delete(teardown); } } - dispose(): void { + dispose() { if (!this.disposed) { this.disposed = true; this.teardowns.forEach(teardown => { @@ -56,30 +47,36 @@ export default class UniversalDisposable { teardown(); } }); - this.teardowns = (null: any); + this.teardowns = null; } } - unsubscribe(): void { + unsubscribe() { this.dispose(); } - clear(): void { + clear() { if (!this.disposed) { this.teardowns.clear(); } } } -function assertTeardown(teardown: AnyTeardown): void { - if ( - typeof teardown.dispose === 'function' || - typeof teardown.unsubscribe === 'function' || - typeof teardown === 'function' - ) { +exports.default = UniversalDisposable; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function assertTeardown(teardown) { + if (typeof teardown.dispose === 'function' || typeof teardown.unsubscribe === 'function' || typeof teardown === 'function') { return; } - throw new TypeError( - 'Arguments to UniversalDisposable.add must be disposable', - ); -} + throw new TypeError('Arguments to UniversalDisposable.add must be disposable'); +} \ No newline at end of file diff --git a/modules/nuclide-commons/cache.js b/modules/nuclide-commons/cache.js index 9a182061..79d9b184 100644 --- a/modules/nuclide-commons/cache.js +++ b/modules/nuclide-commons/cache.js @@ -1,39 +1,27 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DISPOSE_VALUE = exports.Cache = undefined; -import {Observable, Subject} from 'rxjs'; +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); // A Cache mapping keys to values which creates entries as they are requested. -export class Cache { - _values: Map; - _factory: (key: KeyType) => ValueType; - _disposeValue: (value: ValueType) => mixed; - _entriesSubject: Subject<[KeyType, ValueType]>; - - constructor( - factory: (key: KeyType) => ValueType, - disposeValue: (value: ValueType) => mixed = value => {}, - ) { +class Cache { + + constructor(factory, disposeValue = value => {}) { this._values = new Map(); this._factory = factory; this._disposeValue = disposeValue; - this._entriesSubject = new Subject(); + this._entriesSubject = new _rxjsBundlesRxMinJs.Subject(); } - has(key: KeyType): boolean { + has(key) { return this._values.has(key); } - get(key: KeyType): ValueType { + get(key) { if (!this._values.has(key)) { const newValue = this._factory(key); this._values.set(key, newValue); @@ -41,14 +29,14 @@ export class Cache { return newValue; } else { // Cannot use invariant as ValueType may include null/undefined. - return (this._values.get(key): any); + return this._values.get(key); } } // After this method this._values.keys() === newKeys. // deletes all keys not in newKeys // gets all keys in newKeys - setKeys(newKeys: Set): void { + setKeys(newKeys) { for (const existingKey of this._values.keys()) { if (!newKeys.has(existingKey)) { this.delete(existingKey); @@ -60,34 +48,31 @@ export class Cache { } } - entries(): Iterator<[KeyType, ValueType]> { + entries() { return this._values.entries(); } - keys(): Iterator { + keys() { return this._values.keys(); } - values(): Iterator { + values() { return this._values.values(); } - observeValues(): Observable { + observeValues() { return this.observeEntries().map(entry => entry[1]); } - observeEntries(): Observable<[KeyType, ValueType]> { - return Observable.concat( - Observable.from(this._values.entries()), - this._entriesSubject, - ); + observeEntries() { + return _rxjsBundlesRxMinJs.Observable.concat(_rxjsBundlesRxMinJs.Observable.from(this._values.entries()), this._entriesSubject); } - observeKeys(): Observable { + observeKeys() { return this.observeEntries().map(entry => entry[0]); } - delete(key: KeyType): boolean { + delete(key) { if (this.has(key)) { const value = this.get(key); this._values.delete(key); @@ -98,7 +83,7 @@ export class Cache { } } - clear(): void { + clear() { // Defend against a dispose call removing elements from the Cache. const values = this._values; this._values = new Map(); @@ -107,13 +92,25 @@ export class Cache { } } - dispose(): void { + dispose() { this.clear(); this._entriesSubject.complete(); } } -// Useful for optional second parameter to Cache constructor. -export const DISPOSE_VALUE = (value: IDisposable) => { +exports.Cache = Cache; // Useful for optional second parameter to Cache constructor. +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const DISPOSE_VALUE = exports.DISPOSE_VALUE = value => { value.dispose(); -}; +}; \ No newline at end of file diff --git a/modules/nuclide-commons/collection.js b/modules/nuclide-commons/collection.js index 347c9bcb..1b9831e8 100644 --- a/modules/nuclide-commons/collection.js +++ b/modules/nuclide-commons/collection.js @@ -1,3 +1,51 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ensureArray = ensureArray; +exports.arrayRemove = arrayRemove; +exports.arrayEqual = arrayEqual; +exports.arrayCompact = arrayCompact; +exports.arrayFlatten = arrayFlatten; +exports.arrayUnique = arrayUnique; +exports.arrayFindLastIndex = arrayFindLastIndex; +exports.mapUnion = mapUnion; +exports.mapCompact = mapCompact; +exports.mapFilter = mapFilter; +exports.mapTransform = mapTransform; +exports.mapEqual = mapEqual; +exports.mapGetWithDefault = mapGetWithDefault; +exports.areSetsEqual = areSetsEqual; +exports.every = every; +exports.setIntersect = setIntersect; +exports.setUnion = setUnion; +exports.setDifference = setDifference; +exports.setFilter = setFilter; +exports.isEmpty = isEmpty; +exports.keyMirror = keyMirror; +exports.collect = collect; +exports.objectFromPairs = objectFromPairs; +exports.objectMapValues = objectMapValues; +exports.objectValues = objectValues; +exports.objectEntries = objectEntries; +exports.objectFromMap = objectFromMap; +exports.concatIterators = concatIterators; +exports.someOfIterable = someOfIterable; +exports.findInIterable = findInIterable; +exports.filterIterable = filterIterable; +exports.mapIterable = mapIterable; +exports.takeIterable = takeIterable; +exports.range = range; +exports.firstOfIterable = firstOfIterable; +exports.iterableIsEmpty = iterableIsEmpty; +exports.iterableContains = iterableContains; +exports.count = count; +exports.isIterable = isIterable; +exports.insideOut = insideOut; +exports.mapFromObject = mapFromObject; +exports.lastFromArray = lastFromArray; +exports.distinct = distinct; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,33 +54,29 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -export function ensureArray(x: Array | T): Array { +function ensureArray(x) { return Array.isArray(x) ? x : [x]; } -export function arrayRemove(array: Array, element: T): void { +function arrayRemove(array, element) { const index = array.indexOf(element); if (index >= 0) { array.splice(index, 1); } } -export function arrayEqual( - array1: Array, - array2: Array, - equalComparator?: (a: T, b: T) => boolean, -): boolean { +function arrayEqual(array1, array2, equalComparator) { if (array1 === array2) { return true; } if (array1.length !== array2.length) { return false; } - const equalFunction = equalComparator || ((a: T, b: T) => a === b); + const equalFunction = equalComparator || ((a, b) => a === b); return array1.every((item1, i) => equalFunction(item1, array2[i])); } @@ -40,7 +84,7 @@ export function arrayEqual( * Returns a copy of the input Array with all `null` and `undefined` values filtered out. * Allows Flow to typecheck the common `filter(x => x != null)` pattern. */ -export function arrayCompact(array: Array): Array { +function arrayCompact(array) { const result = []; for (const elem of array) { if (elem != null) { @@ -53,7 +97,7 @@ export function arrayCompact(array: Array): Array { /** * Flattens an Array> into just an Array */ -export function arrayFlatten(array: Array>): Array { +function arrayFlatten(array) { const result = []; for (const subArray of array) { result.push(...subArray); @@ -66,7 +110,7 @@ export function arrayFlatten(array: Array>): Array { * Uses SameValueZero for equality purposes, which is like '===' except it deems * two NaNs equal. http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero */ -export function arrayUnique(array: Array): Array { +function arrayUnique(array) { return Array.from(new Set(array)); } @@ -74,11 +118,7 @@ export function arrayUnique(array: Array): Array { * Returns the last index in the input array that matches the predicate. * Returns -1 if no match is found. */ -export function arrayFindLastIndex( - array: Array, - predicate: (elem: T, index: number, array: Array) => boolean, - thisArg?: any, -): number { +function arrayFindLastIndex(array, predicate, thisArg) { for (let i = array.length - 1; i >= 0; i--) { if (predicate.call(thisArg, array[i], i, array)) { return i; @@ -91,7 +131,7 @@ export function arrayFindLastIndex( * Merges a given arguments of maps into one Map, with the latest maps * overriding the values of the prior maps. */ -export function mapUnion(...maps: Array>): Map { +function mapUnion(...maps) { const unionMap = new Map(); for (const map of maps) { for (const [key, value] of map) { @@ -101,7 +141,7 @@ export function mapUnion(...maps: Array>): Map { return unionMap; } -export function mapCompact(map: Map): Map { +function mapCompact(map) { const selected = new Map(); for (const [key, value] of map) { if (value != null) { @@ -111,10 +151,7 @@ export function mapCompact(map: Map): Map { return selected; } -export function mapFilter( - map: Map, - selector: (key: T, value: X) => boolean, -): Map { +function mapFilter(map, selector) { const selected = new Map(); for (const [key, value] of map) { if (selector(key, value)) { @@ -124,10 +161,7 @@ export function mapFilter( return selected; } -export function mapTransform( - src: Map, - transform: (value: V1, key: T) => V2, -): Map { +function mapTransform(src, transform) { const result = new Map(); for (const [key, value] of src) { result.set(key, transform(value, key)); @@ -135,47 +169,36 @@ export function mapTransform( return result; } -export function mapEqual( - map1: Map, - map2: Map, - equalComparator?: (val1: X, val2: X, key1?: T, key2?: T) => boolean, -) { +function mapEqual(map1, map2, equalComparator) { if (map1.size !== map2.size) { return false; } - const equalFunction = equalComparator || ((a: X, b: X) => a === b); + const equalFunction = equalComparator || ((a, b) => a === b); for (const [key1, value1] of map1) { - if (!map2.has(key1) || !equalFunction(value1, (map2.get(key1): any))) { + if (!map2.has(key1) || !equalFunction(value1, map2.get(key1))) { return false; } } return true; } -export function mapGetWithDefault( - map: Map, - key: K, - default_: V, -): V { +function mapGetWithDefault(map, key, default_) { if (map.has(key)) { // Cast through `any` since map.get's return is a maybe type. We can't just get the value and // check it against `null`, since null/undefined may inhabit V. We know this is safe since we // just checked that the map has the key. - return (map.get(key): any); + return map.get(key); } else { return default_; } } -export function areSetsEqual(a: Set, b: Set): boolean { +function areSetsEqual(a, b) { return a.size === b.size && every(a, element => b.has(element)); } // Array.every but for any iterable. -export function every( - values: Iterable, - predicate: (element: T) => boolean, -): boolean { +function every(values, predicate) { for (const element of values) { if (!predicate(element)) { return false; @@ -184,11 +207,11 @@ export function every( return true; } -export function setIntersect(a: Set, b: Set): Set { +function setIntersect(a, b) { return setFilter(a, e => b.has(e)); } -function setUnionTwo(a: Set, b: Set): Set { +function setUnionTwo(a, b) { // Avoids the extra Array allocations that `new Set([...a, ...b])` would incur. Some quick tests // indicate it would be about 60% slower. const result = new Set(a); @@ -198,23 +221,19 @@ function setUnionTwo(a: Set, b: Set): Set { return result; } -export function setUnion(...sets: Array>): Set { +function setUnion(...sets) { if (sets.length < 1) { return new Set(); } - const setReducer = (accumulator: Set, current: Set): Set => { + const setReducer = (accumulator, current) => { return setUnionTwo(accumulator, current); }; return sets.reduce(setReducer); } -export function setDifference( - a: Set, - b: Set, - hash_?: (v: T) => any, -): Set { +function setDifference(a, b, hash_) { if (a.size === 0) { return new Set(); } else if (b.size === 0) { @@ -231,10 +250,7 @@ export function setDifference( return result; } -export function setFilter( - set: Set, - predicate: (value: T) => boolean, -): Set { +function setFilter(set, predicate) { const out = new Set(); for (const item of set) { if (predicate(item)) { @@ -248,7 +264,7 @@ export function setFilter( /** * O(1)-check if a given object is empty (has no properties, inherited or not) */ -export function isEmpty(obj: Object): boolean { +function isEmpty(obj) { for (const key in obj) { return false; } @@ -261,7 +277,7 @@ export function isEmpty(obj: Object): boolean { * * Based off the equivalent function in www. */ -export function keyMirror(obj: T): {[key: $Enum]: $Enum} { +function keyMirror(obj) { const ret = {}; Object.keys(obj).forEach(key => { ret[key] = key; @@ -273,7 +289,7 @@ export function keyMirror(obj: T): {[key: $Enum]: $Enum} { * Given an array of [key, value] pairs, construct a map where the values for * each key are collected into an array of values, in order. */ -export function collect(pairs: Array<[K, V]>): Map> { +function collect(pairs) { const result = new Map(); for (const pair of pairs) { const [k, v] = pair; @@ -287,9 +303,7 @@ export function collect(pairs: Array<[K, V]>): Map> { return result; } -export function objectFromPairs( - iterable: Iterable<[T, U]>, -): {[T]: U} { +function objectFromPairs(iterable) { const result = {}; for (const [key, value] of iterable) { result[key] = value; @@ -297,28 +311,16 @@ export function objectFromPairs( return result; } -export function objectMapValues( - object: {[T: string]: U}, - project: (value: U, key: T) => V, -): {[T]: V} { +function objectMapValues(object, project) { const result = {}; Object.keys(object).forEach(key => { - result[key] = project(object[key], ((key: any): T)); + result[key] = project(object[key], key); }); return result; } -export class MultiMap { +class MultiMap { // Invariant: no empty sets. They should be removed instead. - _map: Map>; - - // TODO may be worth defining a getter but no setter, to mimic Map. But please just behave and - // don't mutate this from outside this class. - // - // Invariant: equal to the sum of the sizes of all the sets contained in this._map - /* The total number of key-value bindings contained */ - size: number; - constructor() { this._map = new Map(); this.size = 0; @@ -328,7 +330,14 @@ export class MultiMap { * Returns the set of values associated with the given key. Do not mutate the given set. Copy it * if you need to store it past the next operation on this MultiMap. */ - get(key: K): Set { + + + // TODO may be worth defining a getter but no setter, to mimic Map. But please just behave and + // don't mutate this from outside this class. + // + // Invariant: equal to the sum of the sizes of all the sets contained in this._map + /* The total number of key-value bindings contained */ + get(key) { const set = this._map.get(key); if (set == null) { return new Set(); @@ -340,7 +349,7 @@ export class MultiMap { * Mimics the Map.prototype.set interface. Deliberately did not choose "set" as the name since the * implication is that it removes the previous binding. */ - add(key: K, value: V): MultiMap { + add(key, value) { let set = this._map.get(key); if (set == null) { set = new Set(); @@ -356,7 +365,7 @@ export class MultiMap { /* * Mimics the Map.prototype.set interface. Replaces the previous binding with new values. */ - set(key: K, values: Iterable): void { + set(key, values) { this.deleteAll(key); const newSet = new Set(values); if (newSet.size !== 0) { @@ -368,7 +377,7 @@ export class MultiMap { /* * Deletes a single binding. Returns true iff the binding existed. */ - delete(key: K, value: V): boolean { + delete(key, value) { const set = this.get(key); const didRemove = set.delete(value); if (set.size === 0) { @@ -383,59 +392,55 @@ export class MultiMap { /* * Deletes all bindings associated with the given key. Returns true iff any bindings were deleted. */ - deleteAll(key: K): boolean { + deleteAll(key) { const set = this.get(key); this.size -= set.size; return this._map.delete(key); } - clear(): void { + clear() { this._map.clear(); this.size = 0; } - has(key: K, value: V): boolean { + has(key, value) { return this.get(key).has(value); } - hasAny(key: K): boolean { + hasAny(key) { return this._map.has(key); } - *values(): Iterable { + *values() { for (const set of this._map.values()) { yield* set; } } - forEach(callback: (value: V, key: K, obj: MultiMap) => void): void { - this._map.forEach((values, key) => - values.forEach(value => callback(value, key, this)), - ); + forEach(callback) { + this._map.forEach((values, key) => values.forEach(value => callback(value, key, this))); } } -export function objectValues(obj: {[key: string]: T}): Array { +exports.MultiMap = MultiMap; +function objectValues(obj) { return Object.keys(obj).map(key => obj[key]); } -export function objectEntries(obj: ?{[key: string]: T}): Array<[string, T]> { +function objectEntries(obj) { if (obj == null) { throw new TypeError(); } const entries = []; for (const key in obj) { - if ( - obj.hasOwnProperty(key) && - Object.prototype.propertyIsEnumerable.call(obj, key) - ) { + if (obj.hasOwnProperty(key) && Object.prototype.propertyIsEnumerable.call(obj, key)) { entries.push([key, obj[key]]); } } return entries; } -export function objectFromMap(map: Map): {[key: string]: T} { +function objectFromMap(map) { const obj = {}; map.forEach((v, k) => { obj[k] = v; @@ -443,9 +448,7 @@ export function objectFromMap(map: Map): {[key: string]: T} { return obj; } -export function* concatIterators( - ...iterators: Array> -): Iterator { +function* concatIterators(...iterators) { for (const iterator of iterators) { for (const element of iterator) { yield element; @@ -453,10 +456,7 @@ export function* concatIterators( } } -export function someOfIterable( - iterable: Iterable, - predicate: (element: T) => boolean, -): boolean { +function someOfIterable(iterable, predicate) { for (const element of iterable) { if (predicate(element)) { return true; @@ -465,10 +465,7 @@ export function someOfIterable( return false; } -export function findInIterable( - iterable: Iterable, - predicate: (element: T) => boolean, -): ?T { +function findInIterable(iterable, predicate) { for (const element of iterable) { if (predicate(element)) { return element; @@ -477,10 +474,7 @@ export function findInIterable( return null; } -export function* filterIterable( - iterable: Iterable, - predicate: (element: T) => boolean, -): Iterable { +function* filterIterable(iterable, predicate) { for (const element of iterable) { if (predicate(element)) { yield element; @@ -488,19 +482,13 @@ export function* filterIterable( } } -export function* mapIterable( - iterable: Iterable, - projectorFn: (element: T) => M, -): Iterable { +function* mapIterable(iterable, projectorFn) { for (const element of iterable) { yield projectorFn(element); } } -export function* takeIterable( - iterable: Iterable, - limit: number, -): Iterable { +function* takeIterable(iterable, limit) { let i = 0; for (const element of iterable) { if (++i > limit) { @@ -511,21 +499,17 @@ export function* takeIterable( } // Return an iterable of the numbers start (inclusive) through stop (exclusive) -export function* range( - start: number, - stop: number, - step?: number = 1, -): Iterable { +function* range(start, stop, step = 1) { for (let i = start; i < stop; i += step) { yield i; } } -export function firstOfIterable(iterable: Iterable): ?T { +function firstOfIterable(iterable) { return findInIterable(iterable, () => true); } -export function iterableIsEmpty(iterable: Iterable): boolean { +function iterableIsEmpty(iterable) { // eslint-disable-next-line no-unused-vars for (const element of iterable) { return false; @@ -533,13 +517,11 @@ export function iterableIsEmpty(iterable: Iterable): boolean { return true; } -export function iterableContains(iterable: Iterable, value: T): boolean { - return !iterableIsEmpty( - filterIterable(iterable, element => element === value), - ); +function iterableContains(iterable, value) { + return !iterableIsEmpty(filterIterable(iterable, element => element === value)); } -export function count(iterable: Iterable): number { +function count(iterable) { let size = 0; // eslint-disable-next-line no-unused-vars for (const element of iterable) { @@ -548,23 +530,17 @@ export function count(iterable: Iterable): number { return size; } -export function isIterable(obj: any): boolean { +function isIterable(obj) { return typeof obj[Symbol.iterator] === 'function'; } // Traverse an array from the inside out, starting at the specified index. -export function* insideOut( - arr: Array, - startingIndex?: number, -): Iterable<[T, number]> { +function* insideOut(arr, startingIndex) { if (arr.length === 0) { return; } - let i = - startingIndex == null - ? Math.floor(arr.length / 2) - : Math.min(arr.length, Math.max(0, startingIndex)); + let i = startingIndex == null ? Math.floor(arr.length / 2) : Math.min(arr.length, Math.max(0, startingIndex)); let j = i - 1; while (i < arr.length || j >= 0) { @@ -579,15 +555,15 @@ export function* insideOut( } } -export function mapFromObject(obj: {[key: string]: T}): Map { +function mapFromObject(obj) { return new Map(objectEntries(obj)); } -export function lastFromArray(arr: Array): T { +function lastFromArray(arr) { return arr[arr.length - 1]; } -export function distinct(array: T[], keyFn?: (t: T) => string): T[] { +function distinct(array, keyFn) { if (keyFn == null) { return Array.from(new Set(array)); } @@ -601,4 +577,4 @@ export function distinct(array: T[], keyFn?: (t: T) => string): T[] { seenKeys.add(key); return true; }); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/debounce.js b/modules/nuclide-commons/debounce.js index 54c6172a..74f5bacc 100644 --- a/modules/nuclide-commons/debounce.js +++ b/modules/nuclide-commons/debounce.js @@ -1,38 +1,18 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import invariant from 'assert'; - -export default function debounce< - T, - TArgs: Array, - TReturn, - TFunc: (...TArgs) => TReturn, // eslint-disable-line space-before-function-paren ->( - func: TFunc, - wait: number, - immediate?: boolean = false, -): { - (...TArgs): TReturn | void, - dispose(): void, -} { +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = debounce; +function debounce(func, wait, immediate = false) { // Taken from: https://github.com/jashkenas/underscore/blob/b10b2e6d72/underscore.js#L815. - let timeout: ?TimeoutID; - let args: ?TArgs; - let context: any; + let timeout; + let args; + let context; let timestamp = 0; - let result: TReturn | void; + let result; - const later = function() { + const later = function () { const last = Date.now() - timestamp; if (last < wait && last >= 0) { @@ -40,7 +20,10 @@ export default function debounce< } else { timeout = null; if (!immediate) { - invariant(args != null); + if (!(args != null)) { + throw new Error('Invariant violation: "args != null"'); + } + result = func.apply(context, args); if (!timeout) { context = args = null; @@ -49,7 +32,7 @@ export default function debounce< } }; - const debounced = function(...args_: TArgs): TReturn | void { + const debounced = function (...args_) { context = this; args = args_; timestamp = Date.now(); @@ -73,4 +56,14 @@ export default function debounce< }; return debounced; -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/event.js b/modules/nuclide-commons/event.js index 085e1032..37326c15 100644 --- a/modules/nuclide-commons/event.js +++ b/modules/nuclide-commons/event.js @@ -1,3 +1,26 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.attachEvent = attachEvent; +exports.observableFromSubscribeFunction = observableFromSubscribeFunction; + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('./UniversalDisposable')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Add an event listener an return a disposable for removing it. Note that this function assumes + * node EventEmitter semantics: namely, that adding the same combination of eventName and callback + * adds a second listener. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,39 +29,22 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import UniversalDisposable from './UniversalDisposable'; -import {Observable} from 'rxjs'; - -/** - * Add an event listener an return a disposable for removing it. Note that this function assumes - * node EventEmitter semantics: namely, that adding the same combination of eventName and callback - * adds a second listener. - */ -export function attachEvent( - emitter: events$EventEmitter, - eventName: string, - callback: Function, -): IDisposable { +function attachEvent(emitter, eventName, callback) { emitter.addListener(eventName, callback); - return new UniversalDisposable(() => { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(() => { emitter.removeListener(eventName, callback); }); } -type SubscribeCallback = (item: T) => any; -type SubscribeFunction = (callback: SubscribeCallback) => IDisposable; - -export function observableFromSubscribeFunction( - fn: SubscribeFunction, -): Observable { - return Observable.create(observer => { +function observableFromSubscribeFunction(fn) { + return _rxjsBundlesRxMinJs.Observable.create(observer => { const disposable = fn(observer.next.bind(observer)); return () => { disposable.dispose(); }; }); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/fsPromise.js b/modules/nuclide-commons/fsPromise.js index 7f16da83..05a9d4df 100644 --- a/modules/nuclide-commons/fsPromise.js +++ b/modules/nuclide-commons/fsPromise.js @@ -1,65 +1,10 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import fs from 'fs'; -import fsPlus from 'fs-plus'; -import globLib from 'glob'; -import mkdirpLib from 'mkdirp'; -import mvLib from 'mv'; -import rimraf from 'rimraf'; -import temp from 'temp'; +'use strict'; -import nuclideUri from './nuclideUri'; -import {runCommand} from './process'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -/** - * Create a temp directory with given prefix. The caller is responsible for cleaning up the - * drectory. - * @param prefix optinal prefix for the temp directory name. - * @return path to a temporary directory. - */ -function tempdir(prefix: string = ''): Promise { - return new Promise((resolve, reject) => { - temp.mkdir(prefix, (err, result) => { - if (err == null) { - resolve(result); - } else { - reject(err); - } - }); - }); -} - -/** - * @return path to a temporary file. The caller is responsible for cleaning up - * the file. - */ -function tempfile(options: any): Promise { - return new Promise((resolve, reject) => { - temp.open(options, (err, info) => { - if (err) { - reject(err); - } else { - fs.close(info.fd, closeErr => { - if (closeErr) { - reject(closeErr); - } else { - resolve(info.path); - } - }); - } - }); - }); -} +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); /** * Searches upward through the filesystem from pathToDirectory to find a file with @@ -69,28 +14,31 @@ function tempfile(options: any): Promise { * not a file. * @return directory that contains the nearest file or null. */ -async function findNearestFile( - fileName: string, - pathToDirectory: string, -): Promise { - // TODO(5586355): If this becomes a bottleneck, we should consider memoizing - // this function. The downside would be that if someone added a closer file - // with fileName to pathToFile (or deleted the one that was cached), then we - // would have a bug. This would probably be pretty rare, though. - let currentPath = nuclideUri.resolve(pathToDirectory); - for (;;) { - const fileToFind = nuclideUri.join(currentPath, fileName); - // eslint-disable-next-line no-await-in-loop - const hasFile = await exists(fileToFind); - if (hasFile) { - return currentPath; - } - if (nuclideUri.isRoot(currentPath)) { - return null; +let findNearestFile = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (fileName, pathToDirectory) { + // TODO(5586355): If this becomes a bottleneck, we should consider memoizing + // this function. The downside would be that if someone added a closer file + // with fileName to pathToFile (or deleted the one that was cached), then we + // would have a bug. This would probably be pretty rare, though. + let currentPath = (_nuclideUri || _load_nuclideUri()).default.resolve(pathToDirectory); + for (;;) { + const fileToFind = (_nuclideUri || _load_nuclideUri()).default.join(currentPath, fileName); + // eslint-disable-next-line no-await-in-loop + const hasFile = yield exists(fileToFind); + if (hasFile) { + return currentPath; + } + if ((_nuclideUri || _load_nuclideUri()).default.isRoot(currentPath)) { + return null; + } + currentPath = (_nuclideUri || _load_nuclideUri()).default.dirname(currentPath); } - currentPath = nuclideUri.dirname(currentPath); - } -} + }); + + return function findNearestFile(_x, _x2) { + return _ref.apply(this, arguments); + }; +})(); /** * Searches upward through the filesystem from pathToDirectory to find the furthest @@ -101,41 +49,29 @@ async function findNearestFile( * @param stopOnMissing Stop searching when we reach a directory without fileName. * @return directory that contains the furthest file or null. */ -async function findFurthestFile( - fileName: string, - pathToDirectory: string, - stopOnMissing: boolean = false, -): Promise { - let currentPath = nuclideUri.resolve(pathToDirectory); - let result = null; - for (;;) { - const fileToFind = nuclideUri.join(currentPath, fileName); - // eslint-disable-next-line no-await-in-loop - const hasFile = await exists(fileToFind); - if ((!hasFile && stopOnMissing) || nuclideUri.isRoot(currentPath)) { - return result; - } else if (hasFile) { - result = currentPath; - } - currentPath = nuclideUri.dirname(currentPath); - } -} -function getCommonAncestorDirectory(filePaths: Array): string { - let commonDirectoryPath = nuclideUri.dirname(filePaths[0]); - while ( - filePaths.some(filePath => !filePath.startsWith(commonDirectoryPath)) - ) { - commonDirectoryPath = nuclideUri.dirname(commonDirectoryPath); - } - return commonDirectoryPath; -} -function exists(filePath: string): Promise { - return new Promise((resolve, reject) => { - fs.exists(filePath, resolve); +let findFurthestFile = (() => { + var _ref2 = (0, _asyncToGenerator.default)(function* (fileName, pathToDirectory, stopOnMissing = false) { + let currentPath = (_nuclideUri || _load_nuclideUri()).default.resolve(pathToDirectory); + let result = null; + for (;;) { + const fileToFind = (_nuclideUri || _load_nuclideUri()).default.join(currentPath, fileName); + // eslint-disable-next-line no-await-in-loop + const hasFile = yield exists(fileToFind); + if (!hasFile && stopOnMissing || (_nuclideUri || _load_nuclideUri()).default.isRoot(currentPath)) { + return result; + } else if (hasFile) { + result = currentPath; + } + currentPath = (_nuclideUri || _load_nuclideUri()).default.dirname(currentPath); + } }); -} + + return function findFurthestFile(_x3, _x4) { + return _ref2.apply(this, arguments); + }; +})(); /** * Runs the equivalent of `mkdir -p` with the given path. @@ -144,73 +80,279 @@ function exists(filePath: string): Promise { * directories were created for some prefix of the given path. * @return true if the path was created; false if it already existed. */ -async function mkdirp(filePath: string): Promise { - const isExistingDirectory = await exists(filePath); - if (isExistingDirectory) { - return false; - } else { - return new Promise((resolve, reject) => { - mkdirpLib(filePath, err => { - if (err) { - reject(err); - } else { - resolve(true); - } +let mkdirp = (() => { + var _ref3 = (0, _asyncToGenerator.default)(function* (filePath) { + const isExistingDirectory = yield exists(filePath); + if (isExistingDirectory) { + return false; + } else { + return new Promise(function (resolve, reject) { + (0, (_mkdirp || _load_mkdirp()).default)(filePath, function (err) { + if (err) { + reject(err); + } else { + resolve(true); + } + }); }); - }); - } -} + } + }); + + return function mkdirp(_x5) { + return _ref3.apply(this, arguments); + }; +})(); /** * Removes directories even if they are non-empty. Does not fail if the directory doesn't exist. */ -function rimrafWrapper(filePath: string): Promise { - return new Promise((resolve, reject) => { - rimraf(filePath, (err, result) => { - if (err == null) { - resolve(result); + + +let getFileSystemType = (() => { + var _ref4 = (0, _asyncToGenerator.default)(function* (entityPath) { + if (process.platform === 'linux' || process.platform === 'darwin') { + try { + const stdout = yield (0, (_process || _load_process()).runCommand)('stat', ['-f', '-L', '-c', '%T', entityPath]).toPromise(); + return stdout.trim(); + } catch (err) { + return null; + } + } else { + // TODO Handle other platforms (windows?) + return null; + } + }); + + return function getFileSystemType(_x6) { + return _ref4.apply(this, arguments); + }; +})(); + +/** @return true only if we are sure entityPath is on NFS. */ + + +let isNfs = (() => { + var _ref5 = (0, _asyncToGenerator.default)(function* (entityPath) { + return (yield getFileSystemType(entityPath)) === 'nfs'; + }); + + return function isNfs(_x7) { + return _ref5.apply(this, arguments); + }; +})(); + +/** @return true only if we are sure entityPath is on a Fuse filesystem like + dewey or gvfs. +*/ + + +let isFuse = (() => { + var _ref6 = (0, _asyncToGenerator.default)(function* (entityPath) { + return (yield getFileSystemType(entityPath)) === 'fuseblk'; + }); + + return function isFuse(_x8) { + return _ref6.apply(this, arguments); + }; +})(); + +let isNonNfsDirectory = (() => { + var _ref7 = (0, _asyncToGenerator.default)(function* (directoryPath) { + try { + const stats = yield stat(directoryPath); + if (stats.isDirectory()) { + return !(yield isNfs(directoryPath)); } else { - reject(err); + return false; } - }); + } catch (e) { + // If the directory cannot be probed for whatever reason, just + // indicate that this is not a valid candidate directory. + // Typically this is ENOENT for missing directory. + return false; + } }); -} -async function getFileSystemType(entityPath: string): Promise { - if (process.platform === 'linux' || process.platform === 'darwin') { + return function isNonNfsDirectory(_x9) { + return _ref7.apply(this, arguments); + }; +})(); + +/** + * Promisified wrappers around fs-plus functions. + */ + +let copyFilePermissions = (() => { + var _ref8 = (0, _asyncToGenerator.default)(function* (sourcePath, destinationPath) { try { - const stdout = await runCommand('stat', [ - '-f', - '-L', - '-c', - '%T', - entityPath, - ]).toPromise(); - return stdout.trim(); + const { mode, uid, gid } = yield stat(sourcePath); + yield Promise.all([ + // The user may not have permissions to use the uid/gid. + chown(destinationPath, uid, gid).catch(function () {}), chmod(destinationPath, mode)]); + } catch (e) { + // If the file does not exist, then ENOENT will be thrown. + if (e.code !== 'ENOENT') { + throw e; + } + // For new files, use the default process file creation mask. + yield chmod(destinationPath, 0o666 & ~process.umask() // eslint-disable-line no-bitwise + ); + } + }); + + return function copyFilePermissions(_x10, _x11) { + return _ref8.apply(this, arguments); + }; +})(); + +/** + * TODO: the fs-plus `writeFile` implementation runs `mkdirp` first. + * We should use `fs.writeFile` and have callsites explicitly opt-in to this behaviour. + */ + + +let writeFileAtomic = (() => { + var _ref9 = (0, _asyncToGenerator.default)(function* (path, data, options) { + const tempFilePath = yield tempfile('nuclide'); + try { + yield writeFile(tempFilePath, data, options); + + // Expand the target path in case it contains symlinks. + let realPath = path; + try { + realPath = yield realpath(path); + } catch (e) {} + // Fallback to using the specified path if it cannot be expanded. + // Note: this is expected in cases where the remote file does not + // actually exist. + + + // Ensure file still has original permissions: + // https://github.com/facebook/nuclide/issues/157 + // We update the mode of the temp file rather than the destination file because + // if we did the mv() then the chmod(), there would be a brief period between + // those two operations where the destination file might have the wrong permissions. + yield copyFilePermissions(realPath, tempFilePath); + + // TODO: put renames into a queue so we don't write older save over new save. + // Use mv as fs.rename doesn't work across partitions. + yield mv(tempFilePath, realPath, { mkdirp: true }); } catch (err) { - return null; + yield unlink(tempFilePath); + throw err; } - } else { - // TODO Handle other platforms (windows?) - return null; - } + }); + + return function writeFileAtomic(_x12, _x13, _x14) { + return _ref9.apply(this, arguments); + }; +})(); + +/** + * Promisified wrappers around fs functions. + */ + +/** + * A utility function to grab the last N bytes from a file. Attempts to do so + * without reading the entire file. + */ +let tailBytes = (() => { + var _ref10 = (0, _asyncToGenerator.default)(function* (file, maxBytes) { + if (maxBytes <= 0) { + throw new Error('tailbytes expects maxBytes > 0'); + } + + // Figure out the size so we know what strategy to use + const { size: file_size } = yield stat(file); + + if (file_size > maxBytes) { + const fd = yield open(file, 'r'); + const buffer = Buffer.alloc(maxBytes); + const bytesRead = yield read(fd, buffer, 0, // buffer offset + maxBytes, // length to read + file_size - maxBytes // file offset + ); + yield close(fd); + + /* If we meant to read the last 100 bytes but only read 50 bytes, then we've + * failed to read the last 100 bytes. So throw. In the future, someone + * could update this code to keep calling `read` until we read maxBytes. + */ + if (bytesRead !== maxBytes) { + throw new Error(`Failed to tail file. Intended to read ${maxBytes} bytes but ` + `only read ${bytesRead} bytes`); + } + return buffer; + } else { + return readFile(file); + } + }); + + return function tailBytes(_x15, _x16) { + return _ref10.apply(this, arguments); + }; +})(); + +var _fs = _interopRequireDefault(require('fs')); + +var _fsPlus; + +function _load_fsPlus() { + return _fsPlus = _interopRequireDefault(require('fs-plus')); } -/** @return true only if we are sure entityPath is on NFS. */ -async function isNfs(entityPath: string): Promise { - return (await getFileSystemType(entityPath)) === 'nfs'; +var _glob; + +function _load_glob() { + return _glob = _interopRequireDefault(require('glob')); } -/** @return true only if we are sure entityPath is on a Fuse filesystem like - dewey or gvfs. -*/ -async function isFuse(entityPath: string): Promise { - return (await getFileSystemType(entityPath)) === 'fuseblk'; +var _mkdirp; + +function _load_mkdirp() { + return _mkdirp = _interopRequireDefault(require('mkdirp')); +} + +var _mv; + +function _load_mv() { + return _mv = _interopRequireDefault(require('mv')); } -function glob(pattern: string, options?: Object): Promise> { +var _rimraf; + +function _load_rimraf() { + return _rimraf = _interopRequireDefault(require('rimraf')); +} + +var _temp; + +function _load_temp() { + return _temp = _interopRequireDefault(require('temp')); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('./nuclideUri')); +} + +var _process; + +function _load_process() { + return _process = require('./process'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Create a temp directory with given prefix. The caller is responsible for cleaning up the + * drectory. + * @param prefix optinal prefix for the temp directory name. + * @return path to a temporary directory. + */ +function tempdir(prefix = '') { return new Promise((resolve, reject) => { - globLib(pattern, options, (err, result) => { + (_temp || _load_temp()).default.mkdir(prefix, (err, result) => { if (err == null) { resolve(result); } else { @@ -220,73 +362,55 @@ function glob(pattern: string, options?: Object): Promise> { }); } -async function isNonNfsDirectory(directoryPath: string): Promise { - try { - const stats = await stat(directoryPath); - if (stats.isDirectory()) { - return !await isNfs(directoryPath); - } else { - return false; - } - } catch (e) { - // If the directory cannot be probed for whatever reason, just - // indicate that this is not a valid candidate directory. - // Typically this is ENOENT for missing directory. - return false; - } -} - /** - * Promisified wrappers around fs-plus functions. + * @return path to a temporary file. The caller is responsible for cleaning up + * the file. + */ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format */ -function copy(source: string, dest: string): Promise { +function tempfile(options) { return new Promise((resolve, reject) => { - fsPlus.copy(source, dest, (err, result) => { - if (err == null) { - resolve(result); - } else { + (_temp || _load_temp()).default.open(options, (err, info) => { + if (err) { reject(err); + } else { + _fs.default.close(info.fd, closeErr => { + if (closeErr) { + reject(closeErr); + } else { + resolve(info.path); + } + }); } }); }); } -async function copyFilePermissions( - sourcePath: string, - destinationPath: string, -): Promise { - try { - const {mode, uid, gid} = await stat(sourcePath); - await Promise.all([ - // The user may not have permissions to use the uid/gid. - chown(destinationPath, uid, gid).catch(() => {}), - chmod(destinationPath, mode), - ]); - } catch (e) { - // If the file does not exist, then ENOENT will be thrown. - if (e.code !== 'ENOENT') { - throw e; - } - // For new files, use the default process file creation mask. - await chmod( - destinationPath, - 0o666 & ~process.umask(), // eslint-disable-line no-bitwise - ); +function getCommonAncestorDirectory(filePaths) { + let commonDirectoryPath = (_nuclideUri || _load_nuclideUri()).default.dirname(filePaths[0]); + while (filePaths.some(filePath => !filePath.startsWith(commonDirectoryPath))) { + commonDirectoryPath = (_nuclideUri || _load_nuclideUri()).default.dirname(commonDirectoryPath); } + return commonDirectoryPath; } -/** - * TODO: the fs-plus `writeFile` implementation runs `mkdirp` first. - * We should use `fs.writeFile` and have callsites explicitly opt-in to this behaviour. - */ -function writeFile( - filename: string, - data: Buffer | string, - options?: Object | string, -): Promise { +function exists(filePath) { return new Promise((resolve, reject) => { - fsPlus.writeFile(filename, data, options, (err, result) => { + _fs.default.exists(filePath, resolve); + }); +}function rimrafWrapper(filePath) { + return new Promise((resolve, reject) => { + (0, (_rimraf || _load_rimraf()).default)(filePath, (err, result) => { if (err == null) { resolve(result); } else { @@ -296,48 +420,45 @@ function writeFile( }); } -async function writeFileAtomic( - path: string, - data: Buffer | string, - options?: Object | string, -): Promise { - const tempFilePath = await tempfile('nuclide'); - try { - await writeFile(tempFilePath, data, options); - - // Expand the target path in case it contains symlinks. - let realPath = path; - try { - realPath = await realpath(path); - } catch (e) { - // Fallback to using the specified path if it cannot be expanded. - // Note: this is expected in cases where the remote file does not - // actually exist. - } +function glob(pattern, options) { + return new Promise((resolve, reject) => { + (0, (_glob || _load_glob()).default)(pattern, options, (err, result) => { + if (err == null) { + resolve(result); + } else { + reject(err); + } + }); + }); +} - // Ensure file still has original permissions: - // https://github.com/facebook/nuclide/issues/157 - // We update the mode of the temp file rather than the destination file because - // if we did the mv() then the chmod(), there would be a brief period between - // those two operations where the destination file might have the wrong permissions. - await copyFilePermissions(realPath, tempFilePath); - - // TODO: put renames into a queue so we don't write older save over new save. - // Use mv as fs.rename doesn't work across partitions. - await mv(tempFilePath, realPath, {mkdirp: true}); - } catch (err) { - await unlink(tempFilePath); - throw err; - } +function copy(source, dest) { + return new Promise((resolve, reject) => { + (_fsPlus || _load_fsPlus()).default.copy(source, dest, (err, result) => { + if (err == null) { + resolve(result); + } else { + reject(err); + } + }); + }); } -/** - * Promisified wrappers around fs functions. - */ +function writeFile(filename, data, options) { + return new Promise((resolve, reject) => { + (_fsPlus || _load_fsPlus()).default.writeFile(filename, data, options, (err, result) => { + if (err == null) { + resolve(result); + } else { + reject(err); + } + }); + }); +} -function chmod(path: string, mode: number | string): Promise { +function chmod(path, mode) { return new Promise((resolve, reject) => { - fs.chmod(path, mode, (err, result) => { + _fs.default.chmod(path, mode, (err, result) => { if (err == null) { resolve(result); } else { @@ -347,9 +468,9 @@ function chmod(path: string, mode: number | string): Promise { }); } -function chown(path: string, uid: number, gid: number): Promise { +function chown(path, uid, gid) { return new Promise((resolve, reject) => { - fs.chown(path, uid, gid, (err, result) => { + _fs.default.chown(path, uid, gid, (err, result) => { if (err == null) { resolve(result); } else { @@ -359,9 +480,9 @@ function chown(path: string, uid: number, gid: number): Promise { }); } -function close(fd: number): Promise { +function close(fd) { return new Promise((resolve, reject) => { - fs.close(fd, err => { + _fs.default.close(fd, err => { if (err == null) { resolve(); } else { @@ -371,9 +492,9 @@ function close(fd: number): Promise { }); } -function lstat(path: string): Promise { +function lstat(path) { return new Promise((resolve, reject) => { - fs.lstat(path, (err, result) => { + _fs.default.lstat(path, (err, result) => { if (err == null) { resolve(result); } else { @@ -383,9 +504,9 @@ function lstat(path: string): Promise { }); } -function mkdir(path: string, mode?: number): Promise { +function mkdir(path, mode) { return new Promise((resolve, reject) => { - fs.mkdir(path, mode, (err, result) => { + _fs.default.mkdir(path, mode, (err, result) => { if (err == null) { resolve(result); } else { @@ -395,26 +516,13 @@ function mkdir(path: string, mode?: number): Promise { }); } -export type MvOptions = { - // Run mkdirp for the directory first. Defaults to false. - mkdirp?: boolean, - // Overwrite the file if it exists. Defaults to true. - clobber?: boolean, - // Optional: the concurrency limit when moving a directory. - limit?: number, -}; - /** * The key difference between 'mv' and 'rename' is that 'mv' works across devices. * It's not uncommon to have temporary files in a different disk, for instance. */ -function mv( - sourcePath: string, - destinationPath: string, - options?: MvOptions = {}, -): Promise { +function mv(sourcePath, destinationPath, options = {}) { return new Promise((resolve, reject) => { - mvLib(sourcePath, destinationPath, options, error => { + (0, (_mv || _load_mv()).default)(sourcePath, destinationPath, options, error => { if (error) { reject(error); } else { @@ -424,13 +532,9 @@ function mv( }); } -function open( - path: string | Buffer | URL, - flags: string | number, - mode: number = 0o666, -): Promise { +function open(path, flags, mode = 0o666) { return new Promise((resolve, reject) => { - fs.open(path, flags, mode, (err, fd) => { + _fs.default.open(path, flags, mode, (err, fd) => { if (err == null) { resolve(fd); } else { @@ -440,15 +544,9 @@ function open( }); } -function read( - fd: number, - buffer: Buffer, - offset: number, - length: number, - position: number | null, -): Promise { +function read(fd, buffer, offset, length, position) { return new Promise((resolve, reject) => { - fs.read(fd, buffer, offset, length, position, (err, bytesRead) => { + _fs.default.read(fd, buffer, offset, length, position, (err, bytesRead) => { if (err == null) { resolve(bytesRead); } else { @@ -460,17 +558,12 @@ function read( // `fs.readFile` returns a Buffer unless an encoding is specified. // This workaround is adapted from the Flow declarations. -type ReadFileType = ((filename: string, encoding: string) => Promise) & - (( - filename: string, - options: {encoding: string, flag?: string}, - ) => Promise) & - ((filename: string, options?: {flag?: string}) => Promise); - -const readFile: ReadFileType = (function(...args: Array) { + + +const readFile = function (...args) { return new Promise((resolve, reject) => { // $FlowIssue: spread operator doesn't preserve any-type - fs.readFile(...args, (err, result) => { + _fs.default.readFile(...args, (err, result) => { if (err == null) { resolve(result); } else { @@ -478,11 +571,11 @@ const readFile: ReadFileType = (function(...args: Array) { } }); }); -}: any); +}; -function readdir(path: string): Promise> { +function readdir(path) { return new Promise((resolve, reject) => { - fs.readdir(path, (err, result) => { + _fs.default.readdir(path, (err, result) => { if (err == null) { resolve(result); } else { @@ -492,9 +585,9 @@ function readdir(path: string): Promise> { }); } -function readlink(path: string): Promise { +function readlink(path) { return new Promise((resolve, reject) => { - fs.readlink(path, (err, result) => { + _fs.default.readlink(path, (err, result) => { if (err == null) { resolve(result); } else { @@ -504,9 +597,9 @@ function readlink(path: string): Promise { }); } -function realpath(path: string, cache?: Object): Promise { +function realpath(path, cache) { return new Promise((resolve, reject) => { - fs.realpath(path, cache, (err, result) => { + _fs.default.realpath(path, cache, (err, result) => { if (err == null) { resolve(result); } else { @@ -516,9 +609,9 @@ function realpath(path: string, cache?: Object): Promise { }); } -function access(path: string, mode: number): Promise { +function access(path, mode) { return new Promise((resolve, reject) => { - fs.access(path, mode, err => { + _fs.default.access(path, mode, err => { if (err == null) { resolve(true); } else { @@ -528,9 +621,9 @@ function access(path: string, mode: number): Promise { }); } -function stat(path: string): Promise { +function stat(path) { return new Promise((resolve, reject) => { - fs.stat(path, (err, result) => { + _fs.default.stat(path, (err, result) => { if (err == null) { resolve(result); } else { @@ -540,9 +633,9 @@ function stat(path: string): Promise { }); } -function symlink(source: string, dest: string, type?: string): Promise { +function symlink(source, dest, type) { return new Promise((resolve, reject) => { - fs.symlink(source, dest, type, (err, result) => { + _fs.default.symlink(source, dest, type, (err, result) => { if (err == null) { resolve(result); } else { @@ -552,49 +645,9 @@ function symlink(source: string, dest: string, type?: string): Promise { }); } -/** - * A utility function to grab the last N bytes from a file. Attempts to do so - * without reading the entire file. - */ -async function tailBytes(file: string, maxBytes: number): Promise { - if (maxBytes <= 0) { - throw new Error('tailbytes expects maxBytes > 0'); - } - - // Figure out the size so we know what strategy to use - const {size: file_size} = await stat(file); - - if (file_size > maxBytes) { - const fd = await open(file, 'r'); - const buffer = Buffer.alloc(maxBytes); - const bytesRead = await read( - fd, - buffer, - 0, // buffer offset - maxBytes, // length to read - file_size - maxBytes, // file offset - ); - await close(fd); - - /* If we meant to read the last 100 bytes but only read 50 bytes, then we've - * failed to read the last 100 bytes. So throw. In the future, someone - * could update this code to keep calling `read` until we read maxBytes. - */ - if (bytesRead !== maxBytes) { - throw new Error( - `Failed to tail file. Intended to read ${maxBytes} bytes but ` + - `only read ${bytesRead} bytes`, - ); - } - return buffer; - } else { - return readFile(file); - } -} - -function unlink(path: string): Promise { +function unlink(path) { return new Promise((resolve, reject) => { - fs.unlink(path, (err, result) => { + _fs.default.unlink(path, (err, result) => { if (err == null) { resolve(result); } else { @@ -604,13 +657,9 @@ function unlink(path: string): Promise { }); } -function utimes( - path: string, - atime: number | Date, - mtime: number | Date, -): Promise { +function utimes(path, atime, mtime) { return new Promise((resolve, reject) => { - fs.utimes(path, atime, mtime, err => { + _fs.default.utimes(path, atime, mtime, err => { if (err == null) { resolve(); } else { @@ -620,9 +669,9 @@ function utimes( }); } -function rmdir(path: string): Promise { +function rmdir(path) { return new Promise((resolve, reject) => { - fs.rmdir(path, err => { + _fs.default.rmdir(path, err => { if (err == null) { resolve(); } else { @@ -632,7 +681,7 @@ function rmdir(path: string): Promise { }); } -export default { +exports.default = { tempdir, tempfile, findNearestFile, @@ -669,5 +718,5 @@ export default { unlink, utimes, rmdir, - access, -}; + access +}; \ No newline at end of file diff --git a/modules/nuclide-commons/humanizeKeystroke.js b/modules/nuclide-commons/humanizeKeystroke.js index 811265c9..d3134a88 100644 --- a/modules/nuclide-commons/humanizeKeystroke.js +++ b/modules/nuclide-commons/humanizeKeystroke.js @@ -1,3 +1,9 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = humanizeKeystroke; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +12,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -24,7 +30,7 @@ const MAC_MODIFIER_KEYMAP = { option: '\u2325', right: '\u2192', shift: '\u21e7', - up: '\u2191', + up: '\u2191' }; const NON_MAC_MODIFIER_KEYMAP = { @@ -37,7 +43,7 @@ const NON_MAC_MODIFIER_KEYMAP = { option: 'Alt', right: 'Right', shift: 'Shift', - up: 'Up', + up: 'Up' }; // Human key combos should always explicitly state the shift key. This map is a disambiguator. @@ -53,13 +59,13 @@ const SHIFT_KEYMAP = { '<': ',', '>': '.', '|': '\\', - '~': '`', + '~': '`' }; const FN_KEY_RE = /f[0-9]{1,2}/; // $FlowIssue -function flatten(arr: Array>): Array { +function flatten(arr) { let flattened = []; for (const el of arr) { if (Array.isArray(el)) { @@ -71,18 +77,17 @@ function flatten(arr: Array>): Array { return flattened; } -function capitalize(word: string): string { +function capitalize(word) { const first = word[0] || ''; const rest = word.slice(1); return first.toUpperCase() + rest; } -function humanizeKey(key: string, platform: ?string): string | Array { +function humanizeKey(key, platform) { if (!key) { return key; } - const modifierKeyMap = - platform === 'darwin' ? MAC_MODIFIER_KEYMAP : NON_MAC_MODIFIER_KEYMAP; + const modifierKeyMap = platform === 'darwin' ? MAC_MODIFIER_KEYMAP : NON_MAC_MODIFIER_KEYMAP; if (modifierKeyMap[key]) { return modifierKeyMap[key]; } @@ -111,10 +116,7 @@ function humanizeKey(key: string, platform: ?string): string | Array { * @param platform An optional String platform to humanize for (default: `process.platform`). * @return a humanized representation of the keystroke. */ -export default function humanizeKeystroke( - keystroke: string, - platform_: ?string, -): string { +function humanizeKeystroke(keystroke, platform_) { let platform = platform_; if (!keystroke) { return keystroke; @@ -144,4 +146,4 @@ export default function humanizeKeystroke( humanizedKeystrokes.push(keys.join(separator)); } return humanizedKeystrokes.join(' '); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/matchIndexesToRanges.js b/modules/nuclide-commons/matchIndexesToRanges.js index 73ff81a8..28f71176 100644 --- a/modules/nuclide-commons/matchIndexesToRanges.js +++ b/modules/nuclide-commons/matchIndexesToRanges.js @@ -1,20 +1,10 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +"use strict"; -type MatchRange = [/* start */ number, /* end */ number]; - -export default function matchIndexesToRanges( - matchIndexes: Array, -): Array { +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = matchIndexesToRanges; +function matchIndexesToRanges(matchIndexes) { let streakOngoing = false; let start = 0; const ranges = []; @@ -38,4 +28,14 @@ export default function matchIndexesToRanges( } }); return ranges; -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/memoizeUntilChanged.js b/modules/nuclide-commons/memoizeUntilChanged.js index 93088431..81501f04 100644 --- a/modules/nuclide-commons/memoizeUntilChanged.js +++ b/modules/nuclide-commons/memoizeUntilChanged.js @@ -1,44 +1,14 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import invariant from 'assert'; -import {arrayEqual} from './collection'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -type memoizeUntilChanged = (( - func: (A, B, C, D) => R, - keySelector_?: (A, B, C, D) => U, - compareKeys_?: (U, U) => boolean, -) => (A, B, C, D) => R) & - (( - func: (A, B, C) => R, - keySelector_?: (A, B, C) => U, - compareKeys_?: (U, U) => boolean, - ) => (A, B, C) => R) & - (( - func: (A, B) => R, - keySelector_?: (A, B) => U, - compareKeys_?: (U, U) => boolean, - ) => (A, B) => R) & - (( - func: (A) => R, - keySelector_?: (A) => U, - compareKeys_?: (U, U) => boolean, - ) => A => R) & - ((func: () => R) => () => R) & - (( - func: (...any: $ReadOnlyArray) => R, - (...any: $ReadOnlyArray) => U, - compareKeys_?: (U, U) => boolean, - ) => (...any: $ReadOnlyArray) => R); +var _collection; + +function _load_collection() { + return _collection = require('./collection'); +} /** * Create a memoized version of the provided function that caches only the latest result. This is @@ -77,25 +47,40 @@ type memoizeUntilChanged = (( * } * } */ -export default ((func, keySelector_?, compareKeys_?) => { - invariant( - !(keySelector_ == null && compareKeys_ != null), - "You can't provide a compare function without also providing a key selector.", - ); +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +exports.default = (func, keySelector_, compareKeys_) => { + if (!!(keySelector_ == null && compareKeys_ != null)) { + throw new Error("You can't provide a compare function without also providing a key selector."); + } let prevKey = null; let prevResult; const keySelector = keySelector_ || DEFAULT_KEY_SELECTOR; - const compareKeys = compareKeys_ || arrayEqual; - return function(...args) { - const key = (keySelector: Function)(...args); - invariant(key != null, 'Key cannot be null'); + const compareKeys = compareKeys_ || (_collection || _load_collection()).arrayEqual; + return function (...args) { + const key = keySelector(...args); + + if (!(key != null)) { + throw new Error('Key cannot be null'); + } + if (prevKey == null || !compareKeys(key, prevKey)) { prevKey = key; - prevResult = (func: Function).apply(this, args); + prevResult = func.apply(this, args); } return prevResult; }; -}: memoizeUntilChanged); +}; -const DEFAULT_KEY_SELECTOR = (...args) => args; +const DEFAULT_KEY_SELECTOR = (...args) => args; \ No newline at end of file diff --git a/modules/nuclide-commons/nice.js b/modules/nuclide-commons/nice.js index 61115d1a..78fca77f 100644 --- a/modules/nuclide-commons/nice.js +++ b/modules/nuclide-commons/nice.js @@ -1,38 +1,25 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import type {LRUCache} from 'lru-cache'; -import type {ObserveProcessOptions, ProcessMessage} from './process'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.niceSafeSpawn = undefined; -import LRU from 'lru-cache'; -import {Observable} from 'rxjs'; +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); -import which from './which'; -import {spawn, observeProcess} from './process'; +let niceSafeSpawn = exports.niceSafeSpawn = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (command, args, execOptions) { + const nicified = yield nicifyCommand(command, args, execOptions); + const processStream = (0, (_process || _load_process()).spawn)(...nicified).publish(); + const processPromise = processStream.take(1).toPromise(); + processStream.connect(); + return processPromise; + }); -const NICE_COMMAND = 'nice'; -const IONICE_COMMAND = 'ionice'; - -export async function niceSafeSpawn( - command: string, - args: Array, - execOptions?: Object, -): Promise { - const nicified = await nicifyCommand(command, args, execOptions); - const processStream = spawn(...nicified).publish(); - const processPromise = processStream.take(1).toPromise(); - processStream.connect(); - return processPromise; -} + return function niceSafeSpawn(_x, _x2, _x3) { + return _ref.apply(this, arguments); + }; +})(); /** * Takes the arguments that you would normally pass to `spawn()` and returns an array of new @@ -46,62 +33,99 @@ export async function niceSafeSpawn( * * See also `scriptifyCommand()` which does a similar thing but for `script`. */ -async function nicifyCommand( - command: string, - args?: Array, - options: T, -): Promise<[string, Array, T]> { - const fullArgs = [command, ...(args || [])]; - if (await hasNiceCommand()) { - fullArgs.unshift(NICE_COMMAND); - } - if (await hasIoniceCommand()) { - // Leave the process in the Best Effort class (default), but set it to the lowest priority for - // that class. Priorities range from 0-7 with 4 as the default and lower numbers representing - // higher priorities. - // - // See `man ionice` or http://linux.die.net/man/1/ionice - // - // It's not specified by POSIX like `nice` is but since it is included in util-linux which is - // relatively core - // (https://git.kernel.org/cgit/utils/util-linux/util-linux.git/tree/schedutils/ionice.c), I - // think we can assume that it uses this interface if it exists. - fullArgs.unshift(IONICE_COMMAND, '-n', '7'); - } - return [fullArgs[0], fullArgs.slice(1), options]; + + +let nicifyCommand = (() => { + var _ref2 = (0, _asyncToGenerator.default)(function* (command, args, options) { + const fullArgs = [command, ...(args || [])]; + if (yield hasNiceCommand()) { + fullArgs.unshift(NICE_COMMAND); + } + if (yield hasIoniceCommand()) { + // Leave the process in the Best Effort class (default), but set it to the lowest priority for + // that class. Priorities range from 0-7 with 4 as the default and lower numbers representing + // higher priorities. + // + // See `man ionice` or http://linux.die.net/man/1/ionice + // + // It's not specified by POSIX like `nice` is but since it is included in util-linux which is + // relatively core + // (https://git.kernel.org/cgit/utils/util-linux/util-linux.git/tree/schedutils/ionice.c), I + // think we can assume that it uses this interface if it exists. + fullArgs.unshift(IONICE_COMMAND, '-n', '7'); + } + return [fullArgs[0], fullArgs.slice(1), options]; + }); + + return function nicifyCommand(_x4, _x5, _x6) { + return _ref2.apply(this, arguments); + }; +})(); + +exports.niceObserveProcess = niceObserveProcess; + +var _lruCache; + +function _load_lruCache() { + return _lruCache = _interopRequireDefault(require('lru-cache')); } -const commandAvailabilityCache: LRUCache> = LRU({ +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _which; + +function _load_which() { + return _which = _interopRequireDefault(require('./which')); +} + +var _process; + +function _load_process() { + return _process = require('./process'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const NICE_COMMAND = 'nice'; +const IONICE_COMMAND = 'ionice'; + +const commandAvailabilityCache = (0, (_lruCache || _load_lruCache()).default)({ max: 10, // Realistically this will not change very often so we can cache for long periods of time. We // probably could just check at startup and get away with it, but maybe someone will install // `ionice` and it would be nice to pick that up. - maxAge: 1000 * 60 * 5, // 5 minutes + maxAge: 1000 * 60 * 5 // 5 minutes }); -function hasNiceCommand(): Promise { +function hasNiceCommand() { return hasCommand(NICE_COMMAND); } -function hasIoniceCommand(): Promise { +function hasIoniceCommand() { return hasCommand(IONICE_COMMAND); } -function hasCommand(command: string): Promise { - let result: ?Promise = commandAvailabilityCache.get(command); +function hasCommand(command) { + let result = commandAvailabilityCache.get(command); if (result == null) { - result = which(command).then(x => x != null); + result = (0, (_which || _load_which()).default)(command).then(x => x != null); commandAvailabilityCache.set(command, result); } return result; } -export function niceObserveProcess( - command: string, - args?: Array, - options?: ObserveProcessOptions, -): Observable { - return Observable.defer(() => - nicifyCommand(command, args, options), - ).switchMap(spawnArgs => observeProcess(...spawnArgs)); -} +function niceObserveProcess(command, args, options) { + return _rxjsBundlesRxMinJs.Observable.defer(() => nicifyCommand(command, args, options)).switchMap(spawnArgs => (0, (_process || _load_process()).observeProcess)(...spawnArgs)); +} \ No newline at end of file diff --git a/modules/nuclide-commons/nuclideUri.js b/modules/nuclide-commons/nuclideUri.js index 0bc223c2..2effba35 100644 --- a/modules/nuclide-commons/nuclideUri.js +++ b/modules/nuclide-commons/nuclideUri.js @@ -1,3 +1,28 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.__TEST__ = undefined; + +var _vscodeUri; + +function _load_vscodeUri() { + return _vscodeUri = _interopRequireDefault(require('vscode-uri')); +} + +var _path = _interopRequireDefault(require('path')); + +var _os = _interopRequireDefault(require('os')); + +var _string; + +function _load_string() { + return _string = require('./string'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +31,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -15,36 +40,9 @@ // // This package creates, queries and decomposes NuclideUris. -import LspUri from 'vscode-uri'; - -export type NuclideUri = string; - -type ParsedUrl = { - hostname: ?string, - path: string, -}; - -type ParsedRemoteUrl = { - hostname: string, - path: string, -}; - -type ParsedPath = { - root: string, - dir: string, - base: string, - ext: string, - name: string, -}; - -import invariant from 'assert'; +const ARCHIVE_SEPARATOR = '!'; // eslint-disable-next-line rulesdir/prefer-nuclide-uri -import pathModule from 'path'; -import os from 'os'; -import {maybeToString} from './string'; - -const ARCHIVE_SEPARATOR = '!'; const KNOWN_ARCHIVE_EXTENSIONS = ['.jar', '.zip']; const REMOTE_PATH_URI_PREFIX = 'nuclide://'; @@ -52,7 +50,7 @@ const REMOTE_PATH_URI_PREFIX = 'nuclide://'; // [A-Za-z] not [0-9_-]. Also, not all schemes require // after them. const URI_PREFIX_REGEX = /^[A-Za-z0-9_-]+:\/\/.*/; -function isRemote(uri: NuclideUri): boolean { +function isRemote(uri) { return uri.startsWith(REMOTE_PATH_URI_PREFIX); } @@ -60,40 +58,36 @@ function isRemote(uri: NuclideUri): boolean { // removing one of the '/'s. These TextBuffers/TextEditors live for a short time // and are destroyed during Nuclide startup. // On Windows, we further mangle the colon into an underscore to avoid an invalid drive prefix. -function isBrokenDeserializedUri(uri: ?NuclideUri): boolean { +function isBrokenDeserializedUri(uri) { return uri != null && uri.match(/nuclide[:_][\\/][^/]/) != null; } // Atom often puts its URIs in places where we'd expect to see Nuclide URIs (or plain paths) -function isAtomUri(uri: NuclideUri): boolean { +function isAtomUri(uri) { return uri.startsWith('atom://'); } -function isUri(uri: string): boolean { +function isUri(uri) { return URI_PREFIX_REGEX.test(uri); } -function isLocal(uri: NuclideUri): boolean { +function isLocal(uri) { return !isRemote(uri) && !isUri(uri) && !isAtomUri(uri); } -function createRemoteUri(hostname: string, remotePath: string): string { - invariant( - remotePath != null && remotePath !== '', - 'NuclideUri must include a path.', - ); +function createRemoteUri(hostname, remotePath) { + if (!(remotePath != null && remotePath !== '')) { + throw new Error('NuclideUri must include a path.'); + } + return `nuclide://${hostname}${remotePath}`; } -function isInArchive(uri: NuclideUri): boolean { +function isInArchive(uri) { if (isAtomUri(uri) || uri.indexOf(ARCHIVE_SEPARATOR) < 0) { return false; } - for ( - let i = uri.indexOf(ARCHIVE_SEPARATOR); - i >= 0; - i = uri.indexOf(ARCHIVE_SEPARATOR, i + 1) - ) { + for (let i = uri.indexOf(ARCHIVE_SEPARATOR); i >= 0; i = uri.indexOf(ARCHIVE_SEPARATOR, i + 1)) { if (_isArchiveSeparator(uri, i)) { return true; } @@ -101,12 +95,8 @@ function isInArchive(uri: NuclideUri): boolean { return false; } -function ancestorOutsideArchive(uri: NuclideUri): NuclideUri { - for ( - let i = uri.indexOf(ARCHIVE_SEPARATOR); - i >= 0; - i = uri.indexOf(ARCHIVE_SEPARATOR, i + 1) - ) { +function ancestorOutsideArchive(uri) { + for (let i = uri.indexOf(ARCHIVE_SEPARATOR); i >= 0; i = uri.indexOf(ARCHIVE_SEPARATOR, i + 1)) { if (_isArchiveSeparator(uri, i)) { return uri.substring(0, i); } @@ -123,67 +113,68 @@ function ancestorOutsideArchive(uri: NuclideUri): NuclideUri { * Everything that does not contain a '://' is assumed to be a local path. Both POSIX and Windows * paths are legal */ -function parse(uri: NuclideUri): ParsedUrl { +function parse(uri) { if (uri.startsWith(REMOTE_PATH_URI_PREFIX)) { const hostAndPath = uri.substr(REMOTE_PATH_URI_PREFIX.length); const hostSep = hostAndPath.indexOf('/'); - invariant( - hostSep !== -1, - `Remote URIs must contain a hostname and a path. Failed to parse ${uri}`, - ); + if (!(hostSep !== -1)) { + throw new Error(`Remote URIs must contain a hostname and a path. Failed to parse ${uri}`); + } const hostname = hostAndPath.substr(0, hostSep); - invariant( - hostname !== '', - `Remote URIs must contain a hostname. Failed to parse ${uri}`, - ); + + if (!(hostname !== '')) { + throw new Error(`Remote URIs must contain a hostname. Failed to parse ${uri}`); + } const path = hostAndPath.substr(hostSep); - invariant( - !_endsWithArchiveSeparator(uri), - `Path cannot end with archive separator. Failed to parse ${uri}`, - ); - return {hostname, path}; + + if (!!_endsWithArchiveSeparator(uri)) { + throw new Error(`Path cannot end with archive separator. Failed to parse ${uri}`); + } + + return { hostname, path }; } - invariant( - !_endsWithArchiveSeparator(uri), - `Path cannot end with archive separator. Failed to parse ${uri}`, - ); - return {hostname: null, path: uri}; + if (!!_endsWithArchiveSeparator(uri)) { + throw new Error(`Path cannot end with archive separator. Failed to parse ${uri}`); + } + + return { hostname: null, path: uri }; } -function parseRemoteUri(remoteUri: NuclideUri): ParsedRemoteUrl { +function parseRemoteUri(remoteUri) { if (!isRemote(remoteUri)) { throw new Error('Expected remote uri. Got ' + remoteUri); } const parsedUri = parse(remoteUri); - invariant( - // flowlint-next-line sketchy-null-string:off - parsedUri.hostname, - `Remote Nuclide URIs must contain hostnames, '${maybeToString( - parsedUri.hostname, - )}' found while parsing '${remoteUri}'`, - ); + + if (! + // flowlint-next-line sketchy-null-string:off + parsedUri.hostname) { + throw new Error(`Remote Nuclide URIs must contain hostnames, '${(0, (_string || _load_string()).maybeToString)(parsedUri.hostname)}' found while parsing '${remoteUri}'`); + } // Explicitly copying object properties appeases Flow's "maybe" type handling. Using the `...` // operator causes null/undefined errors, and `Object.assign` bypasses type checking. + + return { hostname: parsedUri.hostname, - path: parsedUri.path, + path: parsedUri.path }; } -function getPath(uri: NuclideUri): string { +function getPath(uri) { return parse(uri).path; } -function getHostname(remoteUri: NuclideUri): string { +function getHostname(remoteUri) { return parseRemoteUri(remoteUri).hostname; } -function getHostnameOpt(remoteUri: ?NuclideUri): ?string { +function getHostnameOpt(remoteUri) { if (remoteUri == null || !isRemote(remoteUri)) { return null; } @@ -191,28 +182,22 @@ function getHostnameOpt(remoteUri: ?NuclideUri): ?string { return getHostname(remoteUri); } -function join(uri: NuclideUri, ...relativePath: Array): NuclideUri { +function join(uri, ...relativePath) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); if (isRemote(uri)) { - const {hostname, path} = parseRemoteUri(uri); + const { hostname, path } = parseRemoteUri(uri); relativePath.splice(0, 0, path); _archiveEncodeArrayInPlace(uriPathModule, relativePath); - return _archiveDecode( - uriPathModule, - createRemoteUri(hostname, uriPathModule.join.apply(null, relativePath)), - ); + return _archiveDecode(uriPathModule, createRemoteUri(hostname, uriPathModule.join.apply(null, relativePath))); } else { relativePath.splice(0, 0, uri); _archiveEncodeArrayInPlace(uriPathModule, relativePath); - return _archiveDecode( - uriPathModule, - uriPathModule.join.apply(null, relativePath), - ); + return _archiveDecode(uriPathModule, uriPathModule.join.apply(null, relativePath)); } } -function archiveJoin(uri: NuclideUri, path: string): NuclideUri { +function archiveJoin(uri, path) { _testForIllegalUri(uri); if (!KNOWN_ARCHIVE_EXTENSIONS.some(ext => uri.endsWith(ext))) { throw new Error(`Cannot archiveJoin with non-archive ${uri} and ${path}`); @@ -220,98 +205,63 @@ function archiveJoin(uri: NuclideUri, path: string): NuclideUri { return uri + ARCHIVE_SEPARATOR + path; } -function normalize(uri: NuclideUri): NuclideUri { +function normalize(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); if (isRemote(uri)) { - const {hostname, path} = parseRemoteUri(uri); - const normal = _archiveDecode( - uriPathModule, - uriPathModule.normalize(_archiveEncode(uriPathModule, path)), - ); + const { hostname, path } = parseRemoteUri(uri); + const normal = _archiveDecode(uriPathModule, uriPathModule.normalize(_archiveEncode(uriPathModule, path))); return createRemoteUri(hostname, normal); } else { - return _archiveDecode( - uriPathModule, - uriPathModule.normalize(_archiveEncode(uriPathModule, uri)), - ); + return _archiveDecode(uriPathModule, uriPathModule.normalize(_archiveEncode(uriPathModule, uri))); } } -function normalizeDir(uri: NuclideUri): NuclideUri { +function normalizeDir(uri) { return ensureTrailingSeparator(normalize(uri)); } -function getParent(uri: NuclideUri): NuclideUri { +function getParent(uri) { // TODO: Is this different than dirname? return normalize(join(uri, '..')); } -function relative(uri: NuclideUri, other: NuclideUri): string { +function relative(uri, other) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); const remote = isRemote(uri); - if ( - remote !== isRemote(other) || - (remote && getHostname(uri) !== getHostname(other)) - ) { - throw new Error( - `Cannot relative urls on different hosts: ${uri} and ${other}`, - ); + if (remote !== isRemote(other) || remote && getHostname(uri) !== getHostname(other)) { + throw new Error(`Cannot relative urls on different hosts: ${uri} and ${other}`); } const uriEncode = _archiveEncode(uriPathModule, remote ? getPath(uri) : uri); - const otherEncode = _archiveEncode( - uriPathModule, - remote ? getPath(other) : other, - ); - return _archiveDecode( - uriPathModule, - uriPathModule.relative( - _matchTrailingArchive(uriEncode, otherEncode), - _matchTrailingArchive(otherEncode, uriEncode), - ), - ); -} - -function basename(uri: NuclideUri, ext: string = ''): string { + const otherEncode = _archiveEncode(uriPathModule, remote ? getPath(other) : other); + return _archiveDecode(uriPathModule, uriPathModule.relative(_matchTrailingArchive(uriEncode, otherEncode), _matchTrailingArchive(otherEncode, uriEncode))); +} + +function basename(uri, ext = '') { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); - return _archiveDecode( - uriPathModule, - uriPathModule.basename(_archiveEncode(uriPathModule, getPath(uri)), ext), - ); + return _archiveDecode(uriPathModule, uriPathModule.basename(_archiveEncode(uriPathModule, getPath(uri)), ext)); } -function dirname(uri: NuclideUri): NuclideUri { +function dirname(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); if (isRemote(uri)) { - const {hostname, path} = parseRemoteUri(uri); - return createRemoteUri( - hostname, - _archiveDecode( - uriPathModule, - uriPathModule.dirname(_archiveEncode(uriPathModule, path)), - ), - ); + const { hostname, path } = parseRemoteUri(uri); + return createRemoteUri(hostname, _archiveDecode(uriPathModule, uriPathModule.dirname(_archiveEncode(uriPathModule, path)))); } else { - return _archiveDecode( - uriPathModule, - uriPathModule.dirname(_archiveEncode(uriPathModule, uri)), - ); + return _archiveDecode(uriPathModule, uriPathModule.dirname(_archiveEncode(uriPathModule, uri))); } } -function extname(uri: NuclideUri): string { +function extname(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); - return _archiveDecode( - uriPathModule, - uriPathModule.extname(_archiveEncode(uriPathModule, getPath(uri))), - ); + return _archiveDecode(uriPathModule, uriPathModule.extname(_archiveEncode(uriPathModule, getPath(uri)))); } -function stripExtension(uri: NuclideUri): NuclideUri { +function stripExtension(uri) { _testForIllegalUri(uri); const ext = extname(uri); if (ext.length === 0) { @@ -321,11 +271,11 @@ function stripExtension(uri: NuclideUri): NuclideUri { return uri.slice(0, -1 * ext.length); } -function _isWindowsPath(path: string): boolean { - return _pathModuleFor(path) === pathModule.win32; +function _isWindowsPath(path) { + return _pathModuleFor(path) === _path.default.win32; } -function _getWindowsPathFromWindowsFileUri(uri: string): ?string { +function _getWindowsPathFromWindowsFileUri(uri) { const prefix = 'file://'; if (!uri.startsWith(prefix)) { return null; @@ -341,7 +291,7 @@ function _getWindowsPathFromWindowsFileUri(uri: string): ?string { * * Returns null if not a valid file: URI. */ -function uriToNuclideUri(uri: string): ?string { +function uriToNuclideUri(uri) { // TODO(ljw): the following check is incorrect. It's designed to support // two-slash file URLs of the form "file://c:\path". But those are invalid // file URLs, and indeed it fails to %-escape "file://c:\My%20Documents". @@ -355,7 +305,7 @@ function uriToNuclideUri(uri: string): ?string { return windowsPathFromUri; } - const lspUri = LspUri.parse(uri); + const lspUri = (_vscodeUri || _load_vscodeUri()).default.parse(uri); if (lspUri.scheme === 'file' && lspUri.path) { // only handle real files for now. @@ -370,19 +320,19 @@ function uriToNuclideUri(uri: string): ?string { /** * Converts local paths to file: URI's. Leaves remote URI's alone. */ -function nuclideUriToUri(uri: NuclideUri): string { +function nuclideUriToUri(uri) { _testForIllegalUri(uri); if (isRemote(uri)) { return uri; } else { - return LspUri.file(uri).toString(); + return (_vscodeUri || _load_vscodeUri()).default.file(uri).toString(); } } /** * Returns true if child is equal to, or is a proper child of parent. */ -function contains(parent: NuclideUri, child: NuclideUri): boolean { +function contains(parent, child) { _testForIllegalUri(parent); _testForIllegalUri(child); @@ -409,10 +359,7 @@ function contains(parent: NuclideUri, child: NuclideUri): boolean { return false; } - return ( - parent.startsWith(child) && - (endsWithSeparator(parent) || _isArchiveSeparator(child, parent.length)) - ); + return parent.startsWith(child) && (endsWithSeparator(parent) || _isArchiveSeparator(child, parent.length)); } if (!child.startsWith(parent)) { @@ -425,17 +372,14 @@ function contains(parent: NuclideUri, child: NuclideUri): boolean { const uriPathModule = _pathModuleFor(child); - return ( - _isArchiveSeparator(child, parent.length) || - child.slice(parent.length).startsWith(uriPathModule.sep) - ); + return _isArchiveSeparator(child, parent.length) || child.slice(parent.length).startsWith(uriPathModule.sep); } /** * Filter an array of paths to contain only the collapsed root paths, e.g. * [a/b/c, a/, c/d/, c/d/e] collapses to [a/, c/d/] */ -function collapse(paths: Array): Array { +function collapse(paths) { return paths.filter(p => !paths.some(fp => contains(fp, p) && fp !== p)); } @@ -443,10 +387,10 @@ const hostFormatters = []; // A formatter which may shorten hostnames. // Returns null if the formatter won't shorten the hostname. -export type HostnameFormatter = (uri: NuclideUri) => ?string; + // Registers a host formatter for nuclideUriToDisplayString -function registerHostnameFormatter(formatter: HostnameFormatter): IDisposable { +function registerHostnameFormatter(formatter) { hostFormatters.push(formatter); return { dispose: () => { @@ -454,7 +398,7 @@ function registerHostnameFormatter(formatter: HostnameFormatter): IDisposable { if (index >= 0) { hostFormatters.splice(index, 1); } - }, + } }; } @@ -462,7 +406,7 @@ function registerHostnameFormatter(formatter: HostnameFormatter): IDisposable { * NuclideUris should never be shown to humans. * This function returns a human usable string. */ -function nuclideUriToDisplayString(uri: NuclideUri): string { +function nuclideUriToDisplayString(uri) { _testForIllegalUri(uri); if (isRemote(uri)) { let hostname = getHostname(uri); @@ -480,7 +424,7 @@ function nuclideUriToDisplayString(uri: NuclideUri): string { } } -function ensureTrailingSeparator(uri: NuclideUri): NuclideUri { +function ensureTrailingSeparator(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); if (uri.endsWith(uriPathModule.sep)) { @@ -490,7 +434,7 @@ function ensureTrailingSeparator(uri: NuclideUri): NuclideUri { return uri + uriPathModule.sep; } -function trimTrailingSeparator(uri: NuclideUri): NuclideUri { +function trimTrailingSeparator(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); let stripped = uri; @@ -502,13 +446,13 @@ function trimTrailingSeparator(uri: NuclideUri): NuclideUri { return stripped; } -function endsWithSeparator(uri: NuclideUri): boolean { +function endsWithSeparator(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); return uri.endsWith(uriPathModule.sep); } -function isAbsolute(uri: NuclideUri): boolean { +function isAbsolute(uri) { _testForIllegalUri(uri); if (isRemote(uri)) { return true; @@ -518,28 +462,22 @@ function isAbsolute(uri: NuclideUri): boolean { } } -function resolve(uri: NuclideUri, ...paths: Array): NuclideUri { +function resolve(uri, ...paths) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); if (isRemote(uri)) { - const {hostname, path} = parseRemoteUri(uri); + const { hostname, path } = parseRemoteUri(uri); paths.splice(0, 0, path); _archiveEncodeArrayInPlace(uriPathModule, paths); - return createRemoteUri( - hostname, - _archiveDecode(uriPathModule, uriPathModule.resolve.apply(null, paths)), - ); + return createRemoteUri(hostname, _archiveDecode(uriPathModule, uriPathModule.resolve.apply(null, paths))); } else { paths.splice(0, 0, uri); _archiveEncodeArrayInPlace(uriPathModule, paths); - return _archiveDecode( - uriPathModule, - uriPathModule.resolve.apply(null, paths), - ); + return _archiveDecode(uriPathModule, uriPathModule.resolve.apply(null, paths)); } } -function expandHomeDir(uri: NuclideUri): NuclideUri { +function expandHomeDir(uri) { _testForIllegalUri(uri); // Do not expand non home relative uris @@ -550,11 +488,14 @@ function expandHomeDir(uri: NuclideUri): NuclideUri { // "home" on Windows is %UserProfile%. Note that Windows environment variables // are NOT case sensitive, but process.env is a magic object that wraps GetEnvironmentVariableW // on Windows, so asking for any case is expected to work. - const {HOME, UserProfile} = process.env; + const { HOME, UserProfile } = process.env; - const isWindows = !isRemote(uri) && os.platform() === 'win32'; + const isWindows = !isRemote(uri) && _os.default.platform() === 'win32'; const homePath = isWindows ? UserProfile : HOME; - invariant(homePath != null); + + if (!(homePath != null)) { + throw new Error('Invariant violation: "homePath != null"'); + } if (uri === '~') { return homePath; @@ -565,7 +506,7 @@ function expandHomeDir(uri: NuclideUri): NuclideUri { return uri; } - return pathModule.resolve(homePath, uri.replace('~', '.')); + return _path.default.resolve(homePath, uri.replace('~', '.')); } /** @@ -574,11 +515,11 @@ function expandHomeDir(uri: NuclideUri): NuclideUri { * * Since remote URI might contain the delimiter, only local paths are allowed. */ -function splitPathList(paths: string): Array { - invariant( - paths.indexOf(REMOTE_PATH_URI_PREFIX) < 0, - 'Splitting remote URIs is not supported', - ); +function splitPathList(paths) { + if (!(paths.indexOf(REMOTE_PATH_URI_PREFIX) < 0)) { + throw new Error('Splitting remote URIs is not supported'); + } + const uriPathModule = _pathModuleFor(paths); return paths.split(uriPathModule.delimiter); @@ -590,15 +531,14 @@ function splitPathList(paths: string): Array { * * Since remote URI might contain the delimiter, only local paths are allowed. */ -function joinPathList(paths: Array): string { +function joinPathList(paths) { if (paths.length === 0) { return ''; } - invariant( - paths.every(path => !isRemote(path)), - 'Joining of remote URIs is not supported', - ); + if (!paths.every(path => !isRemote(path))) { + throw new Error('Joining of remote URIs is not supported'); + } const uriPathModule = _pathModuleFor(paths[0]); return paths.join(uriPathModule.delimiter); @@ -608,15 +548,17 @@ function joinPathList(paths: Array): string { * This function prepends the given relative path with a "current-folder" prefix * which is `./` on *nix and .\ on Windows */ -function ensureLocalPrefix(uri: NuclideUri): NuclideUri { +function ensureLocalPrefix(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); - invariant(!isRemote(uri), 'Local prefix can not be added to a remote path'); - invariant( - !isAbsolute(uri), - 'Local prefix can not be added to an absolute path', - ); + if (!!isRemote(uri)) { + throw new Error('Local prefix can not be added to a remote path'); + } + + if (!!isAbsolute(uri)) { + throw new Error('Local prefix can not be added to an absolute path'); + } const localPrefix = `.${uriPathModule.sep}`; if (uri.startsWith(localPrefix)) { @@ -626,35 +568,33 @@ function ensureLocalPrefix(uri: NuclideUri): NuclideUri { return localPrefix + uri; } -function isRoot(uri: NuclideUri): boolean { +function isRoot(uri) { _testForIllegalUri(uri); return dirname(uri) === uri; } -function parsePath(uri: NuclideUri): ParsedPath { +function parsePath(uri) { _testForIllegalUri(uri); const uriPathModule = _pathModuleFor(uri); if (!isInArchive(uri)) { return uriPathModule.parse(getPath(uri)); } else { - const parsed = uriPathModule.parse( - _archiveEncode(uriPathModule, getPath(uri)), - ); + const parsed = uriPathModule.parse(_archiveEncode(uriPathModule, getPath(uri))); return { root: _archiveDecode(uriPathModule, parsed.root), dir: _archiveDecode(uriPathModule, parsed.dir), base: _archiveDecode(uriPathModule, parsed.base), ext: _archiveDecode(uriPathModule, parsed.ext), - name: _archiveDecode(uriPathModule, parsed.name), + name: _archiveDecode(uriPathModule, parsed.name) }; } } -function pathSeparatorFor(uri: NuclideUri): string { +function pathSeparatorFor(uri) { return _pathModuleFor(uri).sep; } -function split(uri: NuclideUri): Array { +function split(uri) { const parts = []; let current = uri; let parent = dirname(current); @@ -673,82 +613,54 @@ function split(uri: NuclideUri): Array { return parts; } -function hasKnownArchiveExtension(uri: NuclideUri): boolean { +function hasKnownArchiveExtension(uri) { return KNOWN_ARCHIVE_EXTENSIONS.some(ext => uri.endsWith(ext)); } -function _pathModuleFor(uri: NuclideUri): typeof pathModule { - invariant( - !_endsWithArchiveSeparator(uri), - `Path cannot end with archive separator. Failed to determine path module for ${uri}`, - ); - if (uri.startsWith(pathModule.posix.sep)) { - return pathModule.posix; +function _pathModuleFor(uri) { + if (!!_endsWithArchiveSeparator(uri)) { + throw new Error(`Path cannot end with archive separator. Failed to determine path module for ${uri}`); + } + + if (uri.startsWith(_path.default.posix.sep)) { + return _path.default.posix; } if (uri.indexOf('://') > -1) { - return pathModule.posix; + return _path.default.posix; } - if (uri[1] === ':' && uri[2] === pathModule.win32.sep) { - return pathModule.win32; + if (uri[1] === ':' && uri[2] === _path.default.win32.sep) { + return _path.default.win32; } - if ( - uri.split(pathModule.win32.sep).length > - uri.split(pathModule.posix.sep).length - ) { - return pathModule.win32; + if (uri.split(_path.default.win32.sep).length > uri.split(_path.default.posix.sep).length) { + return _path.default.win32; } else { - return pathModule.posix; + return _path.default.posix; } } // Runs _archiveEncode in-place on array, and returns argument for convenience. -function _archiveEncodeArrayInPlace( - uriPathModule: typeof pathModule, - array: Array, -): Array { - array.forEach((uri, i, a) => (a[i] = _archiveEncode(uriPathModule, uri))); +function _archiveEncodeArrayInPlace(uriPathModule, array) { + array.forEach((uri, i, a) => a[i] = _archiveEncode(uriPathModule, uri)); return array; } // This adds a native separator after every archive separator // so that the native path handling code sees them. -function _archiveEncode( - uriPathModule: typeof pathModule, - uri: NuclideUri, -): NuclideUri { +function _archiveEncode(uriPathModule, uri) { if (uri.indexOf(ARCHIVE_SEPARATOR) < 0) { return uri; } - return KNOWN_ARCHIVE_EXTENSIONS.reduce( - (acc, ext) => - acc.replace( - `${ext}${ARCHIVE_SEPARATOR}`, - `${ext}${ARCHIVE_SEPARATOR}${uriPathModule.sep}`, - ), - uri, - ); + return KNOWN_ARCHIVE_EXTENSIONS.reduce((acc, ext) => acc.replace(`${ext}${ARCHIVE_SEPARATOR}`, `${ext}${ARCHIVE_SEPARATOR}${uriPathModule.sep}`), uri); } // This is the inverse of `encodeArchiveSeparators()` to put things // back after the native path handler has run. -function _archiveDecode( - uriPathModule: typeof pathModule, - uri: NuclideUri, -): NuclideUri { +function _archiveDecode(uriPathModule, uri) { if (uri.indexOf(ARCHIVE_SEPARATOR) < 0) { return uri; } - return _trimArchiveSuffix( - KNOWN_ARCHIVE_EXTENSIONS.reduce( - (acc, ext) => - acc.replace( - `${ext}${ARCHIVE_SEPARATOR}${uriPathModule.sep}`, - `${ext}${ARCHIVE_SEPARATOR}`, - ), - uri, - ), - ); + return _trimArchiveSuffix(KNOWN_ARCHIVE_EXTENSIONS.reduce((acc, ext) => acc.replace(`${ext}${ARCHIVE_SEPARATOR}${uriPathModule.sep}`, `${ext}${ARCHIVE_SEPARATOR}`), uri)); } // When working with encoded uri's, the archive separator is part of the name @@ -762,19 +674,15 @@ function _archiveDecode( // /etc/file.zip!/abc // We need to add a trailing '!' to the first one so uriPathModule can see that // the first contains the second. -function _matchTrailingArchive(uri: string, other: string): string { - if ( - uri.length < other.length && - other.startsWith(uri) && - _isArchiveSeparator(other, uri.length) - ) { +function _matchTrailingArchive(uri, other) { + if (uri.length < other.length && other.startsWith(uri) && _isArchiveSeparator(other, uri.length)) { return uri + ARCHIVE_SEPARATOR; } else { return uri; } } -function _trimArchiveSuffix(path: string): string { +function _trimArchiveSuffix(path) { if (_endsWithArchiveSeparator(path)) { return path.substring(0, path.length - ARCHIVE_SEPARATOR.length); } else { @@ -782,27 +690,21 @@ function _trimArchiveSuffix(path: string): string { } } -function _endsWithArchiveSeparator(path: string): boolean { +function _endsWithArchiveSeparator(path) { return _isArchiveSeparator(path, path.length - 1); } -function _isArchiveSeparator(path: string, index: number): boolean { - return ( - path.length > index && - path.charAt(index) === ARCHIVE_SEPARATOR && - KNOWN_ARCHIVE_EXTENSIONS.some(ext => { - const extStart = index - ext.length; - return path.indexOf(ext, extStart) === extStart; - }) - ); +function _isArchiveSeparator(path, index) { + return path.length > index && path.charAt(index) === ARCHIVE_SEPARATOR && KNOWN_ARCHIVE_EXTENSIONS.some(ext => { + const extStart = index - ext.length; + return path.indexOf(ext, extStart) === extStart; + }); } -function _testForIllegalUri(uri: ?NuclideUri): void { +function _testForIllegalUri(uri) { if (uri != null) { if (_endsWithArchiveSeparator(uri)) { - throw new Error( - `Path operation invoked on URI ending with ${ARCHIVE_SEPARATOR}: ${uri}`, - ); + throw new Error(`Path operation invoked on URI ending with ${ARCHIVE_SEPARATOR}: ${uri}`); } } } @@ -811,24 +713,34 @@ const NUCLIDE_URI_TYPE_NAME = 'NuclideUri'; // If mustBeRemote is present then remote-ness must match, otherwise remote-ness // is ignored. -function validate(uri: NuclideUri, mustBeRemote?: boolean): void { +function validate(uri, mustBeRemote) { // Be a little extra paranoid to catch places where the type system may be weak. - invariant(uri != null, 'Unexpected null NuclideUri'); - invariant( - typeof uri === 'string', - `Unexpected NuclideUri type: ${String(uri)}`, - ); + if (!(uri != null)) { + throw new Error('Unexpected null NuclideUri'); + } + + if (!(typeof uri === 'string')) { + throw new Error(`Unexpected NuclideUri type: ${String(uri)}`); + } if (isRemote(uri)) { parse(uri); - invariant(mustBeRemote !== false, 'Expected remote NuclideUri'); + + if (!(mustBeRemote !== false)) { + throw new Error('Expected remote NuclideUri'); + } } else { - invariant(uri !== '', 'NuclideUri must contain a non-empty path'); - invariant(mustBeRemote !== true, 'Expected local NuclideUri'); + if (!(uri !== '')) { + throw new Error('NuclideUri must contain a non-empty path'); + } + + if (!(mustBeRemote !== true)) { + throw new Error('Expected local NuclideUri'); + } } } -export default { +exports.default = { basename, dirname, extname, @@ -873,9 +785,8 @@ export default { hasKnownArchiveExtension, ARCHIVE_SEPARATOR, KNOWN_ARCHIVE_EXTENSIONS, - NUCLIDE_URI_TYPE_NAME, -}; - -export const __TEST__ = { - _pathModuleFor, + NUCLIDE_URI_TYPE_NAME }; +const __TEST__ = exports.__TEST__ = { + _pathModuleFor +}; \ No newline at end of file diff --git a/modules/nuclide-commons/observable.js b/modules/nuclide-commons/observable.js index 209ce050..9ac35f02 100644 --- a/modules/nuclide-commons/observable.js +++ b/modules/nuclide-commons/observable.js @@ -1,3 +1,56 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SingletonExecutor = exports.PromiseCanceledError = exports.nextAnimationFrame = exports.macrotask = exports.microtask = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +exports.splitStream = splitStream; +exports.bufferUntil = bufferUntil; +exports.cacheWhileSubscribed = cacheWhileSubscribed; +exports.diffSets = diffSets; +exports.reconcileSetDiffs = reconcileSetDiffs; +exports.reconcileSets = reconcileSets; +exports.toggle = toggle; +exports.compact = compact; +exports.takeWhileInclusive = takeWhileInclusive; +exports.concatLatest = concatLatest; +exports.throttle = throttle; +exports.completingSwitchMap = completingSwitchMap; +exports.fastDebounce = fastDebounce; +exports.toCancelablePromise = toCancelablePromise; +exports.poll = poll; + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('./UniversalDisposable')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _collection; + +function _load_collection() { + return _collection = require('./collection'); +} + +var _debounce; + +function _load_debounce() { + return _debounce = _interopRequireDefault(require('./debounce')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Splits a stream of strings on newlines. + * Includes the newlines in the resulting stream (if includeNewlines is true). + * Sends any non-newline terminated data before closing. + * Does not ensure a trailing newline. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +59,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -24,24 +77,9 @@ // .let(makeExciting()) // .subscribe(x => console.log(x)); -import UniversalDisposable from './UniversalDisposable'; -import invariant from 'assert'; -import {Observable, ReplaySubject, Subject} from 'rxjs'; -import {setDifference} from './collection'; -import debounce from './debounce'; - -/** - * Splits a stream of strings on newlines. - * Includes the newlines in the resulting stream (if includeNewlines is true). - * Sends any non-newline terminated data before closing. - * Does not ensure a trailing newline. - */ -export function splitStream( - input: Observable, - includeNewlines?: boolean = true, -): Observable { - return Observable.create(observer => { - let current: string = ''; +function splitStream(input, includeNewlines = true) { + return _rxjsBundlesRxMinJs.Observable.create(observer => { + let current = ''; function onEnd() { if (current !== '') { @@ -50,26 +88,22 @@ export function splitStream( } } - return input.subscribe( - value => { - const lines = value.split('\n'); - lines[0] = current + lines[0]; - current = lines.pop(); - if (includeNewlines) { - lines.forEach(line => observer.next(line + '\n')); - } else { - lines.forEach(line => observer.next(line)); - } - }, - error => { - onEnd(); - observer.error(error); - }, - () => { - onEnd(); - observer.complete(); - }, - ); + return input.subscribe(value => { + const lines = value.split('\n'); + lines[0] = current + lines[0]; + current = lines.pop(); + if (includeNewlines) { + lines.forEach(line => observer.next(line + '\n')); + } else { + lines.forEach(line => observer.next(line)); + } + }, error => { + onEnd(); + observer.error(error); + }, () => { + onEnd(); + observer.complete(); + }); }); } @@ -82,38 +116,31 @@ export function splitStream( * (which includes the element). IMPORTANT: DO NOT MUTATE THE BUFFER. It returns a boolean * specifying whether to complete the buffer (and begin a new one). */ -export function bufferUntil( - condition: (item: T, buffer: Array) => boolean, -): (Observable) => Observable> { - return (stream: Observable) => - Observable.create(observer => { - let buffer = null; - const flush = () => { - if (buffer != null) { - observer.next(buffer); - buffer = null; - } - }; - return stream.subscribe( - x => { - if (buffer == null) { - buffer = []; - } - buffer.push(x); - if (condition(x, buffer)) { - flush(); - } - }, - err => { - flush(); - observer.error(err); - }, - () => { - flush(); - observer.complete(); - }, - ); +function bufferUntil(condition) { + return stream => _rxjsBundlesRxMinJs.Observable.create(observer => { + let buffer = null; + const flush = () => { + if (buffer != null) { + observer.next(buffer); + buffer = null; + } + }; + return stream.subscribe(x => { + if (buffer == null) { + buffer = []; + } + buffer.push(x); + if (condition(x, buffer)) { + flush(); + } + }, err => { + flush(); + observer.error(err); + }, () => { + flush(); + observer.complete(); }); + }); } /** @@ -124,49 +151,36 @@ export function bufferUntil( * be just fine because the hot Observable will continue producing values even when there are no * subscribers, so you can be assured that the cached values are up-to-date. */ -export function cacheWhileSubscribed(input: Observable): Observable { - return input.multicast(() => new ReplaySubject(1)).refCount(); +function cacheWhileSubscribed(input) { + return input.multicast(() => new _rxjsBundlesRxMinJs.ReplaySubject(1)).refCount(); } -type Diff = { - added: Set, - removed: Set, -}; - /** * Given a stream of sets, return a stream of diffs. * **IMPORTANT:** These sets are assumed to be immutable by convention. Don't mutate them! */ -export function diffSets( - hash?: (v: T) => any, -): (Observable>) => Observable> { - return (sets: Observable>) => - Observable.concat( - Observable.of(new Set()), // Always start with no items with an empty set - sets, - ) - .pairwise() - .map(([previous, next]) => ({ - added: setDifference(next, previous, hash), - removed: setDifference(previous, next, hash), - })) - .filter(diff => diff.added.size > 0 || diff.removed.size > 0); +function diffSets(hash) { + return sets => _rxjsBundlesRxMinJs.Observable.concat(_rxjsBundlesRxMinJs.Observable.of(new Set()), // Always start with no items with an empty set + sets).pairwise().map(([previous, next]) => ({ + added: (0, (_collection || _load_collection()).setDifference)(next, previous, hash), + removed: (0, (_collection || _load_collection()).setDifference)(previous, next, hash) + })).filter(diff => diff.added.size > 0 || diff.removed.size > 0); } /** * Give a stream of diffs, perform an action for each added item and dispose of the returned * disposable when the item is removed. */ -export function reconcileSetDiffs( - diffs: Observable>, - addAction: (addedItem: T) => IDisposable, - hash_?: (v: T) => any, -): IDisposable { +function reconcileSetDiffs(diffs, addAction, hash_) { const hash = hash_ || (x => x); const itemsToDisposables = new Map(); const disposeItem = item => { const disposable = itemsToDisposables.get(hash(item)); - invariant(disposable != null); + + if (!(disposable != null)) { + throw new Error('Invariant violation: "disposable != null"'); + } + disposable.dispose(); itemsToDisposables.delete(item); }; @@ -177,18 +191,15 @@ export function reconcileSetDiffs( itemsToDisposables.clear(); }; - return new UniversalDisposable( - diffs.subscribe(diff => { - // For every item that got added, perform the add action. - diff.added.forEach(item => { - itemsToDisposables.set(hash(item), addAction(item)); - }); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(diffs.subscribe(diff => { + // For every item that got added, perform the add action. + diff.added.forEach(item => { + itemsToDisposables.set(hash(item), addAction(item)); + }); - // "Undo" the add action for each item that got removed. - diff.removed.forEach(disposeItem); - }), - disposeAll, - ); + // "Undo" the add action for each item that got removed. + diff.removed.forEach(disposeItem); + }), disposeAll); } /** @@ -219,88 +230,52 @@ export function reconcileSetDiffs( * of the dogs observable, his notification will remain until `disposable.dispose()` is called, at * which point the cleanup for all remaining items will be performed. */ -export function reconcileSets( - sets: Observable>, - addAction: (addedItem: T) => IDisposable, - hash?: (v: T) => any, -): IDisposable { +function reconcileSets(sets, addAction, hash) { const diffs = sets.let(diffSets(hash)); return reconcileSetDiffs(diffs, addAction, hash); } -export function toggle( - toggler: Observable, -): (Observable) => Observable { - return (source: Observable) => - toggler - .distinctUntilChanged() - .switchMap(enabled => (enabled ? source : Observable.empty())); +function toggle(toggler) { + return source => toggler.distinctUntilChanged().switchMap(enabled => enabled ? source : _rxjsBundlesRxMinJs.Observable.empty()); } -export function compact(source: Observable): Observable { +function compact(source) { // Flow does not understand the semantics of `filter` - return (source.filter(x => x != null): any); + return source.filter(x => x != null); } /** * Like `takeWhile`, but includes the first item that doesn't match the predicate. */ -export function takeWhileInclusive( - predicate: (value: T) => boolean, -): (Observable) => Observable { - return (source: Observable) => - Observable.create(observer => - source.subscribe( - x => { - observer.next(x); - if (!predicate(x)) { - observer.complete(); - } - }, - err => { - observer.error(err); - }, - () => { - observer.complete(); - }, - ), - ); +function takeWhileInclusive(predicate) { + return source => _rxjsBundlesRxMinJs.Observable.create(observer => source.subscribe(x => { + observer.next(x); + if (!predicate(x)) { + observer.complete(); + } + }, err => { + observer.error(err); + }, () => { + observer.complete(); + })); } // Concatenate the latest values from each input observable into one big list. // Observables who have not emitted a value yet are treated as empty. -export function concatLatest( - ...observables: Array>> -): Observable> { +function concatLatest(...observables) { // First, tag all input observables with their index. - // Flow errors with ambiguity without the explicit annotation. - const tagged: Array, number]>> = observables.map( - (observable, index) => observable.map(list => [list, index]), - ); - return Observable.merge(...tagged) - .scan((accumulator, [list, index]) => { - accumulator[index] = list; - return accumulator; - }, observables.map(x => [])) - .map(accumulator => [].concat(...accumulator)); + const tagged = observables.map((observable, index) => observable.map(list => [list, index])); + return _rxjsBundlesRxMinJs.Observable.merge(...tagged).scan((accumulator, [list, index]) => { + accumulator[index] = list; + return accumulator; + }, observables.map(x => [])).map(accumulator => [].concat(...accumulator)); } -type ThrottleOptions = { - // Should the first element be emitted immeditately? Defaults to true. - leading?: boolean, -}; - /** * A more sensible alternative to RxJS's throttle/audit/sample operators. */ -export function throttle( - duration: - | number - | Observable - | ((value: T) => Observable | Promise), - options_: ?ThrottleOptions, -): (Observable) => Observable { - return (source: Observable) => { +function throttle(duration, options_) { + return source => { const options = options_ || {}; const leading = options.leading !== false; let audit; @@ -319,16 +294,10 @@ export function throttle( return audit(source); } - return Observable.create(observer => { + return _rxjsBundlesRxMinJs.Observable.create(observer => { const connectableSource = source.publish(); - const throttled = Observable.merge( - connectableSource.take(1), - audit(connectableSource.skip(1)), - ); - return new UniversalDisposable( - throttled.subscribe(observer), - connectableSource.connect(), - ); + const throttled = _rxjsBundlesRxMinJs.Observable.merge(connectableSource.take(1), audit(connectableSource.skip(1))); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(throttled.subscribe(observer), connectableSource.connect()); }); }; } @@ -346,22 +315,16 @@ export function throttle( * ends up returning an Observable that completes immediately. * With a regular switchMap, this would never terminate. */ -export function completingSwitchMap( - project: (input: T, index: number) => rxjs$ObservableInput, -): (Observable) => Observable { +function completingSwitchMap(project) { // An alternative implementation is to materialize the input observable, // but this avoids the creation of extra notifier objects. const completedSymbol = Symbol('completed'); - return (observable: Observable) => - Observable.concat( - observable, - Observable.of((completedSymbol: any)), - ).switchMap((input, index) => { - if (input === completedSymbol) { - return Observable.empty(); - } - return project(input, index); - }); + return observable => _rxjsBundlesRxMinJs.Observable.concat(observable, _rxjsBundlesRxMinJs.Observable.of(completedSymbol)).switchMap((input, index) => { + if (input === completedSymbol) { + return _rxjsBundlesRxMinJs.Observable.empty(); + } + return project(input, index); + }); } /** @@ -376,29 +339,22 @@ export function completingSwitchMap( * * [1]: https://github.com/ReactiveX/rxjs/blob/master/src/operators/debounceTime.ts#L106 */ -export function fastDebounce( - delay: number, -): (Observable) => Observable { - return (observable: Observable) => - Observable.create(observer => { - const debouncedNext = debounce((x: T) => observer.next(x), delay); - const subscription = observable.subscribe( - debouncedNext, - observer.error.bind(observer), - observer.complete.bind(observer), - ); - return new UniversalDisposable(subscription, debouncedNext); - }); +function fastDebounce(delay) { + return observable => _rxjsBundlesRxMinJs.Observable.create(observer => { + const debouncedNext = (0, (_debounce || _load_debounce()).default)(x => observer.next(x), delay); + const subscription = observable.subscribe(debouncedNext, observer.error.bind(observer), observer.complete.bind(observer)); + return new (_UniversalDisposable || _load_UniversalDisposable()).default(subscription, debouncedNext); + }); } -export const microtask = Observable.create(observer => { +const microtask = exports.microtask = _rxjsBundlesRxMinJs.Observable.create(observer => { process.nextTick(() => { observer.next(); observer.complete(); }); }); -export const macrotask = Observable.create(observer => { +const macrotask = exports.macrotask = _rxjsBundlesRxMinJs.Observable.create(observer => { const timerId = setImmediate(() => { observer.next(); observer.complete(); @@ -408,7 +364,7 @@ export const macrotask = Observable.create(observer => { }; }); -export const nextAnimationFrame = Observable.create(observer => { +const nextAnimationFrame = exports.nextAnimationFrame = _rxjsBundlesRxMinJs.Observable.create(observer => { if (typeof requestAnimationFrame === 'undefined') { throw new Error('This util can only be used in Atom'); } @@ -421,45 +377,35 @@ export const nextAnimationFrame = Observable.create(observer => { }; }); -export type CancelablePromise = { - promise: Promise, - cancel: () => void, -}; - /** * Thrown when a CancelablePromise is canceled(). */ -export class PromiseCanceledError extends Error { +class PromiseCanceledError extends Error { constructor() { super(); this.name = 'PromiseCanceledError'; } } -// Given an observable, convert to a Promise (thereby subscribing to the Observable) +exports.PromiseCanceledError = PromiseCanceledError; // Given an observable, convert to a Promise (thereby subscribing to the Observable) // and return back a cancellation function as well. // If the cancellation function is called before the returned promise resolves, // then unsubscribe from the underlying Promise and have the returned Promise throw. // If the cancellation function is called after the returned promise resolves, // then it does nothing. -export function toCancelablePromise( - observable: Observable, -): CancelablePromise { + +function toCancelablePromise(observable) { // Assign a dummy value to keep flow happy - let cancel: () => void = () => {}; + let cancel = () => {}; - const promise: Promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { // Stolen from Rx.js toPromise.js let value; - const subscription = observable.subscribe( - v => { - value = v; - }, - reject, - () => { - resolve(value); - }, - ); + const subscription = observable.subscribe(v => { + value = v; + }, reject, () => { + resolve(value); + }); // Attempt cancellation of both the subscription and the promise. // Do not let one failure prevent the other from succeeding. @@ -473,44 +419,50 @@ export function toCancelablePromise( }; }); - return {promise, cancel}; + return { promise, cancel }; } // Executes tasks. Ensures that at most one task is running at a time. // This class is handy for expensive tasks like processes, provided // you never want the result of a previous task after a new task has started. -export class SingletonExecutor { - _currentTask: ?CancelablePromise = null; +class SingletonExecutor { + constructor() { + this._currentTask = null; + } // Executes(subscribes to) the task. // Will terminate(unsubscribe) to any previously executing task. // Subsequent executes() will terminate this task if called before // this task completes. - async execute(createTask: Observable): Promise { - // Kill any previously running processes - this.cancel(); - - // Start a new process - const task = toCancelablePromise(createTask); - this._currentTask = task; - - // Wait for the process to complete or be canceled ... - try { - return await task.promise; - } finally { - // ... and always clean up if we haven't been canceled already. - if (task === this._currentTask) { - this._currentTask = null; + execute(createTask) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + // Kill any previously running processes + _this.cancel(); + + // Start a new process + const task = toCancelablePromise(createTask); + _this._currentTask = task; + + // Wait for the process to complete or be canceled ... + try { + return yield task.promise; + } finally { + // ... and always clean up if we haven't been canceled already. + if (task === _this._currentTask) { + _this._currentTask = null; + } } - } + })(); } - isExecuting(): boolean { + isExecuting() { return this._currentTask != null; } // Cancels any currently executing tasks. - cancel(): void { + cancel() { if (this._currentTask != null) { this._currentTask.cancel(); this._currentTask = null; @@ -518,40 +470,37 @@ export class SingletonExecutor { } } -/** - * Repeatedly subscribe to an observable every `delay` milliseconds, waiting for the observable to - * complete each time. This is preferable to, say, `Observable.interval(d).switchMap(() => source)` - * because, in the case that `source` takes longer than `d` milliseconds to produce a value, that - * formulation will never produce a value (while continuing to incur the overhead of subscribing to - * source). - * - * Example: - * - * // Ask what time it is every second until it's Friday. - * runCommand('date') - * .let(poll(1000)) - * .filter(output => output.startsWith('Fri')) - * .take(1) - * .subscribe(() => { - * console.log("IT'S FRIDAY!!") - * }); - * - */ -export function poll(delay: number): (Observable) => Observable { - return (source: Observable) => - Observable.defer(() => { - const delays = new Subject(); - return delays - .switchMap(n => Observable.timer(n)) - .merge(Observable.of(null)) - .switchMap(() => { - const subscribedAt = Date.now(); - return source.do({ - complete: () => { - const timeElapsed = Date.now() - subscribedAt; - delays.next(Math.max(0, delay - timeElapsed)); - }, - }); - }); +exports.SingletonExecutor = SingletonExecutor; /** + * Repeatedly subscribe to an observable every `delay` milliseconds, waiting for the observable to + * complete each time. This is preferable to, say, `Observable.interval(d).switchMap(() => source)` + * because, in the case that `source` takes longer than `d` milliseconds to produce a value, that + * formulation will never produce a value (while continuing to incur the overhead of subscribing to + * source). + * + * Example: + * + * // Ask what time it is every second until it's Friday. + * runCommand('date') + * .let(poll(1000)) + * .filter(output => output.startsWith('Fri')) + * .take(1) + * .subscribe(() => { + * console.log("IT'S FRIDAY!!") + * }); + * + */ + +function poll(delay) { + return source => _rxjsBundlesRxMinJs.Observable.defer(() => { + const delays = new _rxjsBundlesRxMinJs.Subject(); + return delays.switchMap(n => _rxjsBundlesRxMinJs.Observable.timer(n)).merge(_rxjsBundlesRxMinJs.Observable.of(null)).switchMap(() => { + const subscribedAt = Date.now(); + return source.do({ + complete: () => { + const timeElapsed = Date.now() - subscribedAt; + delays.next(Math.max(0, delay - timeElapsed)); + } + }); }); -} + }); +} \ No newline at end of file diff --git a/modules/nuclide-commons/package.js b/modules/nuclide-commons/package.js index 8928ceab..c4939202 100644 --- a/modules/nuclide-commons/package.js +++ b/modules/nuclide-commons/package.js @@ -1,29 +1,40 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import fs from 'fs'; -import invariant from 'assert'; +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getPackageMinorVersion = getPackageMinorVersion; + +var _fs = _interopRequireDefault(require('fs')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // Use a regex and not the "semver" module so the result here is the same // as from python code. -const SEMVERISH_RE = /^(\d+)\.(\d+)\.(\d+)(?:-([a-z0-9.-]+))?$/; +const SEMVERISH_RE = /^(\d+)\.(\d+)\.(\d+)(?:-([a-z0-9.-]+))?$/; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ -export function getPackageMinorVersion(packageJsonPath: string): string { - const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); +function getPackageMinorVersion(packageJsonPath) { + const pkgJson = JSON.parse(_fs.default.readFileSync(packageJsonPath, 'utf8')); const match = SEMVERISH_RE.exec(pkgJson.version); - invariant(match); + + if (!match) { + throw new Error('Invariant violation: "match"'); + } // const majorVersion = match[1]; + + const minorVersion = match[2]; // const patchVersion = match[3]; // const prereleaseVersion = match[4]; return minorVersion; -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/performanceNow.js b/modules/nuclide-commons/performanceNow.js index 12914cb0..4ba73296 100644 --- a/modules/nuclide-commons/performanceNow.js +++ b/modules/nuclide-commons/performanceNow.js @@ -1,3 +1,8 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +11,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -22,9 +27,7 @@ * const timeItTookInMilliseconds = performanceNow() - now; */ -export default (typeof performance !== 'undefined' - ? (): number => performance.now() - : (): number => { - const [seconds, nanoseconds] = process.hrtime(); - return seconds * 1000 + nanoseconds / 1000000; - }); +exports.default = typeof performance !== 'undefined' ? () => performance.now() : () => { + const [seconds, nanoseconds] = process.hrtime(); + return seconds * 1000 + nanoseconds / 1000000; +}; \ No newline at end of file diff --git a/modules/nuclide-commons/process.js b/modules/nuclide-commons/process.js index d00f78fa..f8291376 100644 --- a/modules/nuclide-commons/process.js +++ b/modules/nuclide-commons/process.js @@ -1,15 +1,285 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.killUnixProcessTree = exports.loggedCalls = exports.ProcessLoggingEvent = exports.ProcessTimeoutError = exports.MaxBufferExceededError = exports.ProcessSystemError = exports.ProcessExitError = exports.memoryUsagePerPid = exports.psTree = exports.getChildrenOfProcess = exports.getOriginalEnvironment = exports.LOG_CATEGORY = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +let getOriginalEnvironment = exports.getOriginalEnvironment = (() => { + var _ref6 = (0, _asyncToGenerator.default)(function* () { + yield new Promise(function (resolve) { + whenShellEnvironmentLoaded(resolve); + }); + if (cachedOriginalEnvironment != null) { + return cachedOriginalEnvironment; + } + + const { NUCLIDE_ORIGINAL_ENV } = process.env; + if (NUCLIDE_ORIGINAL_ENV != null && NUCLIDE_ORIGINAL_ENV.trim() !== '') { + const envString = new Buffer(NUCLIDE_ORIGINAL_ENV, 'base64').toString(); + cachedOriginalEnvironment = {}; + for (const envVar of envString.split('\0')) { + // envVar should look like A=value_of_A + const equalIndex = envVar.indexOf('='); + if (equalIndex !== -1) { + cachedOriginalEnvironment[envVar.substring(0, equalIndex)] = envVar.substring(equalIndex + 1); + } + } + // Guard against invalid original environments. + if (!Object.keys(cachedOriginalEnvironment).length) { + cachedOriginalEnvironment = process.env; + } + } else { + cachedOriginalEnvironment = process.env; + } + return cachedOriginalEnvironment; + }); + + return function getOriginalEnvironment() { + return _ref6.apply(this, arguments); + }; +})(); + /** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format + * Returns a string suitable for including in displayed error messages. + */ + + +let getChildrenOfProcess = exports.getChildrenOfProcess = (() => { + var _ref7 = (0, _asyncToGenerator.default)(function* (processId) { + const processes = yield psTree(); + + return processes.filter(function (processInfo) { + return processInfo.parentPid === processId; + }); + }); + + return function getChildrenOfProcess(_x) { + return _ref7.apply(this, arguments); + }; +})(); + +/** + * Get a list of descendants, sorted by increasing depth (including the one with the provided pid). */ + +let getDescendantsOfProcess = (() => { + var _ref8 = (0, _asyncToGenerator.default)(function* (pid) { + const processes = yield psTree(); + let rootProcessInfo; + const pidToChildren = new (_collection || _load_collection()).MultiMap(); + processes.forEach(function (info) { + if (info.pid === pid) { + rootProcessInfo = info; + } + pidToChildren.add(info.parentPid, info); + }); + const descendants = rootProcessInfo == null ? [] : [rootProcessInfo]; + // Walk through the array, adding the children of the current element to the end. This + // breadth-first traversal means that the elements will be sorted by depth. + for (let i = 0; i < descendants.length; i++) { + const info = descendants[i]; + const children = pidToChildren.get(info.pid); + descendants.push(...Array.from(children)); + } + return descendants; + }); + + return function getDescendantsOfProcess(_x2) { + return _ref8.apply(this, arguments); + }; +})(); + +let psTree = exports.psTree = (() => { + var _ref9 = (0, _asyncToGenerator.default)(function* () { + if (isWindowsPlatform()) { + return psTreeWindows(); + } + const [commands, withArgs] = yield Promise.all([runCommand('ps', ['-A', '-o', 'ppid,pid,comm']).toPromise(), runCommand('ps', ['-A', '-ww', '-o', 'pid,args']).toPromise()]); + + return parsePsOutput(commands, withArgs); + }); + + return function psTree() { + return _ref9.apply(this, arguments); + }; +})(); + +let psTreeWindows = (() => { + var _ref10 = (0, _asyncToGenerator.default)(function* () { + const stdout = yield runCommand('wmic.exe', ['PROCESS', 'GET', 'ParentProcessId,ProcessId,Name']).toPromise(); + return parsePsOutput(stdout); + }); + + return function psTreeWindows() { + return _ref10.apply(this, arguments); + }; +})(); + +// Use `ps` to get memory usage for an array of process id's as a map. +let memoryUsagePerPid = exports.memoryUsagePerPid = (() => { + var _ref11 = (0, _asyncToGenerator.default)(function* (pids) { + const usage = new Map(); + if (pids.length >= 1) { + try { + const stdout = yield runCommand('ps', ['-p', pids.join(','), '-o', 'pid=', '-o', 'rss=']).toPromise(); + stdout.split('\n').forEach(function (line) { + const parts = line.trim().split(/\s+/); + if (parts.length === 2) { + const [pid, rss] = parts.map(function (x) { + return parseInt(x, 10); + }); + usage.set(pid, rss); + } + }); + } catch (err) { + // Ignore errors. + } + } + return usage; + }); + + return function memoryUsagePerPid(_x3) { + return _ref11.apply(this, arguments); + }; +})(); + +/** + * Add no-op error handlers to the process's streams so that Node doesn't throw them. + */ + + +let _killProcess = (() => { + var _ref12 = (0, _asyncToGenerator.default)(function* (proc, killTree) { + proc.wasKilled = true; + if (!killTree) { + proc.kill(); + return; + } + if (/^win/.test(process.platform)) { + yield killWindowsProcessTree(proc.pid); + } else { + yield killUnixProcessTree(proc); + } + }); + + return function _killProcess(_x4, _x5) { + return _ref12.apply(this, arguments); + }; +})(); + +let killUnixProcessTree = exports.killUnixProcessTree = (() => { + var _ref13 = (0, _asyncToGenerator.default)(function* (proc) { + const descendants = yield getDescendantsOfProcess(proc.pid); + // Kill the processes, starting with those of greatest depth. + for (const info of descendants.reverse()) { + killPid(info.pid); + } + }); + + return function killUnixProcessTree(_x6) { + return _ref13.apply(this, arguments); + }; +})(); + +exports.runCommand = runCommand; +exports.observeProcess = observeProcess; +exports.runCommandDetailed = runCommandDetailed; +exports.observeProcessRaw = observeProcessRaw; +exports.spawn = spawn; +exports.fork = fork; +exports.getOutputStream = getOutputStream; +exports.scriptifyCommand = scriptifyCommand; +exports.killProcess = killProcess; +exports.killPid = killPid; +exports.exitEventToMessage = exitEventToMessage; +exports.parsePsOutput = parsePsOutput; +exports.preventStreamsFromThrowing = preventStreamsFromThrowing; +exports.logStreamErrors = logStreamErrors; + +var _child_process = _interopRequireDefault(require('child_process')); + +var _idx; + +function _load_idx() { + return _idx = _interopRequireDefault(require('idx')); +} + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _util = _interopRequireDefault(require('util')); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('./UniversalDisposable')); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('./nuclideUri')); +} + +var _performanceNow; + +function _load_performanceNow() { + return _performanceNow = _interopRequireDefault(require('./performanceNow')); +} + +var _collection; + +function _load_collection() { + return _collection = require('./collection'); +} + +var _event; + +function _load_event() { + return _event = require('./event'); +} + +var _stream; + +function _load_stream() { + return _stream = require('./stream'); +} + +var _observable; + +function _load_observable() { + return _observable = require('./observable'); +} + +var _string; + +function _load_string() { + return _string = require('./string'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const LOG_CATEGORY = exports.LOG_CATEGORY = 'nuclide-commons/process'; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + // // __ __ __ __ ___ __ __ __ // |__) |__) / \ / ` |__ /__` /__` | /__` @@ -48,25 +318,7 @@ // // [RxJS]: http://reactivex.io/rxjs/ -import child_process from 'child_process'; -import idx from 'idx'; -import {getLogger} from 'log4js'; -import invariant from 'assert'; -import {Observable} from 'rxjs'; -import util from 'util'; - -import UniversalDisposable from './UniversalDisposable'; -import nuclideUri from './nuclideUri'; -import performanceNow from './performanceNow'; -import {MultiMap} from './collection'; -import {observableFromSubscribeFunction} from './event'; -import {observeStream} from './stream'; -import {splitStream, takeWhileInclusive} from './observable'; -import {shellQuote} from './string'; - -export const LOG_CATEGORY = 'nuclide-commons/process'; - -const logger = getLogger(LOG_CATEGORY); +const logger = (0, (_log4js || _load_log4js()).getLogger)(LOG_CATEGORY); /** * Run a command, accumulate the output. Errors are surfaced as stream errors and unsubscribing will @@ -121,12 +373,7 @@ const logger = getLogger(LOG_CATEGORY); * [1]: https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options * [2]: https://nodejs.org/api/errors.html#errors_class_system_error */ -export function runCommand( - command: string, - args?: Array = [], - options?: ObserveProcessOptions = {}, - rest: void, -): Observable { +function runCommand(command, args = [], options = {}, rest) { return runCommandDetailed(command, args, options).map(event => event.stdout); } @@ -156,22 +403,10 @@ export function runCommand( * }); * ``` */ -export function observeProcess( - command: string, - args?: Array, - options?: ObserveProcessOptions, -): Observable { - return spawn(command, args, options).flatMap(proc => - getOutputStream(proc, options), - ); +function observeProcess(command, args, options) { + return spawn(command, args, options).flatMap(proc => getOutputStream(proc, options)); } -export type DetailedProcessResult = { - stdout: string, - stderr: string, - exitCode: ?number, -}; - /** * Identical to `runCommand()`, but instead of only emitting the accumulated stdout, the returned * observable emits an object containing the accumulated stdout, the accumulated stderr, and the @@ -180,59 +415,39 @@ export type DetailedProcessResult = { * In general, you should prefer `runCommand()`, however, this function is useful for when stderr is * needed even if the process exits successfully. */ -export function runCommandDetailed( - command: string, - args?: Array = [], - options?: ObserveProcessOptions = {}, - rest: void, -): Observable { - const maxBuffer = idx(options, _ => _.maxBuffer) || DEFAULT_MAX_BUFFER; - return observeProcess(command, args, {...options, maxBuffer}) - .catch(error => { - // Catch ProcessExitErrors so that we can add stdout to them. - if (error instanceof ProcessExitError) { - return Observable.of({kind: 'process-exit-error', error}); - } - throw error; - }) - .reduce( - (acc, event) => { - switch (event.kind) { - case 'stdout': - return {...acc, stdout: acc.stdout + event.data}; - case 'stderr': - return {...acc, stderr: acc.stderr + event.data}; - case 'exit': - return {...acc, exitCode: event.exitCode}; - case 'process-exit-error': - const {error} = event; - throw new ProcessExitError( - error.exitCode, - error.signal, - error.process, - acc.stderr, - acc.stdout, - ); - default: - (event.kind: empty); - throw new Error(`Invalid event kind: ${event.kind}`); - } - }, - {stdout: '', stderr: '', exitCode: null}, - ); +function runCommandDetailed(command, args = [], options = {}, rest) { + var _ref; + + const maxBuffer = ((_ref = options) != null ? _ref.maxBuffer : _ref) || DEFAULT_MAX_BUFFER; + return observeProcess(command, args, Object.assign({}, options, { maxBuffer })).catch(error => { + // Catch ProcessExitErrors so that we can add stdout to them. + if (error instanceof ProcessExitError) { + return _rxjsBundlesRxMinJs.Observable.of({ kind: 'process-exit-error', error }); + } + throw error; + }).reduce((acc, event) => { + switch (event.kind) { + case 'stdout': + return Object.assign({}, acc, { stdout: acc.stdout + event.data }); + case 'stderr': + return Object.assign({}, acc, { stderr: acc.stderr + event.data }); + case 'exit': + return Object.assign({}, acc, { exitCode: event.exitCode }); + case 'process-exit-error': + const { error } = event; + throw new ProcessExitError(error.exitCode, error.signal, error.process, acc.stderr, acc.stdout); + default: + event.kind; + throw new Error(`Invalid event kind: ${event.kind}`); + } + }, { stdout: '', stderr: '', exitCode: null }); } /** * Identical to `observeProcess()`, but doesn't buffer by line. */ -export function observeProcessRaw( - command: string, - args?: Array, - options?: ObserveProcessOptions, -): Observable { - return spawn(command, args, options).flatMap(proc => - getOutputStream(proc, {...options, splitByLines: false}), - ); +function observeProcessRaw(command, args, options) { + return spawn(command, args, options).flatMap(proc => getOutputStream(proc, Object.assign({}, options, { splitByLines: false }))); } // @@ -268,22 +483,14 @@ export function observeProcessRaw( * }); * ``` */ -export function spawn( - command: string, - args?: Array, - options?: SpawnProcessOptions, -): Observable { +function spawn(command, args, options) { return createProcessStream('spawn', command, args, options); } /** * Identical to `spawn()` (above), but uses `child_process.fork()` to create the process. */ -export function fork( - modulePath: string, - args?: Array, - options?: ForkProcessOptions, -): Observable { +function fork(modulePath, args, options) { return createProcessStream('fork', modulePath, args, options); } @@ -298,76 +505,41 @@ export function fork( * This function intentionally does not close the process when you unsubscribe. It's usually used in * conjunction with `spawn()` which does that already. */ -export function getOutputStream( - proc: child_process$ChildProcess, - options?: GetOutputStreamOptions, - rest: void, -): Observable { - const chunk = - idx(options, _ => _.splitByLines) === false ? x => x : splitStream; - const maxBuffer = idx(options, _ => _.maxBuffer); - const isExitError = idx(options, _ => _.isExitError) || isExitErrorDefault; - const exitErrorBufferSize = idx(options, _ => _.exitErrorBufferSize) || 2000; - return Observable.defer(() => { - const stdoutEvents = chunk( - limitBufferSize(observeStream(proc.stdout), maxBuffer, 'stdout'), - ).map(data => ({kind: 'stdout', data})); - const stderrEvents = chunk( - limitBufferSize(observeStream(proc.stderr), maxBuffer, 'stderr'), - ) - .map(data => ({kind: 'stderr', data})) - .share(); +function getOutputStream(proc, options, rest) { + var _ref2, _ref3, _ref4, _ref5; + + const chunk = ((_ref2 = options) != null ? _ref2.splitByLines : _ref2) === false ? x => x : (_observable || _load_observable()).splitStream; + const maxBuffer = (_ref3 = options) != null ? _ref3.maxBuffer : _ref3; + const isExitError = ((_ref4 = options) != null ? _ref4.isExitError : _ref4) || isExitErrorDefault; + const exitErrorBufferSize = ((_ref5 = options) != null ? _ref5.exitErrorBufferSize : _ref5) || 2000; + return _rxjsBundlesRxMinJs.Observable.defer(() => { + const stdoutEvents = chunk(limitBufferSize((0, (_stream || _load_stream()).observeStream)(proc.stdout), maxBuffer, 'stdout')).map(data => ({ kind: 'stdout', data })); + const stderrEvents = chunk(limitBufferSize((0, (_stream || _load_stream()).observeStream)(proc.stderr), maxBuffer, 'stderr')).map(data => ({ kind: 'stderr', data })).share(); // Accumulate the first `exitErrorBufferSize` bytes of stderr so that we can give feedback about // about exit errors (then stop so we don't fill up memory with it). - const accumulatedStderr = stderrEvents - .scan( - (acc, event) => (acc + event.data).slice(0, exitErrorBufferSize), - '', - ) - .startWith('') - .let(takeWhileInclusive(acc => acc.length < exitErrorBufferSize)); + const accumulatedStderr = stderrEvents.scan((acc, event) => (acc + event.data).slice(0, exitErrorBufferSize), '').startWith('').let((0, (_observable || _load_observable()).takeWhileInclusive)(acc => acc.length < exitErrorBufferSize)); // We need to start listening for the exit event immediately, but defer emitting it until the // (buffered) output streams end. - const closeEvents = Observable.fromEvent( - proc, - // We listen to the "close" event instead of "exit" because we want to get all of the stdout - // and stderr. - 'close', - (exitCode: ?number, signal: ?string) => ({ - kind: 'exit', - exitCode, - signal, - }), - ) - .filter(isRealExit) - .take(1) - .withLatestFrom(accumulatedStderr) - .map(([event, stderr]) => { - if (isExitError(event)) { - throw new ProcessExitError( - event.exitCode, - event.signal, - proc, - stderr, - ); - } - return event; - }) - .publishReplay(); + const closeEvents = _rxjsBundlesRxMinJs.Observable.fromEvent(proc, + // We listen to the "close" event instead of "exit" because we want to get all of the stdout + // and stderr. + 'close', (exitCode, signal) => ({ + kind: 'exit', + exitCode, + signal + })).filter(isRealExit).take(1).withLatestFrom(accumulatedStderr).map(([event, stderr]) => { + if (isExitError(event)) { + throw new ProcessExitError(event.exitCode, event.signal, proc, stderr); + } + return event; + }).publishReplay(); const exitSub = closeEvents.connect(); - return Observable.merge(stdoutEvents, stderrEvents) - .concat(closeEvents) - .let( - takeWhileInclusive( - event => event.kind !== 'error' && event.kind !== 'exit', - ), - ) - .finally(() => { - exitSub.unsubscribe(); - }); + return _rxjsBundlesRxMinJs.Observable.merge(stdoutEvents, stderrEvents).concat(closeEvents).let((0, (_observable || _load_observable()).takeWhileInclusive)(event => event.kind !== 'error' && event.kind !== 'exit')).finally(() => { + exitSub.unsubscribe(); + }); }); } @@ -390,51 +562,38 @@ export function getOutputStream( * * See also `nicifyCommand()` which does a similar thing but for `nice`. */ -export function scriptifyCommand( - command: string, - args?: Array = [], - options: T, -): [string, Array, T] { +function scriptifyCommand(command, args = [], options) { if (process.platform === 'darwin') { // On OS X, script takes the program to run and its arguments as varargs at the end. return ['script', ['-q', '/dev/null', command].concat(args), options]; } else { // On Linux, script takes the command to run as the -c parameter so we have to combine all of // the arguments into a single string. - const joined = shellQuote([command, ...args]); + const joined = (0, (_string || _load_string()).shellQuote)([command, ...args]); // flowlint-next-line sketchy-null-mixed:off const opts = options || {}; // flowlint-next-line sketchy-null-mixed:off const env = opts.env || {}; - return [ - 'script', - ['-q', '/dev/null', '-c', joined], - // `script` will use `SHELL`, but shells have different behaviors with regard to escaping. To - // make sure that out escaping is correct, we need to force a particular shell. - {...opts, env: {...env, SHELL: '/bin/bash'}}, - ]; + return ['script', ['-q', '/dev/null', '-c', joined], + // `script` will use `SHELL`, but shells have different behaviors with regard to escaping. To + // make sure that out escaping is correct, we need to force a particular shell. + Object.assign({}, opts, { env: Object.assign({}, env, { SHELL: '/bin/bash' }) })]; } } /** * Kills a process and, optionally, its descendants. */ -export function killProcess( - proc: child_process$ChildProcess, - killTree: boolean, -): void { - _killProcess(proc, killTree).then( - () => {}, - error => { - logger.error(`Killing process ${proc.pid} failed`, error); - }, - ); +function killProcess(proc, killTree) { + _killProcess(proc, killTree).then(() => {}, error => { + logger.error(`Killing process ${proc.pid} failed`, error); + }); } /** * Kill the process with the provided pid. */ -export function killPid(pid: number): void { +function killPid(pid) { try { process.kill(pid); } catch (err) { @@ -447,131 +606,30 @@ export function killPid(pid: number): void { // If provided, read the original environment from NUCLIDE_ORIGINAL_ENV. // This should contain the base64-encoded output of `env -0`. let cachedOriginalEnvironment = null; -export async function getOriginalEnvironment(): Promise { - await new Promise(resolve => { - whenShellEnvironmentLoaded(resolve); - }); - if (cachedOriginalEnvironment != null) { - return cachedOriginalEnvironment; - } - - const {NUCLIDE_ORIGINAL_ENV} = process.env; - if (NUCLIDE_ORIGINAL_ENV != null && NUCLIDE_ORIGINAL_ENV.trim() !== '') { - const envString = new Buffer(NUCLIDE_ORIGINAL_ENV, 'base64').toString(); - cachedOriginalEnvironment = {}; - for (const envVar of envString.split('\0')) { - // envVar should look like A=value_of_A - const equalIndex = envVar.indexOf('='); - if (equalIndex !== -1) { - cachedOriginalEnvironment[ - envVar.substring(0, equalIndex) - ] = envVar.substring(equalIndex + 1); - } - } - // Guard against invalid original environments. - if (!Object.keys(cachedOriginalEnvironment).length) { - cachedOriginalEnvironment = process.env; - } - } else { - cachedOriginalEnvironment = process.env; - } - return cachedOriginalEnvironment; -} - -/** - * Returns a string suitable for including in displayed error messages. - */ -export function exitEventToMessage(event: { - exitCode: ?number, - signal: ?string, -}): string { +function exitEventToMessage(event) { if (event.exitCode != null) { return `exit code ${event.exitCode}`; } else { - invariant(event.signal != null); - return `signal ${event.signal}`; - } -} - -export async function getChildrenOfProcess( - processId: number, -): Promise> { - const processes = await psTree(); - - return processes.filter(processInfo => processInfo.parentPid === processId); -} - -/** - * Get a list of descendants, sorted by increasing depth (including the one with the provided pid). - */ -async function getDescendantsOfProcess( - pid: number, -): Promise> { - const processes = await psTree(); - let rootProcessInfo; - const pidToChildren = new MultiMap(); - processes.forEach(info => { - if (info.pid === pid) { - rootProcessInfo = info; + if (!(event.signal != null)) { + throw new Error('Invariant violation: "event.signal != null"'); } - pidToChildren.add(info.parentPid, info); - }); - const descendants = rootProcessInfo == null ? [] : [rootProcessInfo]; - // Walk through the array, adding the children of the current element to the end. This - // breadth-first traversal means that the elements will be sorted by depth. - for (let i = 0; i < descendants.length; i++) { - const info = descendants[i]; - const children = pidToChildren.get(info.pid); - descendants.push(...Array.from(children)); - } - return descendants; -} -export async function psTree(): Promise> { - if (isWindowsPlatform()) { - return psTreeWindows(); + return `signal ${event.signal}`; } - const [commands, withArgs] = await Promise.all([ - runCommand('ps', ['-A', '-o', 'ppid,pid,comm']).toPromise(), - runCommand('ps', ['-A', '-ww', '-o', 'pid,args']).toPromise(), - ]); - - return parsePsOutput(commands, withArgs); -} - -async function psTreeWindows(): Promise> { - const stdout = await runCommand('wmic.exe', [ - 'PROCESS', - 'GET', - 'ParentProcessId,ProcessId,Name', - ]).toPromise(); - return parsePsOutput(stdout); } -export function parsePsOutput( - psOutput: string, - argsOutput: ?string, -): Array { +function parsePsOutput(psOutput, argsOutput) { // Remove the first header line. - const lines = psOutput - .trim() - .split(/\n|\r\n/) - .slice(1); + const lines = psOutput.trim().split(/\n|\r\n/).slice(1); let withArgs = new Map(); if (argsOutput != null) { - withArgs = new Map( - argsOutput - .trim() - .split(/\n|\r\n/) - .slice(1) - .map(line => { - const columns = line.trim().split(/\s+/); - const pid = parseInt(columns[0], 10); - const command = columns.slice(1).join(' '); - return [pid, command]; - }), - ); + withArgs = new Map(argsOutput.trim().split(/\n|\r\n/).slice(1).map(line => { + const columns = line.trim().split(/\s+/); + const pid = parseInt(columns[0], 10); + const command = columns.slice(1).join(' '); + return [pid, command]; + })); } return lines.map(line => { @@ -585,73 +643,21 @@ export function parsePsOutput( command, parentPid: parseInt(parentPid, 10), pid, - commandWithArgs: commandWithArgs == null ? command : commandWithArgs, + commandWithArgs: commandWithArgs == null ? command : commandWithArgs }; }); -} - -// Use `ps` to get memory usage for an array of process id's as a map. -export async function memoryUsagePerPid( - pids: Array, -): Promise> { - const usage = new Map(); - if (pids.length >= 1) { - try { - const stdout = await runCommand('ps', [ - '-p', - pids.join(','), - '-o', - 'pid=', - '-o', - 'rss=', - ]).toPromise(); - stdout.split('\n').forEach(line => { - const parts = line.trim().split(/\s+/); - if (parts.length === 2) { - const [pid, rss] = parts.map(x => parseInt(x, 10)); - usage.set(pid, rss); - } - }); - } catch (err) { - // Ignore errors. - } - } - return usage; -} - -/** - * Add no-op error handlers to the process's streams so that Node doesn't throw them. - */ -export function preventStreamsFromThrowing( - proc: child_process$ChildProcess, -): IDisposable { - return new UniversalDisposable(getStreamErrorEvents(proc).subscribe()); +}function preventStreamsFromThrowing(proc) { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(getStreamErrorEvents(proc).subscribe()); } /** * Log errors from a process's streams. This function returns an `rxjs$ISubscription` so that it * can easily be used with `Observable.using()`. */ -export function logStreamErrors( - proc: child_process$ChildProcess, - command: string, - args: Array, - options?: Object, -): IDisposable & rxjs$ISubscription { - return new UniversalDisposable( - getStreamErrorEvents(proc) - .do(([err, streamName]) => { - logger.error( - `stream error on stream ${streamName} with command:`, - command, - args, - options, - 'error:', - err, - ); - }) - .subscribe(), - ); +function logStreamErrors(proc, command, args, options) { + return new (_UniversalDisposable || _load_UniversalDisposable()).default(getStreamErrorEvents(proc).do(([err, streamName]) => { + logger.error(`stream error on stream ${streamName} with command:`, command, args, options, 'error:', err); + }).subscribe()); } // @@ -660,90 +666,11 @@ export function logStreamErrors( // Exactly one of exitCode and signal will be non-null. // Killing a process will result in a null exitCode but a non-null signal. -export type ProcessExitMessage = { - kind: 'exit', - exitCode: ?number, - signal: ?string, -}; -export type ProcessMessage = - | { - kind: 'stdout', - data: string, - } - | { - kind: 'stderr', - data: string, - } - | ProcessExitMessage; // In older versions of process.js, errors were emitted as messages instead of errors. This type // exists to support the transition, but no new usages should be added. -export type LegacyProcessMessage = - | ProcessMessage - | {kind: 'error', error: Object}; - -export type ProcessInfo = { - parentPid: number, - pid: number, - command: string, - commandWithArgs: string, -}; - -export type Level = 'info' | 'log' | 'warning' | 'error' | 'debug' | 'success'; -export type Message = {text: string, level: Level}; -export type MessageEvent = { - type: 'message', - message: Message, -}; - -export type ProgressEvent = { - type: 'progress', - progress: ?number, -}; - -export type ResultEvent = { - type: 'result', - result: mixed, -}; - -export type StatusEvent = { - type: 'status', - status: ?string, -}; - -export type TaskEvent = - | MessageEvent - | ProgressEvent - | ResultEvent - | StatusEvent; - -type CreateProcessStreamOptions = ( - | child_process$spawnOpts - | child_process$forkOpts) & { - killTreeWhenDone?: ?boolean, - timeout?: ?number, - input?: ?(string | Observable), - dontLogInNuclide?: ?boolean, -}; - -type GetOutputStreamOptions = { - splitByLines?: ?boolean, - maxBuffer?: ?number, - exitErrorBufferSize?: ?number, - isExitError?: ?(event: ProcessExitMessage) => boolean, -}; - -export type ObserveProcessOptions = SpawnProcessOptions & - GetOutputStreamOptions; - -export type SpawnProcessOptions = child_process$spawnOpts & - CreateProcessStreamOptions; -export type ForkProcessOptions = child_process$forkOpts & - CreateProcessStreamOptions; - -export type ProcessError = ProcessSystemError | ProcessExitError; // // Errors @@ -758,33 +685,17 @@ export type ProcessError = ProcessSystemError | ProcessExitError; * `observeProcess()`, it will be truncated. Similarly, `stdout` will only be populated when the * error is thrown by output-accumulating functions. For others, it will always be `null`. */ -export class ProcessExitError extends Error { - exitCode: ?number; - signal: ?string; - stderr: string; - stdout: ?string; - command: string; - args: Array; - process: child_process$ChildProcess; - - constructor( - exitCode: ?number, - signal: ?string, - proc: child_process$ChildProcess, - stderr: string, - stdout?: string, - ) { +class ProcessExitError extends Error { + + constructor(exitCode, signal, proc, stderr, stdout) { // $FlowIssue: This isn't typed in the Flow node type defs - const {spawnargs} = proc; - const argsAndCommand = - spawnargs[0] === process.execPath ? spawnargs.slice(1) : spawnargs; + const { spawnargs } = proc; + const argsAndCommand = spawnargs[0] === process.execPath ? spawnargs.slice(1) : spawnargs; const [command, ...args] = argsAndCommand; - super( - `"${command}" failed with ${exitEventToMessage({ - exitCode, - signal, - })}\n\n${stderr}\n\n${argsAndCommand.join(' ')}`, - ); + super(`"${command}" failed with ${exitEventToMessage({ + exitCode, + signal + })}\n\n${stderr}\n\n${argsAndCommand.join(' ')}`); this.name = 'ProcessExitError'; this.exitCode = exitCode; this.signal = signal; @@ -796,18 +707,14 @@ export class ProcessExitError extends Error { } } -/** - * Process system errors are just augmented Error objects. We wrap the errors and expose the process - * since our utilities throw the errors before returning the process. - */ -export class ProcessSystemError extends Error { - errno: number | string; - code: string; - path: ?string; - syscall: ?string; - process: child_process$ChildProcess; - - constructor(err: any, proc: child_process$ChildProcess) { +exports.ProcessExitError = ProcessExitError; /** + * Process system errors are just augmented Error objects. We wrap the errors and expose the process + * since our utilities throw the errors before returning the process. + */ + +class ProcessSystemError extends Error { + + constructor(err, proc) { super(err.message); this.name = 'ProcessSystemError'; this.errno = err.errno; @@ -818,81 +725,79 @@ export class ProcessSystemError extends Error { } } -export class MaxBufferExceededError extends Error { - constructor(streamName: string) { +exports.ProcessSystemError = ProcessSystemError; +class MaxBufferExceededError extends Error { + constructor(streamName) { super(`${streamName} maxBuffer exceeded`); this.name = 'MaxBufferExceededError'; } } -export class ProcessTimeoutError extends Error { - constructor(timeout: number, proc: child_process$ChildProcess) { +exports.MaxBufferExceededError = MaxBufferExceededError; +class ProcessTimeoutError extends Error { + constructor(timeout, proc) { // $FlowIssue: This isn't typed in the Flow node type defs - const {spawnargs} = proc; - const commandName = - spawnargs[0] === process.execPath ? spawnargs[1] : spawnargs[0]; + const { spawnargs } = proc; + const commandName = spawnargs[0] === process.execPath ? spawnargs[1] : spawnargs[0]; super(`"${commandName}" timed out after ${timeout}ms`); this.name = 'ProcessTimeoutError'; } } -// +exports.ProcessTimeoutError = ProcessTimeoutError; // // Internal Stuff // // Pay no attention! This is just stuff that's used internally to implement the good stuff. // // Node crashes if we allow buffers that are too large. + const DEFAULT_MAX_BUFFER = 100 * 1024 * 1024; const MAX_LOGGED_CALLS = 100; const NUM_PRESERVED_HISTORY_CALLS = 50; -const noopDisposable = {dispose: () => {}}; -const whenShellEnvironmentLoaded = - typeof atom !== 'undefined' && !atom.inSpecMode() - ? atom.whenShellEnvironmentLoaded.bind(atom) - : cb => { - cb(); - return noopDisposable; - }; +const noopDisposable = { dispose: () => {} }; +const whenShellEnvironmentLoaded = typeof atom !== 'undefined' && !atom.inSpecMode() ? atom.whenShellEnvironmentLoaded.bind(atom) : cb => { + cb(); + return noopDisposable; +}; /** * Log custom events to log4js so that we can easily hook into process events * using a custom log4js appender (e.g. for analytics purposes). */ -export class ProcessLoggingEvent { - command: string; - duration: number; +class ProcessLoggingEvent { - constructor(command: string, duration: number) { + constructor(command, duration) { this.command = command; this.duration = duration; // log4js uses util.inspect to convert log arguments to strings. // Note: computed property methods aren't supported by Flow yet. - (this: any)[util.inspect.custom] = () => { + this[_util.default.inspect.custom] = () => { return `${this.duration}ms: ${this.command}`; }; } } -export const loggedCalls = []; -function logCall(duration: number, command: string, args: Array) { +exports.ProcessLoggingEvent = ProcessLoggingEvent; +const loggedCalls = exports.loggedCalls = []; +function logCall(duration, command, args) { // Trim the history once in a while, to avoid doing expensive array // manipulation all the time after we reached the end of the history if (loggedCalls.length > MAX_LOGGED_CALLS) { loggedCalls.splice(0, loggedCalls.length - NUM_PRESERVED_HISTORY_CALLS, { command: '... history stripped ...', duration: 0, - time: new Date(), + time: new Date() }); } - const fullCommand = shellQuote([command, ...args]); + const fullCommand = (0, (_string || _load_string()).shellQuote)([command, ...args]); loggedCalls.push({ command: fullCommand, duration, - time: new Date(), + time: new Date() }); logger.info(new ProcessLoggingEvent(fullCommand, duration)); } @@ -909,169 +814,103 @@ function logCall(duration: number, command: string, args: Array) { * * IMPORTANT: The exit event does NOT mean that all stdout and stderr events have been received. */ -function createProcessStream( - type: 'spawn' | 'fork' = 'spawn', - commandOrModulePath: string, - args?: Array = [], - options?: CreateProcessStreamOptions = {}, -): Observable { +function createProcessStream(type = 'spawn', commandOrModulePath, args = [], options = {}) { const inputOption = options.input; let input; if (inputOption != null) { - input = - typeof inputOption === 'string' - ? Observable.of(inputOption) - : inputOption; + input = typeof inputOption === 'string' ? _rxjsBundlesRxMinJs.Observable.of(inputOption) : inputOption; } - return observableFromSubscribeFunction(whenShellEnvironmentLoaded) - .take(1) - .switchMap(() => { - const {dontLogInNuclide, killTreeWhenDone, timeout} = options; - // flowlint-next-line sketchy-null-number:off - const enforceTimeout = timeout - ? x => - x.timeoutWith( - timeout, - Observable.throw(new ProcessTimeoutError(timeout, proc)), - ) - : x => x; - const proc = child_process[type]( - nuclideUri.expandHomeDir(commandOrModulePath), - args, - // $FlowFixMe: child_process$spawnOpts and child_process$forkOpts have incompatible stdio types. - {...options}, - ); - - // Don't let Node throw stream errors and crash the process. Note that we never dispose of - // this because stream errors can still occur after the user unsubscribes from our process - // observable. That's okay; when the streams close, the listeners will be removed. - preventStreamsFromThrowing(proc); - - // If we were to connect the error handler as part of the returned observable, unsubscribing - // would cause it to be removed. That would leave no attached error handler, so node would - // throw, triggering Atom's uncaught exception handler. - const errors = Observable.fromEvent(proc, 'error') - .flatMap(Observable.throw) - .publish(); - errors.connect(); - - const exitEvents = Observable.fromEvent( - proc, - 'exit', - (exitCode: ?number, signal: ?string) => ({ - kind: 'exit', - exitCode, - signal, - }), - ) - .filter(isRealExit) - .take(1); - - if (dontLogInNuclide !== true) { - // Log the completion of the process. Note that we intentionally don't merge this with the - // returned observable because we don't want to cancel the side-effect when the user - // unsubscribes or when the process exits ("close" events come after "exit" events). - const now = performanceNow(); - Observable.fromEvent(proc, 'close') - .do(() => { - logCall( - Math.round(performanceNow() - now), - commandOrModulePath, - args, - ); - }) - .subscribe(); - } + return (0, (_event || _load_event()).observableFromSubscribeFunction)(whenShellEnvironmentLoaded).take(1).switchMap(() => { + const { dontLogInNuclide, killTreeWhenDone, timeout } = options; + // flowlint-next-line sketchy-null-number:off + const enforceTimeout = timeout ? x => x.timeoutWith(timeout, _rxjsBundlesRxMinJs.Observable.throw(new ProcessTimeoutError(timeout, proc))) : x => x; + const proc = _child_process.default[type]((_nuclideUri || _load_nuclideUri()).default.expandHomeDir(commandOrModulePath), args, + // $FlowFixMe: child_process$spawnOpts and child_process$forkOpts have incompatible stdio types. + Object.assign({}, options)); + + // Don't let Node throw stream errors and crash the process. Note that we never dispose of + // this because stream errors can still occur after the user unsubscribes from our process + // observable. That's okay; when the streams close, the listeners will be removed. + preventStreamsFromThrowing(proc); + + // If we were to connect the error handler as part of the returned observable, unsubscribing + // would cause it to be removed. That would leave no attached error handler, so node would + // throw, triggering Atom's uncaught exception handler. + const errors = _rxjsBundlesRxMinJs.Observable.fromEvent(proc, 'error').flatMap(_rxjsBundlesRxMinJs.Observable.throw).publish(); + errors.connect(); + + const exitEvents = _rxjsBundlesRxMinJs.Observable.fromEvent(proc, 'exit', (exitCode, signal) => ({ + kind: 'exit', + exitCode, + signal + })).filter(isRealExit).take(1); + + if (dontLogInNuclide !== true) { + // Log the completion of the process. Note that we intentionally don't merge this with the + // returned observable because we don't want to cancel the side-effect when the user + // unsubscribes or when the process exits ("close" events come after "exit" events). + const now = (0, (_performanceNow || _load_performanceNow()).default)(); + _rxjsBundlesRxMinJs.Observable.fromEvent(proc, 'close').do(() => { + logCall(Math.round((0, (_performanceNow || _load_performanceNow()).default)() - now), commandOrModulePath, args); + }).subscribe(); + } - let finished = false; - return enforceTimeout( - Observable.using( - // Log stream errors, but only for as long as you're subscribed to the process observable. - () => logStreamErrors(proc, commandOrModulePath, args, options), - () => - Observable.merge( - // Node [delays the emission of process errors][1] by a tick in order to give - // consumers a chance to subscribe to the error event. This means that our observable - // would normally emit the process and then, a tick later, error. However, it's more - // convenient to never emit the process if there was an error. Although observables - // don't require the error to be delayed at all, the underlying event emitter - // abstraction does, so we'll just roll with that and use `pid == null` as a signal - // that an error is forthcoming. - // - // [1]: https://github.com/nodejs/node/blob/v7.10.0/lib/internal/child_process.js#L301 - proc.pid == null ? Observable.empty() : Observable.of(proc), - Observable.never(), // Don't complete until we say so! - ), - ) - .merge( - // Write any input to stdin. This is just for the side-effect. We merge it here to - // ensure that writing to the stdin stream happens after our event listeners are added. - input == null - ? Observable.empty() - : input - .do({ - next: str => { - proc.stdin.write(str); - }, - complete: () => { - proc.stdin.end(); - }, - }) - .ignoreElements(), - ) - .takeUntil(errors) - .takeUntil(exitEvents) - .do({ - error: () => { - finished = true; - }, - complete: () => { - finished = true; - }, - }), - ) - .catch(err => { - // Since this utility errors *before* emitting the process, add the process to the error - // so that users can get whatever info they need off of it. - if (err instanceof Error && err.name === 'Error' && 'errno' in err) { - throw new ProcessSystemError(err, proc); - } - throw err; - }) - .finally(() => { - // flowlint-next-line sketchy-null-mixed:off - if (!proc.wasKilled && !finished) { - killProcess(proc, Boolean(killTreeWhenDone)); - } - }); + let finished = false; + return enforceTimeout(_rxjsBundlesRxMinJs.Observable.using( + // Log stream errors, but only for as long as you're subscribed to the process observable. + () => logStreamErrors(proc, commandOrModulePath, args, options), () => _rxjsBundlesRxMinJs.Observable.merge( + // Node [delays the emission of process errors][1] by a tick in order to give + // consumers a chance to subscribe to the error event. This means that our observable + // would normally emit the process and then, a tick later, error. However, it's more + // convenient to never emit the process if there was an error. Although observables + // don't require the error to be delayed at all, the underlying event emitter + // abstraction does, so we'll just roll with that and use `pid == null` as a signal + // that an error is forthcoming. + // + // [1]: https://github.com/nodejs/node/blob/v7.10.0/lib/internal/child_process.js#L301 + proc.pid == null ? _rxjsBundlesRxMinJs.Observable.empty() : _rxjsBundlesRxMinJs.Observable.of(proc), _rxjsBundlesRxMinJs.Observable.never() // Don't complete until we say so! + )).merge( + // Write any input to stdin. This is just for the side-effect. We merge it here to + // ensure that writing to the stdin stream happens after our event listeners are added. + input == null ? _rxjsBundlesRxMinJs.Observable.empty() : input.do({ + next: str => { + proc.stdin.write(str); + }, + complete: () => { + proc.stdin.end(); + } + }).ignoreElements()).takeUntil(errors).takeUntil(exitEvents).do({ + error: () => { + finished = true; + }, + complete: () => { + finished = true; + } + })).catch(err => { + // Since this utility errors *before* emitting the process, add the process to the error + // so that users can get whatever info they need off of it. + if (err instanceof Error && err.name === 'Error' && 'errno' in err) { + throw new ProcessSystemError(err, proc); + } + throw err; + }).finally(() => { + // flowlint-next-line sketchy-null-mixed:off + if (!proc.wasKilled && !finished) { + killProcess(proc, Boolean(killTreeWhenDone)); + } }); + }); } -function isRealExit(event: {exitCode: ?number, signal: ?string}): boolean { +function isRealExit(event) { // An exit signal from SIGUSR1 doesn't actually exit the process, so skip that. return event.signal !== 'SIGUSR1'; } -async function _killProcess( - proc: child_process$ChildProcess & {wasKilled?: boolean}, - killTree: boolean, -): Promise { - proc.wasKilled = true; - if (!killTree) { - proc.kill(); - return; - } - if (/^win/.test(process.platform)) { - await killWindowsProcessTree(proc.pid); - } else { - await killUnixProcessTree(proc); - } -} - -function killWindowsProcessTree(pid: number): Promise { +function killWindowsProcessTree(pid) { return new Promise((resolve, reject) => { - child_process.exec(`taskkill /pid ${pid} /T /F`, error => { + _child_process.default.exec(`taskkill /pid ${pid} /T /F`, error => { if (error == null) { reject(error); } else { @@ -1081,33 +920,20 @@ function killWindowsProcessTree(pid: number): Promise { }); } -export async function killUnixProcessTree( - proc: child_process$ChildProcess, -): Promise { - const descendants = await getDescendantsOfProcess(proc.pid); - // Kill the processes, starting with those of greatest depth. - for (const info of descendants.reverse()) { - killPid(info.pid); - } -} - -function isExitErrorDefault(exit: ProcessExitMessage): boolean { +function isExitErrorDefault(exit) { return exit.exitCode !== 0; } -function isWindowsPlatform(): boolean { - return /^win/.test(process.platform); +function isWindowsPlatform() { + return (/^win/.test(process.platform) + ); } -function limitBufferSize( - stream: Observable, - maxBuffer: ?number, - streamName: string, -): Observable { +function limitBufferSize(stream, maxBuffer, streamName) { if (maxBuffer == null) { return stream; } - return Observable.defer(() => { + return _rxjsBundlesRxMinJs.Observable.defer(() => { let totalSize = 0; return stream.do(data => { totalSize += data.length; @@ -1122,20 +948,7 @@ function limitBufferSize( * Get an observable of error events for a process's streams. Note that these are represented as * normal elements, not observable errors. */ -function getStreamErrorEvents( - proc: child_process$ChildProcess, -): Observable<[Error, string]> { - const streams = [ - ['stdin', proc.stdin], - ['stdout', proc.stdout], - ['stderr', proc.stderr], - ]; - return Observable.merge( - ...streams.map( - ([name, stream]) => - stream == null - ? Observable.empty() - : Observable.fromEvent(stream, 'error').map(err => [err, name]), - ), - ); -} +function getStreamErrorEvents(proc) { + const streams = [['stdin', proc.stdin], ['stdout', proc.stdout], ['stderr', proc.stderr]]; + return _rxjsBundlesRxMinJs.Observable.merge(...streams.map(([name, stream]) => stream == null ? _rxjsBundlesRxMinJs.Observable.empty() : _rxjsBundlesRxMinJs.Observable.fromEvent(stream, 'error').map(err => [err, name]))); +} \ No newline at end of file diff --git a/modules/nuclide-commons/promise.js b/modules/nuclide-commons/promise.js index 264e63ce..4c9bd387 100644 --- a/modules/nuclide-commons/promise.js +++ b/modules/nuclide-commons/promise.js @@ -1,25 +1,257 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.PromiseWithState = exports.asyncSome = exports.asyncObjFilter = exports.asyncFilter = exports.Deferred = exports.retryLimit = exports.TimedOutError = exports.triggerAfterWait = exports.RequestSerializer = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + /** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * Executes a provided callback only if a promise takes longer than + * `milliSeconds` milliseconds to resolve. * - * @flow - * @format + * @param `promise` the promise to wait on. + * @param `milliSeconds` max amount of time that `promise` can take to resolve + * before timeoutFn is fired. + * @param `timeoutFn` the function to execute when a promise takes longer than + * `milliSeconds` ms to resolve. + * @param `cleanupFn` the cleanup function to execute after the promise resolves. + */ +let triggerAfterWait = exports.triggerAfterWait = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (promise, milliSeconds, timeoutFn, cleanupFn) { + const timeout = setTimeout(timeoutFn, milliSeconds); + try { + return yield promise; + } finally { + clearTimeout(timeout); + if (cleanupFn) { + cleanupFn(); + } + } + }); + + return function triggerAfterWait(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); + +/** + * Thrown by `timeoutPromise` if the timer fires before the promise resolves/rejects. */ -import invariant from 'assert'; -type RunReturn = - | { - status: 'success', - result: T, +/** + * Call an async function repeatedly with a maximum number of trials limit, + * until a valid result that's defined by a validation function. + * A failed call can result from an async thrown exception, or invalid result. + * + * @param `retryFunction` the async logic that's wanted to be retried. + * @param `validationFunction` the validation function that decides whether a response is valid. + * @param `maximumTries` the number of times the `retryFunction` can fail to get a valid + * response before the `retryLimit` is terminated reporting an error. + * @param `retryIntervalMs` optional, the number of milliseconds to wait between trials, if wanted. + * + * If an exception is encountered on the last trial, the exception is thrown. + * If no valid response is found, an exception is thrown. + */ +let retryLimit = exports.retryLimit = (() => { + var _ref2 = (0, _asyncToGenerator.default)(function* (retryFunction, validationFunction, maximumTries, retryIntervalMs = 0) { + let result = null; + let tries = 0; + let lastError = null; + while (tries === 0 || tries < maximumTries) { + try { + // eslint-disable-next-line no-await-in-loop + result = yield retryFunction(); + lastError = null; + if (validationFunction(result)) { + return result; + } + } catch (error) { + lastError = error; + result = null; + } + + if (++tries < maximumTries && retryIntervalMs !== 0) { + // eslint-disable-next-line no-await-in-loop + yield sleep(retryIntervalMs); + } } - | { - status: 'outdated', - }; + if (lastError != null) { + throw lastError; + } else if (tries === maximumTries) { + throw new Error('No valid response found!'); + } else { + return result; + } + }); + + return function retryLimit(_x5, _x6, _x7) { + return _ref2.apply(this, arguments); + }; +})(); + +/** + * Limits async function execution parallelism to only one at a time. + * Hence, if a call is already running, it will wait for it to finish, + * then start the next async execution, but if called again while not finished, + * it will return the scheduled execution promise. + * + * Sample Usage: + * ``` + * let i = 1; + * const oneExecAtATime = oneParallelAsyncCall(() => { + * return next Promise((resolve, reject) => { + * setTimeout(200, () => resolve(i++)); + * }); + * }); + * + * const result1Promise = oneExecAtATime(); // Start an async, and resolve to 1 in 200 ms. + * const result2Promise = oneExecAtATime(); // Schedule the next async, and resolve to 2 in 400 ms. + * const result3Promise = oneExecAtATime(); // Reuse scheduled promise and resolve to 2 in 400 ms. + * ``` + */ + + +/** + * `filter` Promise utility that allows filtering an array with an async Promise function. + * It's an alternative to `Array.prototype.filter` that accepts an async function. + * You can optionally configure a limit to set the maximum number of async operations at a time. + * + * Previously, with the `Promise.all` primitive, we can't set the parallelism limit and we have to + * `filter`, so, we replace the old `filter` code: + * var existingFilePaths = []; + * await Promise.all(filePaths.map(async (filePath) => { + * if (await fsPromise.exists(filePath)) { + * existingFilePaths.push(filePath); + * } + * })); + * with limit 5 parallel filesystem operations at a time: + * var existingFilePaths = await asyncFilter(filePaths, fsPromise.exists, 5); + * + * @param array the array of items for `filter`ing. + * @param filterFunction the async `filter` function that returns a Promise that resolves to a + * boolean. + * @param limit the configurable number of parallel async operations. + */ +let asyncFilter = exports.asyncFilter = (() => { + var _ref5 = (0, _asyncToGenerator.default)(function* (array, filterFunction, limit) { + const filteredList = []; + // flowlint-next-line sketchy-null-number:off + yield asyncLimit(array, limit || array.length, (() => { + var _ref6 = (0, _asyncToGenerator.default)(function* (item) { + if (yield filterFunction(item)) { + filteredList.push(item); + } + }); + + return function (_x12) { + return _ref6.apply(this, arguments); + }; + })()); + return filteredList; + }); + + return function asyncFilter(_x9, _x10, _x11) { + return _ref5.apply(this, arguments); + }; +})(); + +let asyncObjFilter = exports.asyncObjFilter = (() => { + var _ref7 = (0, _asyncToGenerator.default)(function* (obj, filterFunction, limit) { + const keys = Object.keys(obj); + const filteredObj = {}; + // flowlint-next-line sketchy-null-number:off + yield asyncLimit(keys, limit || keys.length, (() => { + var _ref8 = (0, _asyncToGenerator.default)(function* (key) { + const item = obj[key]; + if (yield filterFunction(item, key)) { + filteredObj[key] = item; + } + }); + + return function (_x16) { + return _ref8.apply(this, arguments); + }; + })()); + return filteredObj; + }); + + return function asyncObjFilter(_x13, _x14, _x15) { + return _ref7.apply(this, arguments); + }; +})(); + +/** + * `some` Promise utility that allows `some` an array with an async Promise some function. + * It's an alternative to `Array.prototype.some` that accepts an async some function. + * You can optionally configure a limit to set the maximum number of async operations at a time. + * + * Previously, with the Promise.all primitive, we can't set the parallelism limit and we have to + * `some`, so, we replace the old `some` code: + * var someFileExist = false; + * await Promise.all(filePaths.map(async (filePath) => { + * if (await fsPromise.exists(filePath)) { + * someFileExist = true; + * } + * })); + * with limit 5 parallel filesystem operations at a time: + * var someFileExist = await asyncSome(filePaths, fsPromise.exists, 5); + * + * @param array the array of items for `some`ing. + * @param someFunction the async `some` function that returns a Promise that resolves to a + * boolean. + * @param limit the configurable number of parallel async operations. + */ + + +let asyncSome = exports.asyncSome = (() => { + var _ref9 = (0, _asyncToGenerator.default)(function* (array, someFunction, limit) { + let resolved = false; + // flowlint-next-line sketchy-null-number:off + yield asyncLimit(array, limit || array.length, (() => { + var _ref10 = (0, _asyncToGenerator.default)(function* (item) { + if (resolved) { + // We don't need to call the someFunction anymore or wait any longer. + return; + } + if (yield someFunction(item)) { + resolved = true; + } + }); + + return function (_x20) { + return _ref10.apply(this, arguments); + }; + })()); + return resolved; + }); + + return function asyncSome(_x17, _x18, _x19) { + return _ref9.apply(this, arguments); + }; +})(); + +/** + * Check if an object is Promise by testing if it has a `then` function property. + */ + + +exports.sleep = sleep; +exports.nextTick = nextTick; +exports.timeoutPromise = timeoutPromise; +exports.createDeadline = createDeadline; +exports.timeoutAfterDeadline = timeoutAfterDeadline; +exports.serializeAsyncCall = serializeAsyncCall; +exports.asyncFind = asyncFind; +exports.denodeify = denodeify; +exports.asyncLimit = asyncLimit; +exports.isPromise = isPromise; +exports.lastly = lastly; +exports.delayTime = delayTime; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Allows a caller to ensure that the results it receives from consecutive @@ -46,11 +278,19 @@ type RunReturn = * receive a 'success' status. If promise1 later resolved, the first callsite * would receive an 'outdated' status. */ -export class RequestSerializer { - _lastDispatchedOp: number; - _lastFinishedOp: number; - _latestPromise: Promise; - _waitResolve: Function; +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +class RequestSerializer { constructor() { this._lastDispatchedOp = 0; @@ -60,113 +300,86 @@ export class RequestSerializer { }); } - async run(promise: Promise): Promise> { - const thisOp = this._lastDispatchedOp + 1; - this._lastDispatchedOp = thisOp; - this._latestPromise = promise; - this._waitResolve(); - const result = await promise; - if (this._lastFinishedOp < thisOp) { - this._lastFinishedOp = thisOp; - return { - status: 'success', - result, - }; - } else { - return { - status: 'outdated', - }; - } + run(promise) { + var _this = this; + + return (0, _asyncToGenerator.default)(function* () { + const thisOp = _this._lastDispatchedOp + 1; + _this._lastDispatchedOp = thisOp; + _this._latestPromise = promise; + _this._waitResolve(); + const result = yield promise; + if (_this._lastFinishedOp < thisOp) { + _this._lastFinishedOp = thisOp; + return { + status: 'success', + result + }; + } else { + return { + status: 'outdated' + }; + } + })(); } /** * Returns a Promise that resolves to the last result of `run`, * as soon as there are no more outstanding `run` calls. */ - async waitForLatestResult(): Promise { - let lastPromise = null; - let result: any = null; - while (lastPromise !== this._latestPromise) { - lastPromise = this._latestPromise; - // Wait for the current last know promise to resolve, or a next run have started. - // eslint-disable-next-line no-await-in-loop - result = await new Promise((resolve, reject) => { - this._waitResolve = resolve; - this._latestPromise.then(resolve); - }); - } - return (result: T); + waitForLatestResult() { + var _this2 = this; + + return (0, _asyncToGenerator.default)(function* () { + let lastPromise = null; + let result = null; + while (lastPromise !== _this2._latestPromise) { + lastPromise = _this2._latestPromise; + // Wait for the current last know promise to resolve, or a next run have started. + // eslint-disable-next-line no-await-in-loop + result = yield new Promise(function (resolve, reject) { + _this2._waitResolve = resolve; + _this2._latestPromise.then(resolve); + }); + } + return result; + })(); } - isRunInProgress(): boolean { + isRunInProgress() { return this._lastDispatchedOp > this._lastFinishedOp; } } -/* - * Returns a promise that will resolve after `milliSeconds` milli seconds. - * this can be used to pause execution asynchronously. - * e.g. await sleep(1000), pauses the async flow execution for 1 second. - */ -export function sleep(milliSeconds: number): Promise { +exports.RequestSerializer = RequestSerializer; /* + * Returns a promise that will resolve after `milliSeconds` milli seconds. + * this can be used to pause execution asynchronously. + * e.g. await sleep(1000), pauses the async flow execution for 1 second. + */ + +function sleep(milliSeconds) { return new Promise(resolve => { setTimeout(resolve, milliSeconds); }); } -export function nextTick(): Promise { +function nextTick() { return new Promise(resolve => { process.nextTick(resolve); }); -} - -/** - * Executes a provided callback only if a promise takes longer than - * `milliSeconds` milliseconds to resolve. - * - * @param `promise` the promise to wait on. - * @param `milliSeconds` max amount of time that `promise` can take to resolve - * before timeoutFn is fired. - * @param `timeoutFn` the function to execute when a promise takes longer than - * `milliSeconds` ms to resolve. - * @param `cleanupFn` the cleanup function to execute after the promise resolves. - */ -export async function triggerAfterWait( - promise: Promise, - milliSeconds: number, - timeoutFn: () => void, - cleanupFn?: () => void, -): Promise { - const timeout = setTimeout(timeoutFn, milliSeconds); - try { - return await promise; - } finally { - clearTimeout(timeout); - if (cleanupFn) { - cleanupFn(); - } - } -} - -/** - * Thrown by `timeoutPromise` if the timer fires before the promise resolves/rejects. - */ -export class TimedOutError extends Error { - timeout: number; - constructor(milliseconds: number) { +}class TimedOutError extends Error { + constructor(milliseconds) { super(`Timed out after ${String(milliseconds)} ms`); this.timeout = milliseconds; } } -/** - * Returns a Promise that resolves to the same value as the given promise, or rejects with - * `TimedOutError` if it takes longer than `milliseconds` milliseconds. - */ -export function timeoutPromise( - promise: Promise, - milliseconds: number, -): Promise { +exports.TimedOutError = TimedOutError; /** + * Returns a Promise that resolves to the same value as the given promise, or rejects with + * `TimedOutError` if it takes longer than `milliseconds` milliseconds. + */ + +function timeoutPromise(promise, milliseconds) { return new Promise((resolve, reject) => { let timeout = setTimeout(() => { timeout = null; @@ -175,19 +388,17 @@ export function timeoutPromise( // We could capture the stack pre-emptively at the start // of this method if we wanted useful ones. }, milliseconds); - promise - .then(value => { - if (timeout != null) { - clearTimeout(timeout); - } - resolve(value); - }) - .catch(value => { - if (timeout != null) { - clearTimeout(timeout); - } - reject(value); - }); + promise.then(value => { + if (timeout != null) { + clearTimeout(timeout); + } + resolve(value); + }).catch(value => { + if (timeout != null) { + clearTimeout(timeout); + } + reject(value); + }); }); } @@ -207,101 +418,19 @@ export function timeoutPromise( // "delay" parameters) and safely remotable (better than "CancellationToken" // parameters) so long as clocks are in sync. In all other respects it's less // versatile than CancellationTokens. -export type DeadlineRequest = number; - -export function createDeadline(delay: number): DeadlineRequest { +function createDeadline(delay) { return Date.now() + delay; } -export function timeoutAfterDeadline( - deadline: DeadlineRequest, - promise: Promise, -): Promise { +function timeoutAfterDeadline(deadline, promise) { const delay = deadline - Date.now(); return timeoutPromise(promise, delay < 0 ? 0 : delay); -} - -/** - * Call an async function repeatedly with a maximum number of trials limit, - * until a valid result that's defined by a validation function. - * A failed call can result from an async thrown exception, or invalid result. - * - * @param `retryFunction` the async logic that's wanted to be retried. - * @param `validationFunction` the validation function that decides whether a response is valid. - * @param `maximumTries` the number of times the `retryFunction` can fail to get a valid - * response before the `retryLimit` is terminated reporting an error. - * @param `retryIntervalMs` optional, the number of milliseconds to wait between trials, if wanted. - * - * If an exception is encountered on the last trial, the exception is thrown. - * If no valid response is found, an exception is thrown. - */ -export async function retryLimit( - retryFunction: () => Promise, - validationFunction: (result: T) => boolean, - maximumTries: number, - retryIntervalMs?: number = 0, -): Promise { - let result = null; - let tries = 0; - let lastError = null; - while (tries === 0 || tries < maximumTries) { - try { - // eslint-disable-next-line no-await-in-loop - result = await retryFunction(); - lastError = null; - if (validationFunction(result)) { - return result; - } - } catch (error) { - lastError = error; - result = null; - } - - if (++tries < maximumTries && retryIntervalMs !== 0) { - // eslint-disable-next-line no-await-in-loop - await sleep(retryIntervalMs); - } - } - if (lastError != null) { - throw lastError; - } else if (tries === maximumTries) { - throw new Error('No valid response found!'); - } else { - return ((result: any): T); - } -} - -/** - * Limits async function execution parallelism to only one at a time. - * Hence, if a call is already running, it will wait for it to finish, - * then start the next async execution, but if called again while not finished, - * it will return the scheduled execution promise. - * - * Sample Usage: - * ``` - * let i = 1; - * const oneExecAtATime = oneParallelAsyncCall(() => { - * return next Promise((resolve, reject) => { - * setTimeout(200, () => resolve(i++)); - * }); - * }); - * - * const result1Promise = oneExecAtATime(); // Start an async, and resolve to 1 in 200 ms. - * const result2Promise = oneExecAtATime(); // Schedule the next async, and resolve to 2 in 400 ms. - * const result3Promise = oneExecAtATime(); // Reuse scheduled promise and resolve to 2 in 400 ms. - * ``` - */ -export function serializeAsyncCall( - asyncFun: () => Promise, -): () => Promise { +}function serializeAsyncCall(asyncFun) { let scheduledCall = null; let pendingCall = null; const startAsyncCall = () => { const resultPromise = asyncFun(); - pendingCall = resultPromise.then( - () => (pendingCall = null), - () => (pendingCall = null), - ); + pendingCall = resultPromise.then(() => pendingCall = null, () => pendingCall = null); return resultPromise; }; const callNext = () => { @@ -310,7 +439,10 @@ export function serializeAsyncCall( }; const scheduleNextCall = () => { if (scheduledCall == null) { - invariant(pendingCall, 'pendingCall must not be null!'); + if (!pendingCall) { + throw new Error('pendingCall must not be null!'); + } + scheduledCall = pendingCall.then(callNext, callNext); } return scheduledCall; @@ -331,10 +463,7 @@ export function serializeAsyncCall( * IMPORTANT: This should almost never be used!! Instead, use the Promise constructor. See * */ -export class Deferred { - promise: Promise; - resolve: (value: T) => void; - reject: (error: Error) => void; +class Deferred { constructor() { this.promise = new Promise((resolve, reject) => { @@ -344,29 +473,26 @@ export class Deferred { } } -/** - * Returns a value derived asynchronously from an element in the items array. - * The test function is applied sequentially to each element in items until - * one returns a Promise that resolves to a non-null value. When this happens, - * the Promise returned by this method will resolve to that non-null value. If - * no such Promise is produced, then the Promise returned by this function - * will resolve to null. - * - * @param items Array of elements that will be passed to test, one at a time. - * @param test Will be called with each item and must return either: - * (1) A "thenable" (i.e, a Promise or promise-like object) that resolves - * to a derived value (that will be returned) or null. - * (2) null. - * In both cases where null is returned, test will be applied to the next - * item in the array. - * @param thisArg Receiver that will be used when test is called. - * @return Promise that resolves to an asynchronously derived value or null. - */ -export function asyncFind( - items_: Array, - test: (t: T) => ?Promise, - thisArg?: mixed, -): Promise { +exports.Deferred = Deferred; /** + * Returns a value derived asynchronously from an element in the items array. + * The test function is applied sequentially to each element in items until + * one returns a Promise that resolves to a non-null value. When this happens, + * the Promise returned by this method will resolve to that non-null value. If + * no such Promise is produced, then the Promise returned by this function + * will resolve to null. + * + * @param items Array of elements that will be passed to test, one at a time. + * @param test Will be called with each item and must return either: + * (1) A "thenable" (i.e, a Promise or promise-like object) that resolves + * to a derived value (that will be returned) or null. + * (2) null. + * In both cases where null is returned, test will be applied to the next + * item in the array. + * @param thisArg Receiver that will be used when test is called. + * @return Promise that resolves to an asynchronously derived value or null. + */ + +function asyncFind(items_, test, thisArg) { let items = items_; return new Promise((resolve, reject) => { // Create a local copy of items to defend against the caller modifying the @@ -374,29 +500,33 @@ export function asyncFind( items = items.slice(); const numItems = items.length; - const next = async function(index) { - if (index === numItems) { - resolve(null); - return; - } + const next = (() => { + var _ref3 = (0, _asyncToGenerator.default)(function* (index) { + if (index === numItems) { + resolve(null); + return; + } - const item = items[index]; - const result = await test.call(thisArg, item); - if (result != null) { - resolve(result); - } else { - next(index + 1); - } - }; + const item = items[index]; + const result = yield test.call(thisArg, item); + if (result != null) { + resolve(result); + } else { + next(index + 1); + } + }); + + return function next(_x8) { + return _ref3.apply(this, arguments); + }; + })(); next(0); }); } -export function denodeify( - f: (...args: Array) => any, -): (...args: Array) => Promise { - return function(...args: Array) { +function denodeify(f) { + return function (...args) { return new Promise((resolve, reject) => { function callback(error, result) { if (error) { @@ -426,162 +556,56 @@ export function denodeify( * @param limit the configurable number of parallel async operations. * @param mappingFunction the async Promise function that could return a useful result. */ -export function asyncLimit( - array: Array, - limit: number, - mappingFunction: (item: T) => Promise, -): Promise> { - const result: Array = new Array(array.length); +function asyncLimit(array, limit, mappingFunction) { + const result = new Array(array.length); let parallelPromises = 0; let index = 0; let parallelLimit = Math.min(limit, array.length) || 1; return new Promise((resolve, reject) => { - const runPromise = async () => { - if (index === array.length) { - if (parallelPromises === 0) { - resolve(result); + const runPromise = (() => { + var _ref4 = (0, _asyncToGenerator.default)(function* () { + if (index === array.length) { + if (parallelPromises === 0) { + resolve(result); + } + return; } - return; - } - ++parallelPromises; - const i = index++; - try { - result[i] = await mappingFunction(array[i]); - } catch (e) { - reject(e); - } - --parallelPromises; - runPromise(); - }; + ++parallelPromises; + const i = index++; + try { + result[i] = yield mappingFunction(array[i]); + } catch (e) { + reject(e); + } + --parallelPromises; + runPromise(); + }); + + return function runPromise() { + return _ref4.apply(this, arguments); + }; + })(); while (parallelLimit--) { runPromise(); } }); -} - -/** - * `filter` Promise utility that allows filtering an array with an async Promise function. - * It's an alternative to `Array.prototype.filter` that accepts an async function. - * You can optionally configure a limit to set the maximum number of async operations at a time. - * - * Previously, with the `Promise.all` primitive, we can't set the parallelism limit and we have to - * `filter`, so, we replace the old `filter` code: - * var existingFilePaths = []; - * await Promise.all(filePaths.map(async (filePath) => { - * if (await fsPromise.exists(filePath)) { - * existingFilePaths.push(filePath); - * } - * })); - * with limit 5 parallel filesystem operations at a time: - * var existingFilePaths = await asyncFilter(filePaths, fsPromise.exists, 5); - * - * @param array the array of items for `filter`ing. - * @param filterFunction the async `filter` function that returns a Promise that resolves to a - * boolean. - * @param limit the configurable number of parallel async operations. - */ -export async function asyncFilter( - array: Array, - filterFunction: (item: T) => Promise, - limit?: number, -): Promise> { - const filteredList = []; - // flowlint-next-line sketchy-null-number:off - await asyncLimit(array, limit || array.length, async (item: T) => { - if (await filterFunction(item)) { - filteredList.push(item); - } - }); - return filteredList; -} - -export async function asyncObjFilter( - obj: {[key: string]: T}, - filterFunction: (item: T, key: string) => Promise, - limit?: number, -): Promise<{[key: string]: T}> { - const keys = Object.keys(obj); - const filteredObj = {}; - // flowlint-next-line sketchy-null-number:off - await asyncLimit(keys, limit || keys.length, async (key: string) => { - const item = obj[key]; - if (await filterFunction(item, key)) { - filteredObj[key] = item; - } - }); - return filteredObj; -} - -/** - * `some` Promise utility that allows `some` an array with an async Promise some function. - * It's an alternative to `Array.prototype.some` that accepts an async some function. - * You can optionally configure a limit to set the maximum number of async operations at a time. - * - * Previously, with the Promise.all primitive, we can't set the parallelism limit and we have to - * `some`, so, we replace the old `some` code: - * var someFileExist = false; - * await Promise.all(filePaths.map(async (filePath) => { - * if (await fsPromise.exists(filePath)) { - * someFileExist = true; - * } - * })); - * with limit 5 parallel filesystem operations at a time: - * var someFileExist = await asyncSome(filePaths, fsPromise.exists, 5); - * - * @param array the array of items for `some`ing. - * @param someFunction the async `some` function that returns a Promise that resolves to a - * boolean. - * @param limit the configurable number of parallel async operations. - */ -export async function asyncSome( - array: Array, - someFunction: (item: T) => Promise, - limit?: number, -): Promise { - let resolved = false; - // flowlint-next-line sketchy-null-number:off - await asyncLimit(array, limit || array.length, async (item: T) => { - if (resolved) { - // We don't need to call the someFunction anymore or wait any longer. - return; - } - if (await someFunction(item)) { - resolved = true; - } - }); - return resolved; -} - -/** - * Check if an object is Promise by testing if it has a `then` function property. - */ -export function isPromise(object: any): boolean { - return ( - Boolean(object) && - typeof object === 'object' && - typeof object.then === 'function' - ); +}function isPromise(object) { + return Boolean(object) && typeof object === 'object' && typeof object.then === 'function'; } /** * We can't name a function 'finally', so use lastly instead. * fn() will be executed (and completed) after the provided promise resolves/rejects. */ -export function lastly( - promise: Promise, - fn: () => Promise | mixed, -): Promise { - return promise.then( - ret => { - return Promise.resolve(fn()).then(() => ret); - }, - err => { - return Promise.resolve(fn()).then(() => Promise.reject(err)); - }, - ); +function lastly(promise, fn) { + return promise.then(ret => { + return Promise.resolve(fn()).then(() => ret); + }, err => { + return Promise.resolve(fn()).then(() => Promise.reject(err)); + }); } /** @@ -589,40 +613,31 @@ export function lastly( * whether or not it has 'settled' (i.e. been fulfilled or rejected). * Here we provide a wrapper that provides that information. */ -export type PromiseState = - | {kind: 'pending'} - | {kind: 'fulfilled', value: T} - | {kind: 'rejected', error: any}; - -export class PromiseWithState { - _promise: Promise; - _state: PromiseState; - - constructor(promise: Promise) { - this._state = {kind: 'pending'}; - this._promise = promise.then( - value => { - this._state = {kind: 'fulfilled', value}; - return value; - }, - error => { - this._state = {kind: 'rejected', error}; - throw error; - }, - ); +class PromiseWithState { + + constructor(promise) { + this._state = { kind: 'pending' }; + this._promise = promise.then(value => { + this._state = { kind: 'fulfilled', value }; + return value; + }, error => { + this._state = { kind: 'rejected', error }; + throw error; + }); } - getPromise(): Promise { + getPromise() { return this._promise; } - getState(): PromiseState { + getState() { return this._state; } } -export function delayTime(ms: number): Promise { +exports.PromiseWithState = PromiseWithState; +function delayTime(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms); }); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/range.js b/modules/nuclide-commons/range.js index 63dbe0eb..915e0fc7 100644 --- a/modules/nuclide-commons/range.js +++ b/modules/nuclide-commons/range.js @@ -1,3 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.wordAtPositionFromBuffer = wordAtPositionFromBuffer; +exports.matchRegexEndingAt = matchRegexEndingAt; +exports.isPositionInRange = isPositionInRange; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,25 +14,18 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -export function wordAtPositionFromBuffer( - buffer: atom$TextBuffer | simpleTextBuffer$TextBuffer, - position: atom$PointObject, - wordRegex: RegExp, -): ?{wordMatch: Array, range: atom$Range} { - const {row, column} = position; +function wordAtPositionFromBuffer(buffer, position, wordRegex) { + const { row, column } = position; const rowRange = buffer.rangeForRow(row); let matchData; // Extract the expression from the row text. buffer.scanInRange(wordRegex, rowRange, data => { - const {range} = data; - if ( - range.start.isLessThanOrEqual(position) && - range.end.isGreaterThan(position) - ) { + const { range } = data; + if (range.start.isLessThanOrEqual(position) && range.end.isGreaterThan(position)) { matchData = data; } // Stop the scan if the scanner has passed our position. @@ -35,7 +36,7 @@ export function wordAtPositionFromBuffer( if (matchData) { return { wordMatch: matchData.match, - range: matchData.range, + range: matchData.range }; } else { return null; @@ -45,21 +46,12 @@ export function wordAtPositionFromBuffer( // Matches a regex on the text of the line ending at endPosition. // regex should end with a '$'. // Useful for autocomplete. -export function matchRegexEndingAt( - buffer: atom$TextBuffer | simpleTextBuffer$TextBuffer, - endPosition: atom$PointObject, - regex: RegExp, -): ?string { +function matchRegexEndingAt(buffer, endPosition, regex) { const line = buffer.getTextInRange([[endPosition.row, 0], endPosition]); const match = regex.exec(line); return match == null ? null : match[0]; } -export function isPositionInRange( - position: atom$Point, - range: atom$Range | Array, -): boolean { - return Array.isArray(range) - ? range.some(r => r.containsPoint(position)) - : range.containsPoint(position); -} +function isPositionInRange(position, range) { + return Array.isArray(range) ? range.some(r => r.containsPoint(position)) : range.containsPoint(position); +} \ No newline at end of file diff --git a/modules/nuclide-commons/redux-observable.js b/modules/nuclide-commons/redux-observable.js index 0d321166..385493ce 100644 --- a/modules/nuclide-commons/redux-observable.js +++ b/modules/nuclide-commons/redux-observable.js @@ -1,14 +1,34 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ActionsObservable = undefined; +exports.combineEpics = combineEpics; +exports.createEpicMiddleware = createEpicMiddleware; + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +// This should be { type: readonly string } when we get readonly props. Because this is used with +// disjoint unions we can't use `string` here due to mutation concerns. Flow doesn't know that we +// aren't going to mutate the objects with a random string value so it can't allow us to pass a +// specific action type into something of type { type: string } +function combineEpics(...epics) { + return (actions, store, extra) => { + const streams = epics.map(epic => epic(actions, store, extra)); + return _rxjsBundlesRxMinJs.Observable.merge(...streams); + }; +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ // Derived from because their version // imports an Rx operator module and we use a bundle. Original license follows: @@ -35,46 +55,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import {Observable, Subject} from 'rxjs'; - -// This should be { type: readonly string } when we get readonly props. Because this is used with -// disjoint unions we can't use `string` here due to mutation concerns. Flow doesn't know that we -// aren't going to mutate the objects with a random string value so it can't allow us to pass a -// specific action type into something of type { type: string } -type Action = {type: any}; -type Store = { - dispatch(action: T): void, - getState(): U, -}; -type Next = (action: T) => T; -export type Epic = ( - actions: ActionsObservable, - store: Store, - extra: E, -) => Observable; - -export function combineEpics( - ...epics: Array> -): Epic { - return (actions: ActionsObservable, store: Store, extra: E) => { - const streams: Array> = epics.map(epic => - epic(actions, store, extra), - ); - return Observable.merge(...streams); - }; -} - -export function createEpicMiddleware( - rootEpic?: Epic, -) { - const actions = new Subject(); +function createEpicMiddleware(rootEpic) { + const actions = new _rxjsBundlesRxMinJs.Subject(); const actionsObs = new ActionsObservable(actions); - return (store: Store) => (next: Next) => { + return store => next => { if (rootEpic != null) { rootEpic(actionsObs, store).subscribe(store.dispatch); } - return (action: T) => { + return action => { const result = next(action); actions.next(action); return result; @@ -82,22 +71,21 @@ export function createEpicMiddleware( }; } -export class ActionsObservable extends Observable { - operator: any; +class ActionsObservable extends _rxjsBundlesRxMinJs.Observable { - constructor(actionsSubject: Observable) { + constructor(actionsSubject) { super(); this.source = actionsSubject; } - lift(operator: any): Observable { + lift(operator) { const observable = new ActionsObservable(this); observable.operator = operator; return observable; } - ofType(...keys: Array): ActionsObservable { - const result = this.filter(({type}) => { + ofType(...keys) { + const result = this.filter(({ type }) => { const len = keys.length; if (len === 1) { return type === keys[0]; @@ -110,6 +98,7 @@ export class ActionsObservable extends Observable { } return false; }); - return ((result: any): ActionsObservable); + return result; } } +exports.ActionsObservable = ActionsObservable; \ No newline at end of file diff --git a/modules/nuclide-commons/spec/BatchProcessedQueue-spec.js b/modules/nuclide-commons/spec/BatchProcessedQueue-spec.js index df865a6f..4a6c734f 100644 --- a/modules/nuclide-commons/spec/BatchProcessedQueue-spec.js +++ b/modules/nuclide-commons/spec/BatchProcessedQueue-spec.js @@ -1,21 +1,17 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import BatchProcessedQueue from '../BatchProcessedQueue'; +var _BatchProcessedQueue; + +function _load_BatchProcessedQueue() { + return _BatchProcessedQueue = _interopRequireDefault(require('../BatchProcessedQueue')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('analytics - BatchProcessedQueue', () => { it('regular operation', () => { const handler = jasmine.createSpy('handler'); - const queue = new BatchProcessedQueue(5000, handler); + const queue = new (_BatchProcessedQueue || _load_BatchProcessedQueue()).default(5000, handler); queue.add(1); queue.add(2); @@ -33,4 +29,14 @@ describe('analytics - BatchProcessedQueue', () => { advanceClock(10000); expect(handler).toHaveBeenCalledWith([42]); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/ConfigCache-spec.js b/modules/nuclide-commons/spec/ConfigCache-spec.js index 7de4b345..6db4d608 100644 --- a/modules/nuclide-commons/spec/ConfigCache-spec.js +++ b/modules/nuclide-commons/spec/ConfigCache-spec.js @@ -1,3 +1,21 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _ConfigCache; + +function _load_ConfigCache() { + return _ConfigCache = require('../ConfigCache'); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('../nuclideUri')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,76 +24,58 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import {ConfigCache} from '../ConfigCache'; -import nuclideUri from '../nuclideUri'; - const CONFIG_FILE_NAME = '.test_nuclide_config_file'; const CONFIG_FILE_NAME_2 = '.test_nuclide_config_file_2'; describe('ConfigCache', () => { - const noConfigFolder = nuclideUri.join(__dirname, 'fixtures'); - const rootFolder = nuclideUri.join(__dirname, 'fixtures/ConfigCache'); - const rootFile = nuclideUri.join(__dirname, 'fixtures/ConfigCache/file'); - const nestedFolder = nuclideUri.join( - __dirname, - 'fixtures/ConfigCache/testFolder', - ); - const nestedFolder2 = nuclideUri.join( - __dirname, - 'fixtures/ConfigCache/testFolder2', - ); - const nestedFile = nuclideUri.join( - __dirname, - 'fixtures/ConfigCache/testFolder/file', - ); + const noConfigFolder = (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures'); + const rootFolder = (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures/ConfigCache'); + const rootFile = (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures/ConfigCache/file'); + const nestedFolder = (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures/ConfigCache/testFolder'); + const nestedFolder2 = (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures/ConfigCache/testFolder2'); + const nestedFile = (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures/ConfigCache/testFolder/file'); it('finds the right config dir', () => { - waitsForPromise(async () => { - const cache = new ConfigCache([CONFIG_FILE_NAME]); - - expect(await cache.getConfigDir(noConfigFolder)).toBe(null); - expect(await cache.getConfigDir(rootFolder)).toBe(rootFolder); - expect(await cache.getConfigDir(rootFile)).toBe(rootFolder); - expect(await cache.getConfigDir(nestedFolder)).toBe(nestedFolder); - expect(await cache.getConfigDir(nestedFile)).toBe(nestedFolder); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const cache = new (_ConfigCache || _load_ConfigCache()).ConfigCache([CONFIG_FILE_NAME]); + + expect((yield cache.getConfigDir(noConfigFolder))).toBe(null); + expect((yield cache.getConfigDir(rootFolder))).toBe(rootFolder); + expect((yield cache.getConfigDir(rootFile))).toBe(rootFolder); + expect((yield cache.getConfigDir(nestedFolder))).toBe(nestedFolder); + expect((yield cache.getConfigDir(nestedFile))).toBe(nestedFolder); + })); }); it('prefers closer matches with multiple config files', () => { - waitsForPromise(async () => { - const cache = new ConfigCache([CONFIG_FILE_NAME, CONFIG_FILE_NAME_2]); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const cache = new (_ConfigCache || _load_ConfigCache()).ConfigCache([CONFIG_FILE_NAME, CONFIG_FILE_NAME_2]); - expect(await cache.getConfigDir(rootFolder)).toBe(rootFolder); - expect(await cache.getConfigDir(nestedFolder2)).toBe(nestedFolder2); - }); + expect((yield cache.getConfigDir(rootFolder))).toBe(rootFolder); + expect((yield cache.getConfigDir(nestedFolder2))).toBe(nestedFolder2); + })); }); it('prefers further matches when the search strategy is "furthest"', () => { - waitsForPromise(async () => { - const cache = new ConfigCache( - [CONFIG_FILE_NAME, CONFIG_FILE_NAME_2], - 'furthest', - ); - - expect(await cache.getConfigDir(rootFolder)).toBe(rootFolder); - expect(await cache.getConfigDir(nestedFolder)).toBe(rootFolder); - expect(await cache.getConfigDir(nestedFolder2)).toBe(rootFolder); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const cache = new (_ConfigCache || _load_ConfigCache()).ConfigCache([CONFIG_FILE_NAME, CONFIG_FILE_NAME_2], 'furthest'); + + expect((yield cache.getConfigDir(rootFolder))).toBe(rootFolder); + expect((yield cache.getConfigDir(nestedFolder))).toBe(rootFolder); + expect((yield cache.getConfigDir(nestedFolder2))).toBe(rootFolder); + })); }); it('prefers priority matches when the search strategy is "priority"', () => { - waitsForPromise(async () => { - const cache = new ConfigCache( - [CONFIG_FILE_NAME, CONFIG_FILE_NAME_2], - 'priority', - ); - - expect(await cache.getConfigDir(rootFolder)).toBe(rootFolder); - expect(await cache.getConfigDir(nestedFolder2)).toBe(rootFolder); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const cache = new (_ConfigCache || _load_ConfigCache()).ConfigCache([CONFIG_FILE_NAME, CONFIG_FILE_NAME_2], 'priority'); + + expect((yield cache.getConfigDir(rootFolder))).toBe(rootFolder); + expect((yield cache.getConfigDir(nestedFolder2))).toBe(rootFolder); + })); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/Hasher-spec.js b/modules/nuclide-commons/spec/Hasher-spec.js index 8135f1c1..3691f4f1 100644 --- a/modules/nuclide-commons/spec/Hasher-spec.js +++ b/modules/nuclide-commons/spec/Hasher-spec.js @@ -1,46 +1,52 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import Hasher from '../Hasher'; +'use strict'; + +var _Hasher; + +function _load_Hasher() { + return _Hasher = _interopRequireDefault(require('../Hasher')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('Hasher', () => { it('creates a new hash for each object', () => { const a = {}; const b = {}; - const hasher = new Hasher(); + const hasher = new (_Hasher || _load_Hasher()).default(); expect(hasher.getHash(a)).not.toBe(hasher.getHash(b)); }); it('returns the same hash for the same object', () => { const a = {}; - const hasher = new Hasher(); + const hasher = new (_Hasher || _load_Hasher()).default(); expect(hasher.getHash(a)).toBe(hasher.getHash(a)); }); it('works for numbers', () => { - const hasher = new Hasher(); + const hasher = new (_Hasher || _load_Hasher()).default(); expect(hasher.getHash(1)).toBe(hasher.getHash(1)); expect(hasher.getHash(1)).not.toBe(hasher.getHash(2)); }); it('works for booleans', () => { - const hasher = new Hasher(); + const hasher = new (_Hasher || _load_Hasher()).default(); expect(hasher.getHash(true)).toBe(hasher.getHash(true)); expect(hasher.getHash(true)).not.toBe(hasher.getHash(false)); }); it('works for strings', () => { - const hasher = new Hasher(); + const hasher = new (_Hasher || _load_Hasher()).default(); expect(hasher.getHash('a')).toBe(hasher.getHash('a')); expect(hasher.getHash('a')).not.toBe(hasher.getHash('b')); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/Model-spec.js b/modules/nuclide-commons/spec/Model-spec.js index 5aed62cc..ee4b66d6 100644 --- a/modules/nuclide-commons/spec/Model-spec.js +++ b/modules/nuclide-commons/spec/Model-spec.js @@ -1,43 +1,44 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import Model from '../Model'; +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _Model; + +function _load_Model() { + return _Model = _interopRequireDefault(require('../Model')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('Model', () => { it('setStates state when setState is called', () => { - const model = new Model({count: 0, other: true}); - model.setState({count: 5}); + const model = new (_Model || _load_Model()).default({ count: 0, other: true }); + model.setState({ count: 5 }); expect(model.state.count).toBe(5); }); it('only changes the provided values when setState is called', () => { - const model = new Model({count: 0, other: true}); - model.setState({count: 5}); + const model = new (_Model || _load_Model()).default({ count: 0, other: true }); + model.setState({ count: 5 }); expect(model.state.other).toBe(true); }); it('can be converted to an observable', () => { - waitsForPromise(async () => { - const model = new Model({count: 0, other: true}); - const states = model - .toObservable() - .take(2) - .toArray() - .toPromise(); - model.setState({count: 5}); - expect(await states).toEqual([ - {count: 0, other: true}, - {count: 5, other: true}, - ]); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const model = new (_Model || _load_Model()).default({ count: 0, other: true }); + const states = model.toObservable().take(2).toArray().toPromise(); + model.setState({ count: 5 }); + expect((yield states)).toEqual([{ count: 0, other: true }, { count: 5, other: true }]); + })); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/ObservablePool-spec.js b/modules/nuclide-commons/spec/ObservablePool-spec.js index 996b7fe1..9c6671f7 100644 --- a/modules/nuclide-commons/spec/ObservablePool-spec.js +++ b/modules/nuclide-commons/spec/ObservablePool-spec.js @@ -1,34 +1,30 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import invariant from 'assert'; -import {Observable, Subject} from 'rxjs'; -import ObservablePool from '../ObservablePool'; +'use strict'; + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _ObservablePool; + +function _load_ObservablePool() { + return _ObservablePool = _interopRequireDefault(require('../ObservablePool')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('ObservablePool', () => { it('limits the concurrency of observable values with cancellation', () => { - const pool = new ObservablePool(2); + const pool = new (_ObservablePool || _load_ObservablePool()).default(2); - const subject1 = new Subject(); + const subject1 = new _rxjsBundlesRxMinJs.Subject(); const spy1 = jasmine.createSpy('1').andReturn(subject1); const req1 = pool.schedule(spy1); - const subject2 = new Subject(); + const subject2 = new _rxjsBundlesRxMinJs.Subject(); const spy2 = jasmine.createSpy('2').andReturn(subject2); const req2 = pool.schedule(spy2); - const subject3 = new Subject(); + const subject3 = new _rxjsBundlesRxMinJs.Subject(); const spy3 = jasmine.createSpy('3').andReturn(subject3); - const req3 = pool.schedule(Observable.defer(spy3)); + const req3 = pool.schedule(_rxjsBundlesRxMinJs.Observable.defer(spy3)); // Nothing should happen until subscription. expect(spy1).not.toHaveBeenCalled(); @@ -61,19 +57,15 @@ describe('ObservablePool', () => { }); it('waits for promises, even on unsubscribe', () => { - const pool = new ObservablePool(1); - let resolve: ?Function; - let reject: ?Function; - const spy1 = jasmine.createSpy('1').andReturn( - new Promise(r => { - resolve = r; - }), - ); - const spy2 = jasmine.createSpy('2').andReturn( - new Promise((_, r) => { - reject = r; - }), - ); + const pool = new (_ObservablePool || _load_ObservablePool()).default(1); + let resolve; + let reject; + const spy1 = jasmine.createSpy('1').andReturn(new Promise(r => { + resolve = r; + })); + const spy2 = jasmine.createSpy('2').andReturn(new Promise((_, r) => { + reject = r; + })); const errorSpy = jasmine.createSpy('errorSpy'); const sub1 = pool.schedule(spy1).subscribe(); pool.schedule(spy2).subscribe(() => {}, errorSpy); @@ -81,10 +73,7 @@ describe('ObservablePool', () => { // Immediately subscribe & unsubscribe - // the request should never be scheduled. const spy3 = jasmine.createSpy('3').andReturn(Promise.resolve()); - pool - .schedule(spy3) - .subscribe() - .unsubscribe(); + pool.schedule(spy3).subscribe().unsubscribe(); expect(spy1).toHaveBeenCalled(); expect(spy2).not.toHaveBeenCalled(); @@ -93,14 +82,21 @@ describe('ObservablePool', () => { // Remove the request, but remain blocked until the promise actually resolves. expect(pool._responseListeners.size).toEqual(1); expect(spy2).not.toHaveBeenCalled(); - invariant(resolve != null, 'spy1 should have been scheduled'); + + if (!(resolve != null)) { + throw new Error('spy1 should have been scheduled'); + } + resolve(); // Promise resolution is always async... waitsFor(() => spy2.wasCalled, 'spy2 should be called'); runs(() => { - invariant(reject != null, 'spy2 was called'); + if (!(reject != null)) { + throw new Error('spy2 was called'); + } + reject('test'); }); @@ -114,25 +110,33 @@ describe('ObservablePool', () => { }); it('catches executor errors', () => { - const pool = new ObservablePool(1); + const pool = new (_ObservablePool || _load_ObservablePool()).default(1); let error; - pool - .schedule(() => { - throw Error('test'); - }) - .subscribe({ - error(err) { - error = err; - }, - }); + pool.schedule(() => { + throw Error('test'); + }).subscribe({ + error(err) { + error = err; + } + }); expect(error).toEqual(Error('test')); }); it('errors on disposal', () => { - const pool = new ObservablePool(1); + const pool = new (_ObservablePool || _load_ObservablePool()).default(1); const errorSpy = jasmine.createSpy('errorSpy'); - pool.schedule(() => Promise.resolve()).subscribe({error: errorSpy}); + pool.schedule(() => Promise.resolve()).subscribe({ error: errorSpy }); pool.dispose(); expect(errorSpy).toHaveBeenCalled(); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/SafeStreamMessageReader-spec.js b/modules/nuclide-commons/spec/SafeStreamMessageReader-spec.js index 126e3e15..5f15647a 100644 --- a/modules/nuclide-commons/spec/SafeStreamMessageReader-spec.js +++ b/modules/nuclide-commons/spec/SafeStreamMessageReader-spec.js @@ -1,3 +1,15 @@ +'use strict'; + +var _stream = _interopRequireDefault(require('stream')); + +var _SafeStreamMessageReader; + +function _load_SafeStreamMessageReader() { + return _SafeStreamMessageReader = _interopRequireDefault(require('../SafeStreamMessageReader')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,41 +18,38 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import Stream from 'stream'; -import SafeStreamMessageReader from '../SafeStreamMessageReader'; - describe('SafeStreamMessageReader', () => { it('reads valid messages', () => { - const readable = new Stream.Readable({ + const readable = new _stream.default.Readable({ read() { this.push('Content-Length: 7\r\n\r\n{"a":1}'); this.push(null); - }, + } }); - const reader = new SafeStreamMessageReader(readable); + const reader = new (_SafeStreamMessageReader || _load_SafeStreamMessageReader()).default(readable); const listenSpy = jasmine.createSpy('listen'); reader.listen(listenSpy); waitsFor(() => listenSpy.wasCalled); runs(() => { - expect(listenSpy.calls[0].args).toEqual([{a: 1}]); + expect(listenSpy.calls[0].args).toEqual([{ a: 1 }]); }); }); it('emits an error for an invalid header', () => { - const readable = new Stream.Readable({ + const readable = new _stream.default.Readable({ read() { this.push('Invalid-Header: test\r\n\r\n'); this.push('Content-Length: 2\r\n\r\n{}'); this.push(null); - }, + } }); - const reader = new SafeStreamMessageReader(readable); + const reader = new (_SafeStreamMessageReader || _load_SafeStreamMessageReader()).default(readable); const listenSpy = jasmine.createSpy('listen'); const errorSpy = jasmine.createSpy('error'); reader.listen(listenSpy); @@ -53,4 +62,4 @@ describe('SafeStreamMessageReader', () => { expect(listenSpy).not.toHaveBeenCalled(); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/UniversalDisposable-spec.js b/modules/nuclide-commons/spec/UniversalDisposable-spec.js index f3f0744f..d250c7c5 100644 --- a/modules/nuclide-commons/spec/UniversalDisposable-spec.js +++ b/modules/nuclide-commons/spec/UniversalDisposable-spec.js @@ -1,21 +1,17 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import UniversalDisposable from '../UniversalDisposable'; +'use strict'; + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('../UniversalDisposable')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('UniversalDisposable', () => { it('disposes of the Disposable arguments', () => { const dispose = jasmine.createSpy('dispose'); - const universal = new UniversalDisposable({dispose}); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default({ dispose }); expect(dispose.wasCalled).toBe(false); universal.dispose(); @@ -23,7 +19,7 @@ describe('UniversalDisposable', () => { }); it('throws if you add after disposing', () => { - const universal = new UniversalDisposable(); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(); universal.dispose(); expect(() => { universal.add(() => {}); @@ -32,7 +28,7 @@ describe('UniversalDisposable', () => { it('calls function arguments', () => { const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable(foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(foo); expect(foo.wasCalled).toBe(false); universal.dispose(); @@ -41,7 +37,7 @@ describe('UniversalDisposable', () => { it('calls unsubscribe arguments', () => { const unsubscribe = jasmine.createSpy('unsubscribe'); - const universal = new UniversalDisposable(unsubscribe); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(unsubscribe); expect(unsubscribe.wasCalled).toBe(false); universal.dispose(); @@ -52,7 +48,7 @@ describe('UniversalDisposable', () => { const dispose = jasmine.createSpy('dispose'); const unsubscribe = jasmine.createSpy('unsubscribe'); const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable({dispose}, {unsubscribe}, foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default({ dispose }, { unsubscribe }, foo); expect(dispose.wasCalled).toBe(false); expect(unsubscribe.wasCalled).toBe(false); @@ -67,8 +63,8 @@ describe('UniversalDisposable', () => { const dispose = jasmine.createSpy('dispose'); const unsubscribe = jasmine.createSpy('unsubscribe'); const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable(); - universal.add({dispose}, {unsubscribe}, foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(); + universal.add({ dispose }, { unsubscribe }, foo); expect(dispose.wasCalled).toBe(false); expect(unsubscribe.wasCalled).toBe(false); @@ -83,7 +79,7 @@ describe('UniversalDisposable', () => { const dispose = jasmine.createSpy('dispose'); const unsubscribe = jasmine.createSpy('unsubscribe'); const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable({dispose}, {unsubscribe}, foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default({ dispose }, { unsubscribe }, foo); expect(dispose.wasCalled).toBe(false); expect(unsubscribe.wasCalled).toBe(false); @@ -98,7 +94,7 @@ describe('UniversalDisposable', () => { const dispose = jasmine.createSpy('dispose'); const unsubscribe = jasmine.createSpy('unsubscribe'); const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable({dispose}, {unsubscribe}, foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default({ dispose }, { unsubscribe }, foo); expect(dispose.wasCalled).toBe(false); expect(unsubscribe.wasCalled).toBe(false); @@ -113,10 +109,10 @@ describe('UniversalDisposable', () => { }); it('supports removal of the teardowns', () => { - const dispose = {dispose: jasmine.createSpy('dispose')}; - const unsubscribe = {unsubscribe: jasmine.createSpy('unsubscribe')}; + const dispose = { dispose: jasmine.createSpy('dispose') }; + const unsubscribe = { unsubscribe: jasmine.createSpy('unsubscribe') }; const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable(dispose, unsubscribe, foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(dispose, unsubscribe, foo); universal.remove(unsubscribe); universal.remove(dispose); @@ -130,10 +126,10 @@ describe('UniversalDisposable', () => { }); it('can clear all of the teardowns', () => { - const dispose = {dispose: jasmine.createSpy('dispose')}; - const unsubscribe = {unsubscribe: jasmine.createSpy('unsubscribe')}; + const dispose = { dispose: jasmine.createSpy('dispose') }; + const unsubscribe = { unsubscribe: jasmine.createSpy('unsubscribe') }; const foo = jasmine.createSpy('foo'); - const universal = new UniversalDisposable(dispose, unsubscribe, foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(dispose, unsubscribe, foo); universal.clear(); @@ -152,7 +148,7 @@ describe('UniversalDisposable', () => { const foo3 = () => ids.push(3); const foo4 = () => ids.push(4); - const universal = new UniversalDisposable(foo1, foo3); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(foo1, foo3); universal.add(foo4, foo2); universal.dispose(); @@ -162,11 +158,11 @@ describe('UniversalDisposable', () => { describe('teardown priority', () => { it('calls dispose()', () => { - const foo: Function = jasmine.createSpy('foo'); + const foo = jasmine.createSpy('foo'); foo.dispose = jasmine.createSpy('dispose'); foo.unsubscribe = jasmine.createSpy('unsubscribe'); - const universal = new UniversalDisposable(foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(foo); universal.dispose(); expect(foo.dispose.wasCalled).toBe(true); @@ -175,11 +171,11 @@ describe('UniversalDisposable', () => { }); it('calls unsubscribe()', () => { - const foo: Function = jasmine.createSpy('foo'); + const foo = jasmine.createSpy('foo'); foo.dispose = null; foo.unsubscribe = jasmine.createSpy('unsubscribe'); - const universal = new UniversalDisposable(foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(foo); universal.dispose(); expect(foo.unsubscribe.wasCalled).toBe(true); @@ -187,14 +183,24 @@ describe('UniversalDisposable', () => { }); it('calls the function', () => { - const foo: Function = jasmine.createSpy('foo'); + const foo = jasmine.createSpy('foo'); foo.dispose = null; foo.unsubscribe = null; - const universal = new UniversalDisposable(foo); + const universal = new (_UniversalDisposable || _load_UniversalDisposable()).default(foo); universal.dispose(); expect(foo.wasCalled).toBe(true); }); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/cache-spec.js b/modules/nuclide-commons/spec/cache-spec.js index f97010d4..a3769f2b 100644 --- a/modules/nuclide-commons/spec/cache-spec.js +++ b/modules/nuclide-commons/spec/cache-spec.js @@ -1,16 +1,14 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import {Cache} from '../cache'; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _cache; + +function _load_cache() { + return _cache = require('../cache'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('Cache', () => { const key1 = 'key1'; @@ -24,7 +22,7 @@ describe('Cache', () => { expect(key).toEqual(key1); return value; }); - const cache: Cache = new Cache(factory); + const cache = new (_cache || _load_cache()).Cache(factory); expect(factory).not.toHaveBeenCalled(); expect(cache.has(key1)).toEqual(false); @@ -40,7 +38,7 @@ describe('Cache', () => { it('delete', () => { const factory = jasmine.createSpy('factory').andReturn(value); - const cache: Cache = new Cache(factory); + const cache = new (_cache || _load_cache()).Cache(factory); expect(cache.delete(key1)).toEqual(false); cache.get(key1); @@ -52,7 +50,7 @@ describe('Cache', () => { it('delete disposes values', () => { const factory = jasmine.createSpy('factory').andReturn(value); const dispose = jasmine.createSpy('dispose'); - const cache: Cache = new Cache(factory, dispose); + const cache = new (_cache || _load_cache()).Cache(factory, dispose); cache.get(key1); cache.delete(key1); @@ -62,7 +60,7 @@ describe('Cache', () => { it('clear disposes values', () => { const factory = jasmine.createSpy('factory').andReturn(value); const dispose = jasmine.createSpy('dispose'); - const cache: Cache = new Cache(factory, dispose); + const cache = new (_cache || _load_cache()).Cache(factory, dispose); cache.get(key1); cache.clear(); @@ -72,7 +70,7 @@ describe('Cache', () => { it('dispose disposes values', () => { const factory = jasmine.createSpy('factory').andReturn(value); const dispose = jasmine.createSpy('dispose'); - const cache: Cache = new Cache(factory, dispose); + const cache = new (_cache || _load_cache()).Cache(factory, dispose); cache.get(key1); cache.dispose(); @@ -80,34 +78,42 @@ describe('Cache', () => { }); it('observeValues sees existing and new values', () => { - waitsForPromise(async () => { - const factory = jasmine.createSpy('factory').andCallFake(key => key); - const cache: Cache = new Cache(factory); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const factory = jasmine.createSpy('factory').andCallFake(function (key) { + return key; + }); + const cache = new (_cache || _load_cache()).Cache(factory); cache.get(key1); - const values = cache - .observeValues() - .toArray() - .toPromise(); + const values = cache.observeValues().toArray().toPromise(); cache.get(key2); cache.dispose(); - expect(await values).toEqual([key1, key2]); - }); + expect((yield values)).toEqual([key1, key2]); + })); }); it('observeKeys sees existing and new keys', () => { - waitsForPromise(async () => { - const factory = jasmine.createSpy('factory').andCallFake(key => value); - const cache: Cache = new Cache(factory); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const factory = jasmine.createSpy('factory').andCallFake(function (key) { + return value; + }); + const cache = new (_cache || _load_cache()).Cache(factory); cache.get(key1); - const values = cache - .observeKeys() - .toArray() - .toPromise(); + const values = cache.observeKeys().toArray().toPromise(); cache.get(key2); cache.dispose(); - expect(await values).toEqual([key1, key2]); - }); + expect((yield values)).toEqual([key1, key2]); + })); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/collection-spec.js b/modules/nuclide-commons/spec/collection-spec.js index 71156143..6dc3d0c7 100644 --- a/modules/nuclide-commons/spec/collection-spec.js +++ b/modules/nuclide-commons/spec/collection-spec.js @@ -1,67 +1,37 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import { - ensureArray, - arrayRemove, - arrayEqual, - arrayCompact, - arrayFindLastIndex, - mapUnion, - insideOut, - isEmpty, - isIterable, - keyMirror, - setFilter, - setIntersect, - setUnion, - collect, - MultiMap, - objectEntries, - objectFromPairs, - objectFromMap, - objectMapValues, - objectValues, - concatIterators, - areSetsEqual, - someOfIterable, - findInIterable, - filterIterable, - mapEqual, - mapIterable, - mapGetWithDefault, - count, - range, - mapFromObject, - distinct, - takeIterable, -} from '../collection'; +'use strict'; + +var _collection; + +function _load_collection() { + return _collection = require('../collection'); +} describe('ensureArray', () => { it('works on arrays', () => { - expect(ensureArray([1])).toEqual([1]); - expect(ensureArray(['test'])).toEqual(['test']); + expect((0, (_collection || _load_collection()).ensureArray)([1])).toEqual([1]); + expect((0, (_collection || _load_collection()).ensureArray)(['test'])).toEqual(['test']); }); it('works on non-arrays', () => { - expect(ensureArray(1)).toEqual([1]); - expect(ensureArray('test')).toEqual(['test']); - }); -}); + expect((0, (_collection || _load_collection()).ensureArray)(1)).toEqual([1]); + expect((0, (_collection || _load_collection()).ensureArray)('test')).toEqual(['test']); + }); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('arrayRemove', () => { - let a: any; - let empty: any; - let single: any; + let a; + let empty; + let single; beforeEach(() => { a = ['a', 'b', 'c']; @@ -70,85 +40,78 @@ describe('arrayRemove', () => { }); it('removes an element properly', () => { - arrayRemove(a, 'b'); + (0, (_collection || _load_collection()).arrayRemove)(a, 'b'); expect(a).toEqual(['a', 'c']); }); it('removes the first element properly', () => { - arrayRemove(a, 'a'); + (0, (_collection || _load_collection()).arrayRemove)(a, 'a'); expect(a).toEqual(['b', 'c']); }); it('removes the last element properly', () => { - arrayRemove(a, 'c'); + (0, (_collection || _load_collection()).arrayRemove)(a, 'c'); expect(a).toEqual(['a', 'b']); }); it('does nothing if the element is not found', () => { - arrayRemove(a, 'd'); + (0, (_collection || _load_collection()).arrayRemove)(a, 'd'); expect(a).toEqual(['a', 'b', 'c']); }); it('does nothing to an empty array', () => { - arrayRemove(empty, 'a'); + (0, (_collection || _load_collection()).arrayRemove)(empty, 'a'); expect(empty).toEqual([]); }); it('works when there is a single element', () => { - arrayRemove(single, 'x'); + (0, (_collection || _load_collection()).arrayRemove)(single, 'x'); expect(single).toEqual([]); }); }); describe('arrayEqual', () => { it('checks boolean elements', () => { - expect(arrayEqual([true, false, true], [true, false, true])).toBe(true); - expect(arrayEqual([true], [false])).toBe(false); + expect((0, (_collection || _load_collection()).arrayEqual)([true, false, true], [true, false, true])).toBe(true); + expect((0, (_collection || _load_collection()).arrayEqual)([true], [false])).toBe(false); }); it('checks number elements', () => { - expect(arrayEqual([1, 2, 3], [1, 2, 3])).toBe(true); - expect(arrayEqual([1, 5, 3], [1, 2, 3])).toBe(false); + expect((0, (_collection || _load_collection()).arrayEqual)([1, 2, 3], [1, 2, 3])).toBe(true); + expect((0, (_collection || _load_collection()).arrayEqual)([1, 5, 3], [1, 2, 3])).toBe(false); }); it('checks object elements', () => { - expect(arrayEqual([{}], [{}])).toBe(false); - expect( - arrayEqual([{x: 1}, {x: 2}], [{x: 1}, {x: 2}], (a, b) => a.x === b.x), - ).toBe(true); + expect((0, (_collection || _load_collection()).arrayEqual)([{}], [{}])).toBe(false); + expect((0, (_collection || _load_collection()).arrayEqual)([{ x: 1 }, { x: 2 }], [{ x: 1 }, { x: 2 }], (a, b) => a.x === b.x)).toBe(true); }); it('works with arrays of different lengths', () => { - expect(arrayEqual([1, 2], [1, 2, 3])).toBe(false); - expect(arrayEqual([1, 2, 3], [1, 2])).toBe(false); + expect((0, (_collection || _load_collection()).arrayEqual)([1, 2], [1, 2, 3])).toBe(false); + expect((0, (_collection || _load_collection()).arrayEqual)([1, 2, 3], [1, 2])).toBe(false); }); it("doesn't call the compare function if the same array is used", () => { const compare = jasmine.createSpy().andReturn(true); const a = [1, 2, 3]; - arrayEqual(a, a, compare); + (0, (_collection || _load_collection()).arrayEqual)(a, a, compare); expect(compare).not.toHaveBeenCalled(); }); }); describe('arrayCompact', () => { it('filters out null and undefined elements', () => { - expect(arrayCompact([0, false, '', [], null, undefined])).toEqual([ - 0, - false, - '', - [], - ]); + expect((0, (_collection || _load_collection()).arrayCompact)([0, false, '', [], null, undefined])).toEqual([0, false, '', []]); }); }); describe('arrayFindLastIndex', () => { it('returns the last matching index', () => { - expect(arrayFindLastIndex([1, 1, 2], x => x === 1)).toBe(1); + expect((0, (_collection || _load_collection()).arrayFindLastIndex)([1, 1, 2], x => x === 1)).toBe(1); }); it('returns -1 if no match is found', () => { - expect(arrayFindLastIndex([1, 1, 2], x => x === 0)).toBe(-1); + expect((0, (_collection || _load_collection()).arrayFindLastIndex)([1, 1, 2], x => x === 0)).toBe(-1); }); }); @@ -156,7 +119,7 @@ describe('mapUnion', () => { it('merges two unique maps', () => { const map1 = new Map([['key1', 'value1'], ['key2', 'value2']]); const map2 = new Map([['key3', 'value3'], ['key4', 'value4']]); - const result = mapUnion(map1, map2); + const result = (0, (_collection || _load_collection()).mapUnion)(map1, map2); expect(result.size).toBe(4); expect(result.get('key1')).toBe('value1'); @@ -168,7 +131,7 @@ describe('mapUnion', () => { it('overrodes with the values of the latest maps', () => { const map1 = new Map([['commonKey', 'value1'], ['key2', 'value2']]); const map2 = new Map([['commonKey', 'value3'], ['key4', 'value4']]); - const result = mapUnion(...[map1, map2]); + const result = (0, (_collection || _load_collection()).mapUnion)(...[map1, map2]); expect(result.size).toBe(3); expect(result.get('commonKey')).toBe('value3'); @@ -179,31 +142,31 @@ describe('mapUnion', () => { describe('isEmpty', () => { it('correctly identifies empty Objects', () => { - expect(isEmpty({})).toEqual(true); + expect((0, (_collection || _load_collection()).isEmpty)({})).toEqual(true); }); it('correctly identifies non-empty Objects', () => { - const proto = {a: 1, b: 2, c: 3}; - const objWithOwnProperties = Object.create(proto, {foo: {value: 'bar'}}); + const proto = { a: 1, b: 2, c: 3 }; + const objWithOwnProperties = Object.create(proto, { foo: { value: 'bar' } }); const objWithoutOwnProperties = Object.create(proto); - expect(isEmpty({a: 1})).toEqual(false); - expect(isEmpty(objWithOwnProperties)).toEqual(false); - expect(isEmpty(objWithoutOwnProperties)).toEqual(false); + expect((0, (_collection || _load_collection()).isEmpty)({ a: 1 })).toEqual(false); + expect((0, (_collection || _load_collection()).isEmpty)(objWithOwnProperties)).toEqual(false); + expect((0, (_collection || _load_collection()).isEmpty)(objWithoutOwnProperties)).toEqual(false); }); }); describe('isIterable', () => { it('detects arrays are iterable', () => { - expect(isIterable(['foo', 'bar'])).toBe(true); + expect((0, (_collection || _load_collection()).isIterable)(['foo', 'bar'])).toBe(true); }); it('detects strings are iterable', () => { - expect(isIterable('foo')).toBe(true); + expect((0, (_collection || _load_collection()).isIterable)('foo')).toBe(true); }); it('detects Sets are iterable', () => { - expect(isIterable(new Set(['foo', 'bar']))).toBe(true); + expect((0, (_collection || _load_collection()).isIterable)(new Set(['foo', 'bar']))).toBe(true); }); it('detects iterable objects are iterable', () => { @@ -211,31 +174,31 @@ describe('isIterable', () => { *[Symbol.iterator]() { yield 1; yield 42; - }, + } }; - expect(isIterable(anIterable)).toBe(true); + expect((0, (_collection || _load_collection()).isIterable)(anIterable)).toBe(true); }); it('detects plain objects are not iterable', () => { - expect(isIterable({foo: 'bar', baz: 42})).toBe(false); + expect((0, (_collection || _load_collection()).isIterable)({ foo: 'bar', baz: 42 })).toBe(false); }); it('detects numbers are not iterable', () => { - expect(isIterable(42)).toBe(false); + expect((0, (_collection || _load_collection()).isIterable)(42)).toBe(false); }); }); describe('keyMirror', () => { it('correctly mirrors objects', () => { - expect(keyMirror({a: null, b: null})).toEqual({a: 'a', b: 'b'}); + expect((0, (_collection || _load_collection()).keyMirror)({ a: null, b: null })).toEqual({ a: 'a', b: 'b' }); }); }); describe('setFilter', () => { it('filters', () => { const set = new Set(['foo', 'bar', 'baz']); - const filtered = setFilter(set, x => x.startsWith('b')); + const filtered = (0, (_collection || _load_collection()).setFilter)(set, x => x.startsWith('b')); expect(filtered.size).toBe(2); expect(filtered.has('bar')).toBe(true); @@ -248,7 +211,7 @@ describe('setIntersect', () => { it('intersects', () => { const set1 = new Set(['foo', 'bar', 'baz']); const set2 = new Set(['fool', 'bar', 'bazl']); - const result = setIntersect(set1, set2); + const result = (0, (_collection || _load_collection()).setIntersect)(set1, set2); expect(result.size).toBe(1); expect(result.has('bar')).toBe(true); @@ -259,27 +222,17 @@ describe('setUnion', () => { it('unions', () => { const set1 = new Set(['foo', 'bar', 'baz']); const set2 = new Set(['fool', 'bar', 'bazl']); - const result = setUnion(set1, set2); + const result = (0, (_collection || _load_collection()).setUnion)(set1, set2); const expected = new Set(['foo', 'bar', 'baz', 'fool', 'bazl']); - expect(areSetsEqual(result, expected)).toBe(true); + expect((0, (_collection || _load_collection()).areSetsEqual)(result, expected)).toBe(true); }); }); describe('collect', () => { it('collects key-value pairs into a Map of arrays', () => { - const pairs = [ - ['neither', 1], - ['neither', 2], - ['fizz', 3], - ['neither', 4], - ['buzz', 5], - ['fizz', 6], - ['neither', 7], - ['neither', 8], - ['fizz', 9], - ]; - const result = collect(pairs); + const pairs = [['neither', 1], ['neither', 2], ['fizz', 3], ['neither', 4], ['buzz', 5], ['fizz', 6], ['neither', 7], ['neither', 8], ['fizz', 9]]; + const result = (0, (_collection || _load_collection()).collect)(pairs); expect(result.size).toBe(3); expect(result.get('fizz')).toEqual([3, 6, 9]); @@ -289,10 +242,10 @@ describe('collect', () => { }); describe('MultiMap', () => { - let multimap: MultiMap = (null: any); + let multimap = null; beforeEach(() => { - multimap = new MultiMap(); + multimap = new (_collection || _load_collection()).MultiMap(); }); afterEach(() => { @@ -320,10 +273,7 @@ describe('MultiMap', () => { }); it('properly adds multiple bindings', () => { - multimap - .add(1, 2) - .add(1, 3) - .add(10, 11); + multimap.add(1, 2).add(1, 3).add(10, 11); expect(multimap.size).toEqual(3); expect(multimap.get(1)).toEqual(new Set([2, 3])); expect(multimap.get(10)).toEqual(new Set([11])); @@ -336,10 +286,7 @@ describe('MultiMap', () => { }); it('properly deletes a single binding', () => { - multimap - .add(1, 2) - .add(1, 3) - .add(10, 11); + multimap.add(1, 2).add(1, 3).add(10, 11); expect(multimap.delete(1, 2)).toBe(true); expect(multimap.get(1)).toEqual(new Set([3])); expect(multimap.get(10)).toEqual(new Set([11])); @@ -358,10 +305,7 @@ describe('MultiMap', () => { }); it('properly clears', () => { - multimap - .add(1, 2) - .add(1, 3) - .add(10, 11); + multimap.add(1, 2).add(1, 3).add(10, 11); multimap.clear(); expect(multimap.size).toEqual(0); expect(multimap.get(1)).toEqual(new Set()); @@ -384,271 +328,191 @@ describe('MultiMap', () => { describe('objectValues', () => { it('returns the values of an object', () => { - expect( - objectValues({ - a: 1, - b: 2, - c: 4, - }), - ).toEqual([1, 2, 4]); + expect((0, (_collection || _load_collection()).objectValues)({ + a: 1, + b: 2, + c: 4 + })).toEqual([1, 2, 4]); }); it('throws for null', () => { - expect(() => objectEntries(null)).toThrow(); + expect(() => (0, (_collection || _load_collection()).objectEntries)(null)).toThrow(); }); it('throws for undefined', () => { - expect(() => objectEntries(undefined)).toThrow(); + expect(() => (0, (_collection || _load_collection()).objectEntries)(undefined)).toThrow(); }); }); describe('objectEntries', () => { it('gets the entries of an object', () => { - expect(objectEntries({a: 1, b: 2})).toEqual([['a', 1], ['b', 2]]); + expect((0, (_collection || _load_collection()).objectEntries)({ a: 1, b: 2 })).toEqual([['a', 1], ['b', 2]]); }); it('errors for null', () => { - expect(() => objectEntries((null: any))).toThrow(); + expect(() => (0, (_collection || _load_collection()).objectEntries)(null)).toThrow(); }); it('errors for undefined', () => { - expect(() => objectEntries((null: any))).toThrow(); + expect(() => (0, (_collection || _load_collection()).objectEntries)(null)).toThrow(); }); it('only includes own properties', () => { - const a = {a: 1}; - const b = {b: 2}; + const a = { a: 1 }; + const b = { b: 2 }; Object.setPrototypeOf(b, a); - expect(objectEntries(b)).toEqual([['b', 2]]); + expect((0, (_collection || _load_collection()).objectEntries)(b)).toEqual([['b', 2]]); }); }); describe('objectFromMap', () => { it('converts a map to an object', () => { - expect(objectFromMap(new Map([['a', 1], ['b', 2]]))).toEqual({a: 1, b: 2}); + expect((0, (_collection || _load_collection()).objectFromMap)(new Map([['a', 1], ['b', 2]]))).toEqual({ a: 1, b: 2 }); }); }); describe('concatIterators', () => { it('concatenates different iterable stuff to a single iterator', () => { - expect( - Array.from( - concatIterators( - new Set([1, 2, 3]), - [4, 5, 6], - new Set([7, 8, 9]).values(), - ), - ), - ).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); + expect(Array.from((0, (_collection || _load_collection()).concatIterators)(new Set([1, 2, 3]), [4, 5, 6], new Set([7, 8, 9]).values()))).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); }); }); describe('areSetsEqual', () => { it('correctly compares empty sets', () => { - expect(areSetsEqual(new Set(), new Set())).toBe(true); + expect((0, (_collection || _load_collection()).areSetsEqual)(new Set(), new Set())).toBe(true); }); it('correctly compares sets with the same properties', () => { - expect(areSetsEqual(new Set(['foo']), new Set(['foo']))).toBe(true); + expect((0, (_collection || _load_collection()).areSetsEqual)(new Set(['foo']), new Set(['foo']))).toBe(true); }); it('returns false when properties are not equal', () => { - expect(areSetsEqual(new Set(['foo']), new Set(['bar']))).toBe(false); + expect((0, (_collection || _load_collection()).areSetsEqual)(new Set(['foo']), new Set(['bar']))).toBe(false); }); it('returns false when an item exists in one set but not the other', () => { - expect(areSetsEqual(new Set(['foo']), new Set())).toBe(false); - expect(areSetsEqual(new Set(), new Set(['foo']))).toBe(false); + expect((0, (_collection || _load_collection()).areSetsEqual)(new Set(['foo']), new Set())).toBe(false); + expect((0, (_collection || _load_collection()).areSetsEqual)(new Set(), new Set(['foo']))).toBe(false); }); }); describe('someOfIterable', () => { it('lazily returns whether any element of an iterable fulfills a given predicate', () => { - expect( - someOfIterable(new Set([1, 2, 3, 4, 5]), element => element % 2 === 0), - ).toEqual(true); - expect( - someOfIterable(new Set([1, 2, 3, 4, 5]), element => element % 5 === 0), - ).toEqual(true); - expect( - someOfIterable(new Set([1, 2, 3, 4, 5]), element => element % 6 === 0), - ).toEqual(false); - expect(someOfIterable([], element => true)).toEqual(false); + expect((0, (_collection || _load_collection()).someOfIterable)(new Set([1, 2, 3, 4, 5]), element => element % 2 === 0)).toEqual(true); + expect((0, (_collection || _load_collection()).someOfIterable)(new Set([1, 2, 3, 4, 5]), element => element % 5 === 0)).toEqual(true); + expect((0, (_collection || _load_collection()).someOfIterable)(new Set([1, 2, 3, 4, 5]), element => element % 6 === 0)).toEqual(false); + expect((0, (_collection || _load_collection()).someOfIterable)([], element => true)).toEqual(false); }); }); describe('findInIterable', () => { it('return the first element of an iterable which fulfills a given predicate', () => { - expect( - findInIterable(new Set([1, 2, 3, 4, 5]), element => element % 2 === 0), - ).toEqual(2); - expect( - findInIterable(new Set([1, 2, 3, 4, 5]), element => element % 5 === 0), - ).toEqual(5); - expect( - findInIterable(new Set([1, 2, 3, 4, 5]), element => element % 6 === 0), - ).toEqual(null); - expect(findInIterable([], element => true)).toEqual(null); + expect((0, (_collection || _load_collection()).findInIterable)(new Set([1, 2, 3, 4, 5]), element => element % 2 === 0)).toEqual(2); + expect((0, (_collection || _load_collection()).findInIterable)(new Set([1, 2, 3, 4, 5]), element => element % 5 === 0)).toEqual(5); + expect((0, (_collection || _load_collection()).findInIterable)(new Set([1, 2, 3, 4, 5]), element => element % 6 === 0)).toEqual(null); + expect((0, (_collection || _load_collection()).findInIterable)([], element => true)).toEqual(null); }); }); describe('filterIterable', () => { it('returns a (lazy) iterable containing all elements which fulfill the given predicate', () => { - expect( - Array.from( - filterIterable(new Set([1, 2, 3, 4, 5]), element => element % 2 === 0), - ), - ).toEqual([2, 4]); - expect( - Array.from(filterIterable(new Set([1, 2, 3, 4, 5]), element => true)), - ).toEqual([1, 2, 3, 4, 5]); - expect( - Array.from(filterIterable(new Set([1, 2, 3, 4, 5]), element => false)), - ).toEqual([]); - expect(Array.from(filterIterable([], element => true))).toEqual([]); + expect(Array.from((0, (_collection || _load_collection()).filterIterable)(new Set([1, 2, 3, 4, 5]), element => element % 2 === 0))).toEqual([2, 4]); + expect(Array.from((0, (_collection || _load_collection()).filterIterable)(new Set([1, 2, 3, 4, 5]), element => true))).toEqual([1, 2, 3, 4, 5]); + expect(Array.from((0, (_collection || _load_collection()).filterIterable)(new Set([1, 2, 3, 4, 5]), element => false))).toEqual([]); + expect(Array.from((0, (_collection || _load_collection()).filterIterable)([], element => true))).toEqual([]); }); }); describe('takeIterable', () => { it('returns a (lazy) iterable containing the first n elements', () => { - expect( - Array.from(takeIterable(new Set([1, 2, 3, 4, 5]), 3)).length, - ).toEqual(3); - expect(Array.from(takeIterable([1, 2, 3], 0)).length).toEqual(0); - expect(Array.from(takeIterable([1, 2, 3], 1)).length).toEqual(1); - expect(Array.from(takeIterable([1, 2, 3], 2)).length).toEqual(2); - expect(Array.from(takeIterable([1, 2, 3], 3)).length).toEqual(3); - expect(Array.from(takeIterable([1, 2, 3], 4)).length).toEqual(3); + expect(Array.from((0, (_collection || _load_collection()).takeIterable)(new Set([1, 2, 3, 4, 5]), 3)).length).toEqual(3); + expect(Array.from((0, (_collection || _load_collection()).takeIterable)([1, 2, 3], 0)).length).toEqual(0); + expect(Array.from((0, (_collection || _load_collection()).takeIterable)([1, 2, 3], 1)).length).toEqual(1); + expect(Array.from((0, (_collection || _load_collection()).takeIterable)([1, 2, 3], 2)).length).toEqual(2); + expect(Array.from((0, (_collection || _load_collection()).takeIterable)([1, 2, 3], 3)).length).toEqual(3); + expect(Array.from((0, (_collection || _load_collection()).takeIterable)([1, 2, 3], 4)).length).toEqual(3); }); }); describe('mapEqual', () => { it('checks primary elements', () => { - expect( - mapEqual( - new Map([[1, true], [2, false], [5, true]]), - new Map([[1, true], [2, false], [5, true]]), - ), - ).toBe(true); - expect(mapEqual(new Map([[1, true]]), new Map([[1, false]]))).toBe(false); - expect(mapEqual(new Map([[1, true]]), new Map([]))).toBe(false); - expect(mapEqual(new Map([[1, true]]), new Map([[2, false]]))).toBe(false); + expect((0, (_collection || _load_collection()).mapEqual)(new Map([[1, true], [2, false], [5, true]]), new Map([[1, true], [2, false], [5, true]]))).toBe(true); + expect((0, (_collection || _load_collection()).mapEqual)(new Map([[1, true]]), new Map([[1, false]]))).toBe(false); + expect((0, (_collection || _load_collection()).mapEqual)(new Map([[1, true]]), new Map([]))).toBe(false); + expect((0, (_collection || _load_collection()).mapEqual)(new Map([[1, true]]), new Map([[2, false]]))).toBe(false); }); it('checks object value elements', () => { - expect(mapEqual(new Map([[1, {x: 1}]]), new Map([[1, {x: 1}]]))).toBe( - false, - ); - expect( - mapEqual( - new Map([[1, {x: 1}]]), - new Map([[1, {x: 1}]]), - (v1, v2) => v1.x === v2.x, - ), - ).toBe(true); + expect((0, (_collection || _load_collection()).mapEqual)(new Map([[1, { x: 1 }]]), new Map([[1, { x: 1 }]]))).toBe(false); + expect((0, (_collection || _load_collection()).mapEqual)(new Map([[1, { x: 1 }]]), new Map([[1, { x: 1 }]]), (v1, v2) => v1.x === v2.x)).toBe(true); }); }); describe('mapIterable', () => { it('projects each element of an iterable into a new iterable', () => { - expect(Array.from(mapIterable(new Set(), element => true))).toEqual([]); - expect( - Array.from( - mapIterable(new Set([1, 2, 3, 4, 5]), element => element * element), - ), - ).toEqual([1, 4, 9, 16, 25]); + expect(Array.from((0, (_collection || _load_collection()).mapIterable)(new Set(), element => true))).toEqual([]); + expect(Array.from((0, (_collection || _load_collection()).mapIterable)(new Set([1, 2, 3, 4, 5]), element => element * element))).toEqual([1, 4, 9, 16, 25]); }); }); describe('mapGetWithDefault', () => { it('normally returns whatever is in the map', () => { - expect(mapGetWithDefault(new Map([[1, 2]]), 1, 3)).toBe(2); + expect((0, (_collection || _load_collection()).mapGetWithDefault)(new Map([[1, 2]]), 1, 3)).toBe(2); }); it('returns the default if the key is not in the map', () => { - expect(mapGetWithDefault(new Map([[1, 2]]), 5, 3)).toBe(3); + expect((0, (_collection || _load_collection()).mapGetWithDefault)(new Map([[1, 2]]), 5, 3)).toBe(3); }); it('returns `null` or `undefined` if they are values in the map', () => { - expect(mapGetWithDefault(new Map([[1, null]]), 1, 3)).toBeNull(); - expect(mapGetWithDefault(new Map([[1, undefined]]), 1, 3)).toBeUndefined(); + expect((0, (_collection || _load_collection()).mapGetWithDefault)(new Map([[1, null]]), 1, 3)).toBeNull(); + expect((0, (_collection || _load_collection()).mapGetWithDefault)(new Map([[1, undefined]]), 1, 3)).toBeUndefined(); }); }); describe('count', () => { it('returns how many values are in an iterable', () => { - expect(count([1, 2])).toBe(2); + expect((0, (_collection || _load_collection()).count)([1, 2])).toBe(2); }); }); describe('insideOut', () => { it('traverses correctly', () => { - expect([...insideOut([])]).toEqual([]); - expect([...insideOut(['a'])]).toEqual([['a', 0]]); - expect([...insideOut(['a', 'b'])]).toEqual([['b', 1], ['a', 0]]); - expect([...insideOut(['a', 'b', 'c'])]).toEqual([ - ['b', 1], - ['a', 0], - ['c', 2], - ]); - expect([...insideOut(['a', 'b', 'c', 'd'])]).toEqual([ - ['c', 2], - ['b', 1], - ['d', 3], - ['a', 0], - ]); + expect([...(0, (_collection || _load_collection()).insideOut)([])]).toEqual([]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a'])]).toEqual([['a', 0]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b'])]).toEqual([['b', 1], ['a', 0]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c'])]).toEqual([['b', 1], ['a', 0], ['c', 2]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c', 'd'])]).toEqual([['c', 2], ['b', 1], ['d', 3], ['a', 0]]); }); it('traverses correctly with an index', () => { - expect([...insideOut([], 99)]).toEqual([]); - expect([...insideOut(['a'], 99)]).toEqual([['a', 0]]); - expect([...insideOut(['a', 'b'], 99)]).toEqual([['b', 1], ['a', 0]]); - expect([...insideOut(['a', 'b', 'c'], 99)]).toEqual([ - ['c', 2], - ['b', 1], - ['a', 0], - ]); - - expect([...insideOut([], -99)]).toEqual([]); - expect([...insideOut(['a'], -99)]).toEqual([['a', 0]]); - expect([...insideOut(['a', 'b'], -99)]).toEqual([['a', 0], ['b', 1]]); - expect([...insideOut(['a', 'b', 'c'], -99)]).toEqual([ - ['a', 0], - ['b', 1], - ['c', 2], - ]); - - expect([...insideOut(['a', 'b'], 1)]).toEqual([['b', 1], ['a', 0]]); - expect([...insideOut(['a', 'b'], 0)]).toEqual([['a', 0], ['b', 1]]); - - expect([...insideOut(['a', 'b', 'c'], 1)]).toEqual([ - ['b', 1], - ['a', 0], - ['c', 2], - ]); - expect([...insideOut(['a', 'b', 'c', 'd'], 1)]).toEqual([ - ['b', 1], - ['a', 0], - ['c', 2], - ['d', 3], - ]); - expect([...insideOut(['a', 'b', 'c', 'd'], 2)]).toEqual([ - ['c', 2], - ['b', 1], - ['d', 3], - ['a', 0], - ]); + expect([...(0, (_collection || _load_collection()).insideOut)([], 99)]).toEqual([]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a'], 99)]).toEqual([['a', 0]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b'], 99)]).toEqual([['b', 1], ['a', 0]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c'], 99)]).toEqual([['c', 2], ['b', 1], ['a', 0]]); + + expect([...(0, (_collection || _load_collection()).insideOut)([], -99)]).toEqual([]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a'], -99)]).toEqual([['a', 0]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b'], -99)]).toEqual([['a', 0], ['b', 1]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c'], -99)]).toEqual([['a', 0], ['b', 1], ['c', 2]]); + + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b'], 1)]).toEqual([['b', 1], ['a', 0]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b'], 0)]).toEqual([['a', 0], ['b', 1]]); + + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c'], 1)]).toEqual([['b', 1], ['a', 0], ['c', 2]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c', 'd'], 1)]).toEqual([['b', 1], ['a', 0], ['c', 2], ['d', 3]]); + expect([...(0, (_collection || _load_collection()).insideOut)(['a', 'b', 'c', 'd'], 2)]).toEqual([['c', 2], ['b', 1], ['d', 3], ['a', 0]]); }); }); describe('range', () => { it('includes the start value, but not the stop value', () => { - expect([...range(1, 4)]).toEqual([1, 2, 3]); + expect([...(0, (_collection || _load_collection()).range)(1, 4)]).toEqual([1, 2, 3]); }); it('is empty if stop is less than, or equal to, start', () => { - expect([...range(2, 1)]).toEqual([]); - expect([...range(1, 1)]).toEqual([]); + expect([...(0, (_collection || _load_collection()).range)(2, 1)]).toEqual([]); + expect([...(0, (_collection || _load_collection()).range)(1, 1)]).toEqual([]); }); }); @@ -658,37 +522,33 @@ describe('objectFromPairs', () => { yield ['a', 1]; yield ['b', 2]; } - expect(objectFromPairs(gen())).toEqual({a: 1, b: 2}); + expect((0, (_collection || _load_collection()).objectFromPairs)(gen())).toEqual({ a: 1, b: 2 }); }); }); describe('objectMapValues', () => { it('maps values', () => { - const mapped = objectMapValues({a: 1, b: 2}, v => v + 1); - expect(mapped).toEqual({a: 2, b: 3}); + const mapped = (0, (_collection || _load_collection()).objectMapValues)({ a: 1, b: 2 }, v => v + 1); + expect(mapped).toEqual({ a: 2, b: 3 }); }); it('can project keys too', () => { - const mapped = objectMapValues({a: 1, b: 2}, (v, k) => k); - expect(mapped).toEqual({a: 'a', b: 'b'}); + const mapped = (0, (_collection || _load_collection()).objectMapValues)({ a: 1, b: 2 }, (v, k) => k); + expect(mapped).toEqual({ a: 'a', b: 'b' }); }); }); describe('mapFromObject', () => { it('converts a object to an map', () => { - expect( - mapEqual(mapFromObject({a: 1, b: 2}), new Map([['a', 1], ['b', 2]])), - ).toEqual(true); + expect((0, (_collection || _load_collection()).mapEqual)((0, (_collection || _load_collection()).mapFromObject)({ a: 1, b: 2 }), new Map([['a', 1], ['b', 2]]))).toEqual(true); }); }); describe('distinct', () => { it('returns the unique values mapped (or keys)', () => { - expect(distinct([1, 2, 3])).toEqual([1, 2, 3]); - expect(distinct(['1', '2', '3'])).toEqual(['1', '2', '3']); - expect(distinct([1, 2, 3, 4], x => String(x % 2 === 0))).toEqual([1, 2]); - expect( - distinct([{x: 1}, {x: 2}, {x: 3}, {x: 4}, {x: 4}], o => String(o.x)), - ).toEqual([{x: 1}, {x: 2}, {x: 3}, {x: 4}]); + expect((0, (_collection || _load_collection()).distinct)([1, 2, 3])).toEqual([1, 2, 3]); + expect((0, (_collection || _load_collection()).distinct)(['1', '2', '3'])).toEqual(['1', '2', '3']); + expect((0, (_collection || _load_collection()).distinct)([1, 2, 3, 4], x => String(x % 2 === 0))).toEqual([1, 2]); + expect((0, (_collection || _load_collection()).distinct)([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }, { x: 4 }], o => String(o.x))).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/debounce-spec.js b/modules/nuclide-commons/spec/debounce-spec.js index 76328e1f..c108ad01 100644 --- a/modules/nuclide-commons/spec/debounce-spec.js +++ b/modules/nuclide-commons/spec/debounce-spec.js @@ -1,3 +1,13 @@ +'use strict'; + +var _debounce; + +function _load_debounce() { + return _debounce = _interopRequireDefault(require('../debounce')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,17 +16,14 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import invariant from 'assert'; -import debounce from '../debounce'; - describe('debounce()', () => { it('only calls function once after time advances', () => { - const timerCallback: any = jasmine.createSpy('timerCallback'); - const debouncedFunc = debounce(timerCallback, 100, false); + const timerCallback = jasmine.createSpy('timerCallback'); + const debouncedFunc = (0, (_debounce || _load_debounce()).default)(timerCallback, 100, false); debouncedFunc(); expect(timerCallback).not.toHaveBeenCalled(); @@ -26,8 +33,8 @@ describe('debounce()', () => { }); it('disposes', () => { - const timerCallback: any = jasmine.createSpy('timerCallback'); - const debouncedFunc = debounce(timerCallback, 100, false); + const timerCallback = jasmine.createSpy('timerCallback'); + const debouncedFunc = (0, (_debounce || _load_debounce()).default)(timerCallback, 100, false); debouncedFunc(); expect(timerCallback).not.toHaveBeenCalled(); @@ -39,8 +46,8 @@ describe('debounce()', () => { }); it('does not swallow flow types', () => { - const func = (a: string): number => 1; - const debounced = debounce(func, 0); + const func = a => 1; + const debounced = (0, (_debounce || _load_debounce()).default)(func, 0); const ret = debounced('bar'); // $FlowIgnore: func's first param should be a string. @@ -48,10 +55,14 @@ describe('debounce()', () => { expect(() => { // $FlowIgnore: debounce's return type is "maybe func's return" type. - (ret: number); + ret; // This is false because we haven't waited for the timer. - invariant(ret != null); - (ret: number); + + if (!(ret != null)) { + throw new Error('Invariant violation: "ret != null"'); + } + + ret; }).toThrow(); debounced.dispose(); @@ -61,4 +72,4 @@ describe('debounce()', () => { debounced.bar(); }).toThrow(); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/event-spec.js b/modules/nuclide-commons/spec/event-spec.js index d8d3ac12..c5e53d10 100644 --- a/modules/nuclide-commons/spec/event-spec.js +++ b/modules/nuclide-commons/spec/event-spec.js @@ -1,3 +1,17 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _events = _interopRequireDefault(require('events')); + +var _event; + +function _load_event() { + return _event = require('../event'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,21 +20,17 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import invariant from 'assert'; -import EventEmitter from 'events'; -import {attachEvent, observableFromSubscribeFunction} from '../event'; - describe('attachEvent', () => { describe('the returned disposable', () => { it("doesn't remove other listeners when disposed multiple times", () => { const foo = jasmine.createSpy('foo'); - const emitter = new EventEmitter(); - const d1 = attachEvent(emitter, 'event', foo); - attachEvent(emitter, 'event', foo); + const emitter = new _events.default(); + const d1 = (0, (_event || _load_event()).attachEvent)(emitter, 'event', foo); + (0, (_event || _load_event()).attachEvent)(emitter, 'event', foo); d1.dispose(); d1.dispose(); emitter.emit('event'); @@ -30,8 +40,8 @@ describe('attachEvent', () => { }); describe('observableFromSubscribeFunction', () => { - let callback: ?(item: number) => mixed; - let disposable: ?IDisposable; + let callback; + let disposable; // The subscribe function will put the given callback and the returned disposable in the variables // above for inspection. @@ -40,7 +50,7 @@ describe('observableFromSubscribeFunction', () => { disposable = { dispose() { callback = null; - }, + } }; spyOn(disposable, 'dispose').andCallThrough(); return disposable; @@ -52,31 +62,35 @@ describe('observableFromSubscribeFunction', () => { }); it('should not call the subscription function until the Observable is subscribed to', () => { - const observable = observableFromSubscribeFunction(subscribeFunction); + const observable = (0, (_event || _load_event()).observableFromSubscribeFunction)(subscribeFunction); expect(callback).toBeNull(); observable.subscribe(() => {}); expect(callback).not.toBeNull(); }); it('should send events to the observable stream', () => { - waitsForPromise(async () => { - const result = observableFromSubscribeFunction(subscribeFunction) - .take(2) - .toArray() - .toPromise(); - invariant(callback != null); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const result = (0, (_event || _load_event()).observableFromSubscribeFunction)(subscribeFunction).take(2).toArray().toPromise(); + + if (!(callback != null)) { + throw new Error('Invariant violation: "callback != null"'); + } + callback(1); callback(2); - expect(await result).toEqual([1, 2]); - }); + expect((yield result)).toEqual([1, 2]); + })); }); it('should properly unsubscribe and resubscribe', () => { - const observable = observableFromSubscribeFunction(subscribeFunction); + const observable = (0, (_event || _load_event()).observableFromSubscribeFunction)(subscribeFunction); let subscription = observable.subscribe(() => {}); expect(callback).not.toBeNull(); - invariant(disposable != null); + if (!(disposable != null)) { + throw new Error('Invariant violation: "disposable != null"'); + } + expect(disposable.dispose).not.toHaveBeenCalled(); subscription.unsubscribe(); expect(disposable.dispose).toHaveBeenCalled(); @@ -91,4 +105,4 @@ describe('observableFromSubscribeFunction', () => { subscription.unsubscribe(); expect(disposable.dispose).toHaveBeenCalled(); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/fixtures/symbol-definition-preview-sample.js b/modules/nuclide-commons/spec/fixtures/symbol-definition-preview-sample.js index 6536861e..b1bac58d 100644 --- a/modules/nuclide-commons/spec/fixtures/symbol-definition-preview-sample.js +++ b/modules/nuclide-commons/spec/fixtures/symbol-definition-preview-sample.js @@ -1,3 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.aSingleLineFunctionSignature = aSingleLineFunctionSignature; +exports.aMultiLineFunctionSignature = aMultiLineFunctionSignature; +exports.aPoorlyIndentedFunction = aPoorlyIndentedFunction; /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -5,7 +13,7 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. * - * @flow + * */ // license header above without @format // eslint-disable-next-line @@ -19,33 +27,17 @@ const A_MULTILINE_CONST = ` lines `; -type Something = { - name: string, - age?: number, -}; - -export function aSingleLineFunctionSignature() { +function aSingleLineFunctionSignature() { return A_CONSTANT + SOME_OTHER_CONSTANT; } -export function aMultiLineFunctionSignature( - aReallyReallyLongArgumentNameThatWouldRequireThisToBreakAcrossMultipleLines: Something, -): number { +function aMultiLineFunctionSignature(aReallyReallyLongArgumentNameThatWouldRequireThisToBreakAcrossMultipleLines) { return 97; } - export function aPoorlyIndentedFunction( -aReallyReallyLongArgumentNameThatWouldRequireThisToBreakAcrossMultipleLines: Something, -): number { +function aPoorlyIndentedFunction(aReallyReallyLongArgumentNameThatWouldRequireThisToBreakAcrossMultipleLines) { return 97; } -type SomethingComplex = { - properties: { - name: string, - age?: number, - }, -}; - -const foo: ?SomethingComplex = null; -foo; +const foo = null; +foo; \ No newline at end of file diff --git a/modules/nuclide-commons/spec/fixtures/throw.js b/modules/nuclide-commons/spec/fixtures/throw.js index 54c55e8c..1a0d1c85 100644 --- a/modules/nuclide-commons/spec/fixtures/throw.js +++ b/modules/nuclide-commons/spec/fixtures/throw.js @@ -1,3 +1,5 @@ +'use strict'; + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,8 +8,8 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -throw new Error('Errored!'); +throw new Error('Errored!'); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/fixtures/toBeMocked.js b/modules/nuclide-commons/spec/fixtures/toBeMocked.js index 009f7899..0f7dcd66 100644 --- a/modules/nuclide-commons/spec/fixtures/toBeMocked.js +++ b/modules/nuclide-commons/spec/fixtures/toBeMocked.js @@ -1,3 +1,9 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.importedFunction = importedFunction; /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,10 +12,10 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -export function importedFunction(arg: any): any { +function importedFunction(arg) { return 0; -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/spec/fixtures/toBeTested.js b/modules/nuclide-commons/spec/fixtures/toBeTested.js index 8eda9295..6ecdecad 100644 --- a/modules/nuclide-commons/spec/fixtures/toBeTested.js +++ b/modules/nuclide-commons/spec/fixtures/toBeTested.js @@ -1,17 +1,26 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import {importedFunction} from './toBeMocked'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.functionToTest = functionToTest; -export function functionToTest(): any { - return importedFunction(42); +var _toBeMocked; + +function _load_toBeMocked() { + return _toBeMocked = require('./toBeMocked'); } + +function functionToTest() { + return (0, (_toBeMocked || _load_toBeMocked()).importedFunction)(42); +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/fsPromise-spec.js b/modules/nuclide-commons/spec/fsPromise-spec.js index ac55ea42..2911f41a 100644 --- a/modules/nuclide-commons/spec/fsPromise-spec.js +++ b/modules/nuclide-commons/spec/fsPromise-spec.js @@ -1,212 +1,185 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import invariant from 'assert'; -import fs from 'fs'; -import temp from 'temp'; -import nuclideUri from '../nuclideUri'; -import fsPromise from '../fsPromise'; -import {generateFixture} from '../test-helpers'; - -temp.track(); +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _fs = _interopRequireDefault(require('fs')); + +var _temp; + +function _load_temp() { + return _temp = _interopRequireDefault(require('temp')); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('../nuclideUri')); +} + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('../fsPromise')); +} + +var _testHelpers; + +function _load_testHelpers() { + return _testHelpers = require('../test-helpers'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +(_temp || _load_temp()).default.track(); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('fsPromise test suite', () => { describe('findNearestFile()', () => { - let dirPath: string = (null: any); + let dirPath = null; beforeEach(() => { - waitsForPromise(async () => { - dirPath = await generateFixture( - 'nearest_test', - new Map([ - ['.some_file', 'just some file'], - ['nested_dir/.another_file', 'just another file'], - ]), - ); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + dirPath = yield (0, (_testHelpers || _load_testHelpers()).generateFixture)('nearest_test', new Map([['.some_file', 'just some file'], ['nested_dir/.another_file', 'just another file']])); + })); }); it('find the file if given the exact directory', () => { - waitsForPromise(async () => { - const foundPath = await fsPromise.findNearestFile( - '.some_file', - dirPath, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findNearestFile('.some_file', dirPath); expect(foundPath).toBe(dirPath); - }); + })); }); it('find the file if given a nested directory', () => { - waitsForPromise(async () => { - const foundPath = await fsPromise.findNearestFile( - '.some_file', - nuclideUri.join(dirPath, 'nested_dir'), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findNearestFile('.some_file', (_nuclideUri || _load_nuclideUri()).default.join(dirPath, 'nested_dir')); expect(foundPath).toBe(dirPath); - }); + })); }); it('does not find the file if not existing', () => { - waitsForPromise(async () => { - const foundPath = await fsPromise.findNearestFile( - 'non-existent.txt', - nuclideUri.join(dirPath, 'nested_dir'), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findNearestFile('non-existent.txt', (_nuclideUri || _load_nuclideUri()).default.join(dirPath, 'nested_dir')); expect(foundPath).toBe(null); - }); + })); }); }); describe('findFurthestFile()', () => { - let dirPath: string = (null: any); + let dirPath = null; beforeEach(() => { - waitsForPromise(async () => { - dirPath = await generateFixture( - 'furthest_test', - new Map([ - ['0/.some_file', 'just a file'], - ['0/1/.some_file', 'just b file'], - // Skip one file to test consecutive vs non-consecutive. - // ['0/1/2', 'just c file'], - ['0/1/2/3/.some_file', 'just d file'], - ['0/1/2/3/4/.some_file', 'just f file'], - ]), - ); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + dirPath = yield (0, (_testHelpers || _load_testHelpers()).generateFixture)('furthest_test', new Map([['0/.some_file', 'just a file'], ['0/1/.some_file', 'just b file'], + // Skip one file to test consecutive vs non-consecutive. + // ['0/1/2', 'just c file'], + ['0/1/2/3/.some_file', 'just d file'], ['0/1/2/3/4/.some_file', 'just f file']])); + })); }); it('find the file if given the exact directory', () => { - waitsForPromise(async () => { - const expectedPath = nuclideUri.join(dirPath, '0'); - const foundPath = await fsPromise.findFurthestFile( - '.some_file', - expectedPath, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const expectedPath = (_nuclideUri || _load_nuclideUri()).default.join(dirPath, '0'); + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findFurthestFile('.some_file', expectedPath); expect(foundPath).toBe(expectedPath); - }); + })); }); it('finds the furthest file if given a nested directory', () => { - waitsForPromise(async () => { - const expectedPath = nuclideUri.join(dirPath, '0'); - const startPath = nuclideUri.join(dirPath, '0/1/2/3/4'); - const foundPath = await fsPromise.findFurthestFile( - '.some_file', - startPath, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const expectedPath = (_nuclideUri || _load_nuclideUri()).default.join(dirPath, '0'); + const startPath = (_nuclideUri || _load_nuclideUri()).default.join(dirPath, '0/1/2/3/4'); + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findFurthestFile('.some_file', startPath); expect(foundPath).toBe(expectedPath); - }); + })); }); it('terminates search as soon as file is not found if given the stopOnMissing flag', () => { - waitsForPromise(async () => { - const expectedPath = nuclideUri.join(dirPath, '0/1/2/3'); - const startPath = nuclideUri.join(dirPath, '0/1/2/3/4'); - const foundPath = await fsPromise.findFurthestFile( - '.some_file', - startPath, - true /* stopOnMissing */, + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const expectedPath = (_nuclideUri || _load_nuclideUri()).default.join(dirPath, '0/1/2/3'); + const startPath = (_nuclideUri || _load_nuclideUri()).default.join(dirPath, '0/1/2/3/4'); + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findFurthestFile('.some_file', startPath, true /* stopOnMissing */ ); expect(foundPath).toBe(expectedPath); - }); + })); }); it('does not find the file if not existing', () => { - waitsForPromise(async () => { - const startPath = nuclideUri.join(dirPath, '0/1/2/3/4'); - const foundPath = await fsPromise.findFurthestFile( - 'non-existent.txt', - startPath, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const startPath = (_nuclideUri || _load_nuclideUri()).default.join(dirPath, '0/1/2/3/4'); + const foundPath = yield (_fsPromise || _load_fsPromise()).default.findFurthestFile('non-existent.txt', startPath); expect(foundPath).toBe(null); - }); + })); }); }); describe('getCommonAncestorDirectory', () => { it('gets the parent directory', () => { - expect( - fsPromise.getCommonAncestorDirectory([ - '/foo/bar.txt', - '/foo/baz/lol.txt', - ]), - ).toBe('/foo'); - expect( - fsPromise.getCommonAncestorDirectory([ - '/foo/bar/abc/def/abc.txt', - '/foo/bar/lol.txt', - ]), - ).toBe('/foo/bar'); + expect((_fsPromise || _load_fsPromise()).default.getCommonAncestorDirectory(['/foo/bar.txt', '/foo/baz/lol.txt'])).toBe('/foo'); + expect((_fsPromise || _load_fsPromise()).default.getCommonAncestorDirectory(['/foo/bar/abc/def/abc.txt', '/foo/bar/lol.txt'])).toBe('/foo/bar'); }); }); describe('writeFileAtomic', () => { - let pathToWriteFile: string; + let pathToWriteFile; beforeEach(() => { - const tempDir = temp.mkdirSync(); - pathToWriteFile = nuclideUri.join(tempDir, 'test'); + const tempDir = (_temp || _load_temp()).default.mkdirSync(); + pathToWriteFile = (_nuclideUri || _load_nuclideUri()).default.join(tempDir, 'test'); }); it('can write to a file', () => { - waitsForPromise(async () => { - await fsPromise.writeFileAtomic( - pathToWriteFile, - "I'm a little teapot.\n", - ); - expect(fs.readFileSync(pathToWriteFile).toString()).toEqual( - "I'm a little teapot.\n", - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield (_fsPromise || _load_fsPromise()).default.writeFileAtomic(pathToWriteFile, "I'm a little teapot.\n"); + expect(_fs.default.readFileSync(pathToWriteFile).toString()).toEqual("I'm a little teapot.\n"); // eslint-disable-next-line no-bitwise - expect(fs.statSync(pathToWriteFile).mode & 0o777).toEqual( - 0o666 & ~process.umask(), // eslint-disable-line no-bitwise + expect(_fs.default.statSync(pathToWriteFile).mode & 0o777).toEqual(0o666 & ~process.umask() // eslint-disable-line no-bitwise ); - }); + })); }); it('calls mkdirp', () => { - waitsForPromise(async () => { - const subPath = nuclideUri.join(pathToWriteFile, 'test'); - await fsPromise.writeFileAtomic(subPath, 'test1234\n'); - expect(fs.readFileSync(subPath).toString()).toEqual('test1234\n'); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const subPath = (_nuclideUri || _load_nuclideUri()).default.join(pathToWriteFile, 'test'); + yield (_fsPromise || _load_fsPromise()).default.writeFileAtomic(subPath, 'test1234\n'); + expect(_fs.default.readFileSync(subPath).toString()).toEqual('test1234\n'); + })); }); it('preserves permissions on files', () => { - fs.writeFileSync(pathToWriteFile, 'test'); - fs.chmodSync(pathToWriteFile, 0o700); + _fs.default.writeFileSync(pathToWriteFile, 'test'); + _fs.default.chmodSync(pathToWriteFile, 0o700); - waitsForPromise(async () => { - await fsPromise.writeFileAtomic(pathToWriteFile, 'test2'); - expect(fs.readFileSync(pathToWriteFile).toString()).toEqual('test2'); - const stat = fs.statSync(pathToWriteFile); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield (_fsPromise || _load_fsPromise()).default.writeFileAtomic(pathToWriteFile, 'test2'); + expect(_fs.default.readFileSync(pathToWriteFile).toString()).toEqual('test2'); + const stat = _fs.default.statSync(pathToWriteFile); // eslint-disable-next-line no-bitwise expect(stat.mode & 0o777).toEqual(0o700); - }); + })); }); it('errors if file cannot be written', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let err; try { - await fsPromise.writeFileAtomic( - pathToWriteFile + '/that/is/missing/', - 'something', - ); + yield (_fsPromise || _load_fsPromise()).default.writeFileAtomic(pathToWriteFile + '/that/is/missing/', 'something'); } catch (e) { err = e; } - invariant(err != null, 'Expected an error'); - }); + + if (!(err != null)) { + throw new Error('Expected an error'); + } + })); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/humanizeKeystroke-spec.js b/modules/nuclide-commons/spec/humanizeKeystroke-spec.js index d9baa7e1..3a433588 100644 --- a/modules/nuclide-commons/spec/humanizeKeystroke-spec.js +++ b/modules/nuclide-commons/spec/humanizeKeystroke-spec.js @@ -1,96 +1,88 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import humanizeKeystroke from '../humanizeKeystroke'; +'use strict'; + +var _humanizeKeystroke; + +function _load_humanizeKeystroke() { + return _humanizeKeystroke = _interopRequireDefault(require('../humanizeKeystroke')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('nuclide-keystroke-label', () => { // adapted from https://github.com/atom/underscore-plus/blob/master/spec/underscore-plus-spec.coffee describe('humanizeKeystroke', () => { it('replaces single keystroke', () => { - expect(humanizeKeystroke('cmd-O', 'darwin')).toEqual('⌘⇧O'); - expect(humanizeKeystroke('cmd-O', 'linux')).toEqual('Cmd+Shift+O'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-O', 'darwin')).toEqual('⌘⇧O'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-O', 'linux')).toEqual('Cmd+Shift+O'); - expect(humanizeKeystroke('cmd-shift-up', 'darwin')).toEqual('⌘⇧↑'); - expect(humanizeKeystroke('cmd-shift-up', 'linux')).toEqual( - 'Cmd+Shift+Up', - ); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-shift-up', 'darwin')).toEqual('⌘⇧↑'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-shift-up', 'linux')).toEqual('Cmd+Shift+Up'); - expect(humanizeKeystroke('cmd-option-down', 'darwin')).toEqual('⌘⌥↓'); - expect(humanizeKeystroke('cmd-option-down', 'linux')).toEqual( - 'Cmd+Alt+Down', - ); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-option-down', 'darwin')).toEqual('⌘⌥↓'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-option-down', 'linux')).toEqual('Cmd+Alt+Down'); - expect(humanizeKeystroke('cmd-option-left', 'darwin')).toEqual('⌘⌥←'); - expect(humanizeKeystroke('cmd-option-left', 'linux')).toEqual( - 'Cmd+Alt+Left', - ); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-option-left', 'darwin')).toEqual('⌘⌥←'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-option-left', 'linux')).toEqual('Cmd+Alt+Left'); - expect(humanizeKeystroke('cmd-option-right', 'darwin')).toEqual('⌘⌥→'); - expect(humanizeKeystroke('cmd-option-right', 'linux')).toEqual( - 'Cmd+Alt+Right', - ); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-option-right', 'darwin')).toEqual('⌘⌥→'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-option-right', 'linux')).toEqual('Cmd+Alt+Right'); - expect(humanizeKeystroke('cmd-o', 'darwin')).toEqual('⌘O'); - expect(humanizeKeystroke('cmd-o', 'linux')).toEqual('Cmd+O'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-o', 'darwin')).toEqual('⌘O'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-o', 'linux')).toEqual('Cmd+O'); - expect(humanizeKeystroke('ctrl-2', 'darwin')).toEqual('⌃2'); - expect(humanizeKeystroke('ctrl-2', 'linux')).toEqual('Ctrl+2'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('ctrl-2', 'darwin')).toEqual('⌃2'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('ctrl-2', 'linux')).toEqual('Ctrl+2'); - expect(humanizeKeystroke('cmd-space', 'darwin')).toEqual('⌘space'); - expect(humanizeKeystroke('cmd-space', 'linux')).toEqual('Cmd+Space'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-space', 'darwin')).toEqual('⌘space'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-space', 'linux')).toEqual('Cmd+Space'); - expect(humanizeKeystroke('cmd-|', 'darwin')).toEqual('⌘⇧\\'); - expect(humanizeKeystroke('cmd-|', 'linux')).toEqual('Cmd+Shift+\\'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-|', 'darwin')).toEqual('⌘⇧\\'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-|', 'linux')).toEqual('Cmd+Shift+\\'); - expect(humanizeKeystroke('cmd-}', 'darwin')).toEqual('⌘⇧]'); - expect(humanizeKeystroke('cmd-}', 'linux')).toEqual('Cmd+Shift+]'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-}', 'darwin')).toEqual('⌘⇧]'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-}', 'linux')).toEqual('Cmd+Shift+]'); - expect(humanizeKeystroke('cmd--', 'darwin')).toEqual('⌘-'); - expect(humanizeKeystroke('cmd--', 'linux')).toEqual('Cmd+-'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd--', 'darwin')).toEqual('⌘-'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd--', 'linux')).toEqual('Cmd+-'); }); it('correctly replaces keystrokes with shift and capital letter', () => { - expect(humanizeKeystroke('cmd-shift-P', 'darwin')).toEqual('⌘⇧P'); - expect(humanizeKeystroke('cmd-shift-P', 'linux')).toEqual('Cmd+Shift+P'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-shift-P', 'darwin')).toEqual('⌘⇧P'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-shift-P', 'linux')).toEqual('Cmd+Shift+P'); }); it('replaces multiple keystrokes', () => { - expect(humanizeKeystroke('cmd-O cmd-n', 'darwin')).toEqual('⌘⇧O ⌘N'); - expect(humanizeKeystroke('cmd-O cmd-n', 'linux')).toEqual( - 'Cmd+Shift+O Cmd+N', - ); - - expect(humanizeKeystroke('cmd-shift-- cmd-n', 'darwin')).toEqual( - '⌘⇧- ⌘N', - ); - expect(humanizeKeystroke('cmd-shift-- cmd-n', 'linux')).toEqual( - 'Cmd+Shift+- Cmd+N', - ); - - expect(humanizeKeystroke('cmd-k right', 'darwin')).toEqual('⌘K →'); - expect(humanizeKeystroke('cmd-k right', 'linux')).toEqual('Cmd+K Right'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-O cmd-n', 'darwin')).toEqual('⌘⇧O ⌘N'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-O cmd-n', 'linux')).toEqual('Cmd+Shift+O Cmd+N'); + + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-shift-- cmd-n', 'darwin')).toEqual('⌘⇧- ⌘N'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-shift-- cmd-n', 'linux')).toEqual('Cmd+Shift+- Cmd+N'); + + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-k right', 'darwin')).toEqual('⌘K →'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-k right', 'linux')).toEqual('Cmd+K Right'); }); it('formats function keys', () => { - expect(humanizeKeystroke('cmd-f2', 'darwin')).toEqual('⌘F2'); - expect(humanizeKeystroke('cmd-f2', 'linux')).toEqual('Cmd+F2'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-f2', 'darwin')).toEqual('⌘F2'); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('cmd-f2', 'linux')).toEqual('Cmd+F2'); }); it('handles junk input', () => { // $FlowFixMe: Deliberately testing invalid input. - expect(humanizeKeystroke()).toEqual(undefined); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)()).toEqual(undefined); // $FlowFixMe: Deliberately testing invalid input. - expect(humanizeKeystroke(null)).toEqual(null); - expect(humanizeKeystroke('')).toEqual(''); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)(null)).toEqual(null); + expect((0, (_humanizeKeystroke || _load_humanizeKeystroke()).default)('')).toEqual(''); }); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/matchIndexesToRanges-spec.js b/modules/nuclide-commons/spec/matchIndexesToRanges-spec.js index fc991d27..fc3cc4bb 100644 --- a/modules/nuclide-commons/spec/matchIndexesToRanges-spec.js +++ b/modules/nuclide-commons/spec/matchIndexesToRanges-spec.js @@ -1,31 +1,29 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import matchIndexesToRanges from '../matchIndexesToRanges'; +var _matchIndexesToRanges; + +function _load_matchIndexesToRanges() { + return _matchIndexesToRanges = _interopRequireDefault(require('../matchIndexesToRanges')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('matchIndexesToRanges', () => { it('makes single character ranges for nonconsecutive values at consecutive indexes', () => { - expect(matchIndexesToRanges([1, 3, 5, 7, 9])).toEqual([ - [1, 2], - [3, 4], - [5, 6], - [7, 8], - [9, 10], - ]); + expect((0, (_matchIndexesToRanges || _load_matchIndexesToRanges()).default)([1, 3, 5, 7, 9])).toEqual([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]); }); it('collapses consecutive values into ranges', () => { - expect( - matchIndexesToRanges([0, 1, 2, 3, 10, 11, 12, 20, 21, 22, 23, 24, 25]), - ).toEqual([[0, 4], [10, 13], [20, 26]]); + expect((0, (_matchIndexesToRanges || _load_matchIndexesToRanges()).default)([0, 1, 2, 3, 10, 11, 12, 20, 21, 22, 23, 24, 25])).toEqual([[0, 4], [10, 13], [20, 26]]); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/memoizeUntilChanged-spec.js b/modules/nuclide-commons/spec/memoizeUntilChanged-spec.js index 07d10ae9..06405835 100644 --- a/modules/nuclide-commons/spec/memoizeUntilChanged-spec.js +++ b/modules/nuclide-commons/spec/memoizeUntilChanged-spec.js @@ -1,23 +1,29 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import memoizeUntilChanged from '../memoizeUntilChanged'; +var _memoizeUntilChanged; -const sum = (a, b) => a + b; +function _load_memoizeUntilChanged() { + return _memoizeUntilChanged = _interopRequireDefault(require('../memoizeUntilChanged')); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const sum = (a, b) => a + b; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('memoizeUntilChanged', () => { it('memoizes', () => { const spy = jasmine.createSpy().andCallFake(sum); - const f = memoizeUntilChanged(spy); + const f = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(spy); f(1, 2); const result = f(1, 2); expect(result).toBe(3); @@ -26,7 +32,7 @@ describe('memoizeUntilChanged', () => { it('resets when args change', () => { const spy = jasmine.createSpy().andCallFake(sum); - const f = memoizeUntilChanged(spy); + const f = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(spy); f(1, 2); const result = f(1, 3); expect(result).toBe(4); @@ -36,7 +42,7 @@ describe('memoizeUntilChanged', () => { it('preserves context', () => { let that; const obj = {}; - const f = memoizeUntilChanged(function f() { + const f = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(function f() { that = this; }); f.call(obj); @@ -45,7 +51,7 @@ describe('memoizeUntilChanged', () => { it('uses all args when memoizing by default', () => { const spy = jasmine.createSpy().andCallFake(sum); - const f = memoizeUntilChanged(spy); + const f = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(spy); f(1, 2); const result = f(1, 3); expect(result).toBe(4); @@ -54,14 +60,12 @@ describe('memoizeUntilChanged', () => { it('uses the key selector and comparator', () => { const spy = jasmine.createSpy().andCallFake(sum); - const f = memoizeUntilChanged( - spy, - // A pretty poor keyselector that uses the sum of the arguments as the key. Lots of collisions - // here! - (x, y) => x + y, - // Compare numbers. - (a, b) => a === b, - ); + const f = (0, (_memoizeUntilChanged || _load_memoizeUntilChanged()).default)(spy, + // A pretty poor keyselector that uses the sum of the arguments as the key. Lots of collisions + // here! + (x, y) => x + y, + // Compare numbers. + (a, b) => a === b); f(1, 2); f(2, 1); f(0, 3); @@ -69,4 +73,4 @@ describe('memoizeUntilChanged', () => { f(0, 4); expect(spy.callCount).toBe(2); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/nice-spec.js b/modules/nuclide-commons/spec/nice-spec.js index 080b0a37..5f9a079b 100644 --- a/modules/nuclide-commons/spec/nice-spec.js +++ b/modules/nuclide-commons/spec/nice-spec.js @@ -1,112 +1,106 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import typeof {niceSafeSpawn as niceSafeSpawnType} from '../nice'; +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); -import {uncachedRequire} from '../test-helpers'; -import {Observable} from 'rxjs'; +var _testHelpers; + +function _load_testHelpers() { + return _testHelpers = require('../test-helpers'); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('nice', () => { - let niceSafeSpawn: niceSafeSpawnType = (null: any); + let niceSafeSpawn = null; - let whichSpy: JasmineSpy = (null: any); - let spawnSpy: JasmineSpy = (null: any); - let shouldFindNiceCommand: boolean = (null: any); - let shouldFindIoniceCommand: boolean = (null: any); + let whichSpy = null; + let spawnSpy = null; + let shouldFindNiceCommand = null; + let shouldFindIoniceCommand = null; // All we need here is a unique value to make sure that `nice` returns whatever `safeSpawn` // returns - const fakeSafeSpawnReturn: child_process$ChildProcess = ({}: any); + const fakeSafeSpawnReturn = {}; beforeEach(() => { shouldFindNiceCommand = true; shouldFindIoniceCommand = true; - whichSpy = spyOn(require('../which'), 'default').andCallFake( - async command => { - if ( - (shouldFindNiceCommand && command === 'nice') || - (shouldFindIoniceCommand && command === 'ionice') - ) { + whichSpy = spyOn(require('../which'), 'default').andCallFake((() => { + var _ref = (0, _asyncToGenerator.default)(function* (command) { + if (shouldFindNiceCommand && command === 'nice' || shouldFindIoniceCommand && command === 'ionice') { return command; } else { return null; } - }, - ); - spawnSpy = spyOn(require('../process'), 'spawn').andReturn( - Observable.of(fakeSafeSpawnReturn), - ); - ({niceSafeSpawn} = (uncachedRequire(require, '../nice'): any)); + }); + + return function (_x) { + return _ref.apply(this, arguments); + }; + })()); + spawnSpy = spyOn(require('../process'), 'spawn').andReturn(_rxjsBundlesRxMinJs.Observable.of(fakeSafeSpawnReturn)); + ({ niceSafeSpawn } = (0, (_testHelpers || _load_testHelpers()).uncachedRequire)(require, '../nice')); }); it('should spawn `nice` and return whatever spawn returns', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const execOptions = {}; - const result = await niceSafeSpawn('echo', ['hi'], execOptions); - expect(spawnSpy).toHaveBeenCalledWith( - 'ionice', - ['-n', '7', 'nice', 'echo', 'hi'], - execOptions, - ); + const result = yield niceSafeSpawn('echo', ['hi'], execOptions); + expect(spawnSpy).toHaveBeenCalledWith('ionice', ['-n', '7', 'nice', 'echo', 'hi'], execOptions); expect(result).toBe(fakeSafeSpawnReturn); - }); + })); }); it('should spawn the command normally if nice and ionice cannot be found', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { shouldFindNiceCommand = false; shouldFindIoniceCommand = false; const execOptions = {}; - const result = await niceSafeSpawn('echo', ['hi'], execOptions); + const result = yield niceSafeSpawn('echo', ['hi'], execOptions); expect(spawnSpy).toHaveBeenCalledWith('echo', ['hi'], execOptions); expect(result).toBe(fakeSafeSpawnReturn); - }); + })); }); it('should spawn with only nice if ionice cannot be found', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { shouldFindIoniceCommand = false; const execOptions = {}; - const result = await niceSafeSpawn('echo', ['hi'], execOptions); - expect(spawnSpy).toHaveBeenCalledWith( - 'nice', - ['echo', 'hi'], - execOptions, - ); + const result = yield niceSafeSpawn('echo', ['hi'], execOptions); + expect(spawnSpy).toHaveBeenCalledWith('nice', ['echo', 'hi'], execOptions); expect(result).toBe(fakeSafeSpawnReturn); - }); + })); }); it('should spawn with only ionice if nice cannot be found', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { // I don't know when we would have ionice but not nice, but we may as well support this case. shouldFindNiceCommand = false; const execOptions = {}; - const result = await niceSafeSpawn('echo', ['hi'], execOptions); - expect(spawnSpy).toHaveBeenCalledWith( - 'ionice', - ['-n', '7', 'echo', 'hi'], - execOptions, - ); + const result = yield niceSafeSpawn('echo', ['hi'], execOptions); + expect(spawnSpy).toHaveBeenCalledWith('ionice', ['-n', '7', 'echo', 'hi'], execOptions); expect(result).toBe(fakeSafeSpawnReturn); - }); + })); }); it('should call which only once per command and cache the result', () => { - waitsForPromise(async () => { - await niceSafeSpawn('echo', []); - await niceSafeSpawn('echo', []); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield niceSafeSpawn('echo', []); + yield niceSafeSpawn('echo', []); expect(whichSpy).toHaveBeenCalledWith('nice'); expect(whichSpy).toHaveBeenCalledWith('ionice'); expect(whichSpy.callCount).toBe(2); - }); + })); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/nuclideUri-spec.js b/modules/nuclide-commons/spec/nuclideUri-spec.js index af87092c..479be641 100644 --- a/modules/nuclide-commons/spec/nuclideUri-spec.js +++ b/modules/nuclide-commons/spec/nuclideUri-spec.js @@ -1,3 +1,21 @@ +'use strict'; + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('../nuclideUri')); +} + +var _nuclideUri2; + +function _load_nuclideUri2() { + return _nuclideUri2 = require('../nuclideUri'); +} + +var _path = _interopRequireDefault(require('path')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,49 +24,39 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import nuclideUri, {__TEST__} from '../nuclideUri'; -// eslint-disable-next-line rulesdir/prefer-nuclide-uri -import path from 'path'; - describe('nuclide-uri', () => { const localUri = '/usr/local/file'; const badRemoteUriNoPath = 'nuclide://fb.com'; const atomUri = 'atom://bla/bla'; - const remoteUri = nuclideUri.createRemoteUri('fb.com', '/usr/local'); - const remoteUriWithSpaces = nuclideUri.createRemoteUri('fb.com', '/a b/c d'); - const remoteUriWithHashes = nuclideUri.createRemoteUri( - 'fb.co.uk', - '/ab/#c.d #', - ); + const remoteUri = (_nuclideUri || _load_nuclideUri()).default.createRemoteUri('fb.com', '/usr/local'); + const remoteUriWithSpaces = (_nuclideUri || _load_nuclideUri()).default.createRemoteUri('fb.com', '/a b/c d'); + const remoteUriWithHashes = (_nuclideUri || _load_nuclideUri()).default.createRemoteUri('fb.co.uk', '/ab/#c.d #'); const localArchiveUri = '/etc/file.zip!a'; - const remoteArchiveUri = nuclideUri.createRemoteUri( - 'fb.com', - '/file.zip!a.txt', - ); + const remoteArchiveUri = (_nuclideUri || _load_nuclideUri()).default.createRemoteUri('fb.com', '/file.zip!a.txt'); const endsWithExclamationUri = '/module/!! WARNING !!'; const archiveSuffixUri = '/etc/file.zip!'; it('isRemote', () => { - expect(nuclideUri.isRemote('/')).toBe(false); - expect(nuclideUri.isRemote(remoteUri)).toBe(true); - expect(nuclideUri.isRemote(atomUri)).toBe(false); - expect(nuclideUri.isRemote(localArchiveUri)).toBe(false); - expect(nuclideUri.isRemote(remoteArchiveUri)).toBe(true); - expect(nuclideUri.isRemote(endsWithExclamationUri)).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isRemote('/')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isRemote(remoteUri)).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isRemote(atomUri)).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isRemote(localArchiveUri)).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isRemote(remoteArchiveUri)).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isRemote(endsWithExclamationUri)).toBe(false); }); it('isLocal', () => { - expect(nuclideUri.isLocal('/')).toBe(true); - expect(nuclideUri.isLocal(remoteUri)).toBe(false); - expect(nuclideUri.isLocal('C:\\abc')).toBe(true); - expect(nuclideUri.isLocal(atomUri)).toBe(false); - expect(nuclideUri.isLocal(localArchiveUri)).toBe(true); - expect(nuclideUri.isLocal(remoteArchiveUri)).toBe(false); - expect(nuclideUri.isLocal(endsWithExclamationUri)).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal('/')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal(remoteUri)).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal('C:\\abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal(atomUri)).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal(localArchiveUri)).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal(remoteArchiveUri)).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isLocal(endsWithExclamationUri)).toBe(true); }); it('createRemoteUri', () => { @@ -58,710 +66,515 @@ describe('nuclide-uri', () => { }); it('join', () => { - expect(nuclideUri.join.bind(null, badRemoteUriNoPath, '../foo')).toThrow(); - expect(nuclideUri.join('/usr/local', 'bin')).toBe('/usr/local/bin'); - expect(nuclideUri.join(remoteUri, 'bin')).toBe( - 'nuclide://fb.com/usr/local/bin', - ); - expect(nuclideUri.join(localArchiveUri, 'b.txt')).toBe( - '/etc/file.zip!a/b.txt', - ); - expect(nuclideUri.join(endsWithExclamationUri, 'b.txt')).toBe( - '/module/!! WARNING !!/b.txt', - ); - expect(nuclideUri.join('/usr/local', '..')).toBe('/usr'); - expect(nuclideUri.join(remoteUri, '..')).toBe('nuclide://fb.com/usr'); - expect(() => nuclideUri.join(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.join.bind(null, badRemoteUriNoPath, '../foo')).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.join('/usr/local', 'bin')).toBe('/usr/local/bin'); + expect((_nuclideUri || _load_nuclideUri()).default.join(remoteUri, 'bin')).toBe('nuclide://fb.com/usr/local/bin'); + expect((_nuclideUri || _load_nuclideUri()).default.join(localArchiveUri, 'b.txt')).toBe('/etc/file.zip!a/b.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.join(endsWithExclamationUri, 'b.txt')).toBe('/module/!! WARNING !!/b.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.join('/usr/local', '..')).toBe('/usr'); + expect((_nuclideUri || _load_nuclideUri()).default.join(remoteUri, '..')).toBe('nuclide://fb.com/usr'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.join(archiveSuffixUri)).toThrow(); }); it('archiveJoin', () => { - expect(nuclideUri.archiveJoin('/file.zip', 'a.txt')).toBe( - '/file.zip!a.txt', - ); - expect(() => nuclideUri.archiveJoin(archiveSuffixUri, 'a.txt')).toThrow(); - expect(() => nuclideUri.archiveJoin('/dir', 'a.txt')).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.archiveJoin('/file.zip', 'a.txt')).toBe('/file.zip!a.txt'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.archiveJoin(archiveSuffixUri, 'a.txt')).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.archiveJoin('/dir', 'a.txt')).toThrow(); }); describe('parsing remote', () => { it('handles simple paths', () => { - expect(nuclideUri.getHostname(remoteUri)).toBe('fb.com'); - expect(nuclideUri.getPath(remoteUri)).toBe('/usr/local'); + expect((_nuclideUri || _load_nuclideUri()).default.getHostname(remoteUri)).toBe('fb.com'); + expect((_nuclideUri || _load_nuclideUri()).default.getPath(remoteUri)).toBe('/usr/local'); }); it('does not encode space characters', () => { - expect(nuclideUri.getHostname(remoteUriWithSpaces)).toBe('fb.com'); - expect(nuclideUri.getPath(remoteUriWithSpaces)).toBe('/a b/c d'); + expect((_nuclideUri || _load_nuclideUri()).default.getHostname(remoteUriWithSpaces)).toBe('fb.com'); + expect((_nuclideUri || _load_nuclideUri()).default.getPath(remoteUriWithSpaces)).toBe('/a b/c d'); }); it('treats hash symbols as literals, part of the path', () => { - const parsedUri = nuclideUri.parse(remoteUriWithHashes); + const parsedUri = (_nuclideUri || _load_nuclideUri()).default.parse(remoteUriWithHashes); expect(parsedUri.hostname).toBe('fb.co.uk'); expect(parsedUri.path).toBe('/ab/#c.d #'); }); it('throws when given an illegal URI', () => { - expect(() => nuclideUri.getHostname(archiveSuffixUri)).toThrow(); - expect(() => nuclideUri.getPath(archiveSuffixUri)).toThrow(); - expect(() => nuclideUri.parse(archiveSuffixUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.getHostname(archiveSuffixUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.getPath(archiveSuffixUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.parse(archiveSuffixUri)).toThrow(); }); }); it('parsing local', () => { - expect(() => nuclideUri.getHostname(localUri)).toThrow(); - expect(() => nuclideUri.getHostname(localArchiveUri)).toThrow(); - expect(nuclideUri.getPath(localUri)).toBe(localUri); - expect(nuclideUri.getPath(localArchiveUri)).toBe(localArchiveUri); - expect(nuclideUri.getPath(remoteArchiveUri)).toBe('/file.zip!a.txt'); - expect(nuclideUri.getPath(endsWithExclamationUri)).toBe( - endsWithExclamationUri, - ); - expect(() => nuclideUri.getPath('nuclide://host/archive.zip!')).toThrow(); - expect(() => nuclideUri.parseRemoteUri(localUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.getHostname(localUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.getHostname(localArchiveUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.getPath(localUri)).toBe(localUri); + expect((_nuclideUri || _load_nuclideUri()).default.getPath(localArchiveUri)).toBe(localArchiveUri); + expect((_nuclideUri || _load_nuclideUri()).default.getPath(remoteArchiveUri)).toBe('/file.zip!a.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.getPath(endsWithExclamationUri)).toBe(endsWithExclamationUri); + expect(() => (_nuclideUri || _load_nuclideUri()).default.getPath('nuclide://host/archive.zip!')).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.parseRemoteUri(localUri)).toThrow(); }); it('basename', () => { - expect(nuclideUri.basename('/')).toBe(''); - expect(nuclideUri.basename('/abc')).toBe('abc'); - expect(nuclideUri.basename('/abc/')).toBe('abc'); - expect(nuclideUri.basename('/abc/def')).toBe('def'); - expect(nuclideUri.basename('/abc/def/')).toBe('def'); - - expect(nuclideUri.basename('nuclide://host/')).toBe(''); - expect(nuclideUri.basename('nuclide://host/abc')).toBe('abc'); - expect(nuclideUri.basename('nuclide://host/abc/')).toBe('abc'); - expect(nuclideUri.basename('nuclide://host/abc/def')).toBe('def'); - expect(nuclideUri.basename('nuclide://host/abc/def/')).toBe('def'); - expect(nuclideUri.basename('nuclide://host/a c/d f')).toBe('d f'); - - expect(nuclideUri.basename('/z.zip!abc')).toBe('abc'); - expect(nuclideUri.basename('/z.zip!abc/')).toBe('abc'); - expect(nuclideUri.basename('/z.zip!abc/def')).toBe('def'); - expect(nuclideUri.basename('/abc/def!ghi')).toBe('def!ghi'); - expect(nuclideUri.basename('/abc/def.txt!ghi')).toBe('def.txt!ghi'); - - expect(nuclideUri.basename('nuclide://host/z.zip!abc')).toBe('abc'); - expect(nuclideUri.basename('nuclide://host/z.zip!abc/')).toBe('abc'); - expect(nuclideUri.basename('nuclide://host/z.zip!abc/def')).toBe('def'); - - expect(nuclideUri.basename('C:\\')).toBe(''); - expect(nuclideUri.basename('C:\\abc')).toBe('abc'); - expect(nuclideUri.basename('C:\\abc\\')).toBe('abc'); - expect(nuclideUri.basename('C:\\abc\\def')).toBe('def'); - expect(nuclideUri.basename('C:\\abc\\def\\')).toBe('def'); - expect(nuclideUri.basename('\\abc\\def')).toBe('def'); - expect(nuclideUri.basename('\\abc\\def\\')).toBe('def'); - - expect(nuclideUri.basename('C:\\z.zip!abc')).toBe('abc'); - expect(nuclideUri.basename('C:\\z.zip!abc\\')).toBe('abc'); - expect(nuclideUri.basename('C:\\z.zip!abc\\def')).toBe('def'); - expect(nuclideUri.basename('C:\\abc\\def!ghi')).toBe('def!ghi'); - expect(nuclideUri.basename('C:\\abc\\def.txt!ghi')).toBe('def.txt!ghi'); - expect(nuclideUri.basename('\\z.zip!abc')).toBe('abc'); - expect(nuclideUri.basename('\\z.zip!abc\\')).toBe('abc'); - expect(nuclideUri.basename('\\z.zip!abc\\def')).toBe('def'); - expect(nuclideUri.basename('\\abc\\def!ghi')).toBe('def!ghi'); - expect(nuclideUri.basename('\\abc\\def.txt!ghi')).toBe('def.txt!ghi'); - - expect(() => nuclideUri.basename(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/abc/')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/abc/def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/abc/def/')).toBe('def'); + + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/abc/')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/abc/def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/abc/def/')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/a c/d f')).toBe('d f'); + + expect((_nuclideUri || _load_nuclideUri()).default.basename('/z.zip!abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/z.zip!abc/')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/z.zip!abc/def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/abc/def!ghi')).toBe('def!ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('/abc/def.txt!ghi')).toBe('def.txt!ghi'); + + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/z.zip!abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/z.zip!abc/')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('nuclide://host/z.zip!abc/def')).toBe('def'); + + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\abc\\')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\abc\\def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\abc\\def\\')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\abc\\def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\abc\\def\\')).toBe('def'); + + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\z.zip!abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\z.zip!abc\\')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\z.zip!abc\\def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\abc\\def!ghi')).toBe('def!ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('C:\\abc\\def.txt!ghi')).toBe('def.txt!ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\z.zip!abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\z.zip!abc\\')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\z.zip!abc\\def')).toBe('def'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\abc\\def!ghi')).toBe('def!ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.basename('\\abc\\def.txt!ghi')).toBe('def.txt!ghi'); + + expect(() => (_nuclideUri || _load_nuclideUri()).default.basename(archiveSuffixUri)).toThrow(); }); it('dirname', () => { - expect(nuclideUri.dirname('/')).toBe('/'); - expect(nuclideUri.dirname('/abc')).toBe('/'); - expect(nuclideUri.dirname('/abc/')).toBe('/'); - expect(nuclideUri.dirname('/abc/def')).toBe('/abc'); - expect(nuclideUri.dirname('/abc/def/')).toBe('/abc'); - - expect(nuclideUri.dirname('nuclide://host/')).toBe('nuclide://host/'); - expect(nuclideUri.dirname('nuclide://host/abc')).toBe('nuclide://host/'); - expect(nuclideUri.dirname('nuclide://host/abc/')).toBe('nuclide://host/'); - expect(nuclideUri.dirname('nuclide://host/abc/def')).toBe( - 'nuclide://host/abc', - ); - expect(nuclideUri.dirname('nuclide://host/abc/def/')).toBe( - 'nuclide://host/abc', - ); - expect(nuclideUri.dirname('nuclide://host/a c/d f')).toBe( - 'nuclide://host/a c', - ); - - expect(nuclideUri.dirname('/z.zip!abc')).toBe('/z.zip'); - expect(nuclideUri.dirname('/z.zip!abc/')).toBe('/z.zip'); - expect(nuclideUri.dirname('/z.zip!abc/def')).toBe('/z.zip!abc'); - expect(nuclideUri.dirname('/abc/def!ghi')).toBe('/abc'); - expect(nuclideUri.dirname('/abc/def.txt!ghi')).toBe('/abc'); - - expect(nuclideUri.dirname('nuclide://host/z.zip!abc')).toBe( - 'nuclide://host/z.zip', - ); - expect(nuclideUri.dirname('nuclide://host/z.zip!abc/')).toBe( - 'nuclide://host/z.zip', - ); - expect(nuclideUri.dirname('nuclide://host/z.zip!abc/def')).toBe( - 'nuclide://host/z.zip!abc', - ); - - expect(nuclideUri.dirname('C:\\')).toBe('C:\\'); - expect(nuclideUri.dirname('C:\\abc')).toBe('C:\\'); - expect(nuclideUri.dirname('C:\\abc\\')).toBe('C:\\'); - expect(nuclideUri.dirname('C:\\abc\\def')).toBe('C:\\abc'); - expect(nuclideUri.dirname('C:\\abc\\def\\')).toBe('C:\\abc'); - expect(nuclideUri.dirname('\\abc\\def')).toBe('\\abc'); - expect(nuclideUri.dirname('\\abc\\def\\')).toBe('\\abc'); - - expect(nuclideUri.dirname('C:\\z.zip!abc')).toBe('C:\\z.zip'); - expect(nuclideUri.dirname('C:\\z.zip!abc/')).toBe('C:\\z.zip'); - expect(nuclideUri.dirname('C:\\z.zip!abc/def')).toBe('C:\\z.zip!abc'); - expect(nuclideUri.dirname('C:\\abc\\def!ghi')).toBe('C:\\abc'); - expect(nuclideUri.dirname('C:\\abc\\def.txt!ghi')).toBe('C:\\abc'); - expect(nuclideUri.dirname('\\z.zip!abc')).toBe('\\z.zip'); - expect(nuclideUri.dirname('\\z.zip!abc/')).toBe('\\z.zip'); - expect(nuclideUri.dirname('\\z.zip!abc/def')).toBe('\\z.zip!abc'); - expect(nuclideUri.dirname('\\abc\\def!ghi')).toBe('\\abc'); - expect(nuclideUri.dirname('\\abc\\def.txt!ghi')).toBe('\\abc'); - - expect(() => nuclideUri.dirname(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/abc')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/abc/')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/abc/def')).toBe('/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/abc/def/')).toBe('/abc'); + + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/abc')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/abc/')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/abc/def')).toBe('nuclide://host/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/abc/def/')).toBe('nuclide://host/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/a c/d f')).toBe('nuclide://host/a c'); + + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/z.zip!abc')).toBe('/z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/z.zip!abc/')).toBe('/z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/z.zip!abc/def')).toBe('/z.zip!abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/abc/def!ghi')).toBe('/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('/abc/def.txt!ghi')).toBe('/abc'); + + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/z.zip!abc')).toBe('nuclide://host/z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/z.zip!abc/')).toBe('nuclide://host/z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('nuclide://host/z.zip!abc/def')).toBe('nuclide://host/z.zip!abc'); + + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\abc')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\abc\\')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\abc\\def')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\abc\\def\\')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\abc\\def')).toBe('\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\abc\\def\\')).toBe('\\abc'); + + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\z.zip!abc')).toBe('C:\\z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\z.zip!abc/')).toBe('C:\\z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\z.zip!abc/def')).toBe('C:\\z.zip!abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\abc\\def!ghi')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('C:\\abc\\def.txt!ghi')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\z.zip!abc')).toBe('\\z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\z.zip!abc/')).toBe('\\z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\z.zip!abc/def')).toBe('\\z.zip!abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\abc\\def!ghi')).toBe('\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.dirname('\\abc\\def.txt!ghi')).toBe('\\abc'); + + expect(() => (_nuclideUri || _load_nuclideUri()).default.dirname(archiveSuffixUri)).toThrow(); }); it('extname', () => { - expect(nuclideUri.extname('/abc')).toBe(''); - expect(nuclideUri.extname('/abc.')).toBe('.'); - expect(nuclideUri.extname('/abc.txt')).toBe('.txt'); - expect(nuclideUri.extname('/abc/def.html')).toBe('.html'); - expect(nuclideUri.extname('/abc/def/')).toBe(''); - expect(nuclideUri.extname('/abc/def.dir/')).toBe('.dir'); - - expect(nuclideUri.extname('nuclide://host/')).toBe(''); - expect(nuclideUri.extname('nuclide://host/abc')).toBe(''); - expect(nuclideUri.extname('nuclide://host/abc.txt')).toBe('.txt'); - expect(nuclideUri.extname('nuclide://host/abc.')).toBe('.'); - expect(nuclideUri.extname('nuclide://host/abc/')).toBe(''); - expect(nuclideUri.extname('nuclide://host/abc/def')).toBe(''); - expect(nuclideUri.extname('nuclide://host/abc/def.js')).toBe('.js'); - - expect(nuclideUri.extname('/z.zip!abc')).toBe(''); - expect(nuclideUri.extname('/z.zip!abc.zip')).toBe('.zip'); - expect(nuclideUri.extname('/abc.txt!def')).toBe('.txt!def'); - - expect(nuclideUri.extname('C:\\')).toBe(''); - expect(nuclideUri.extname('C:\\abc')).toBe(''); - expect(nuclideUri.extname('C:\\abc\\')).toBe(''); - expect(nuclideUri.extname('C:\\abc.')).toBe('.'); - expect(nuclideUri.extname('C:\\abc.js')).toBe('.js'); - expect(nuclideUri.extname('C:\\abc\\def')).toBe(''); - expect(nuclideUri.extname('C:\\abc\\def\\')).toBe(''); - expect(nuclideUri.extname('C:\\abc\\def.')).toBe('.'); - expect(nuclideUri.extname('C:\\abc\\def.html')).toBe('.html'); - expect(nuclideUri.extname('\\abc\\def')).toBe(''); - expect(nuclideUri.extname('\\abc\\def.dir\\')).toBe('.dir'); - expect(nuclideUri.extname('\\abc\\def.')).toBe('.'); - expect(nuclideUri.extname('\\abc\\def.xml')).toBe('.xml'); - - expect(nuclideUri.extname('C:\\z.zip!abc')).toBe(''); - expect(nuclideUri.extname('C:\\z.zip!abc.zip')).toBe('.zip'); - expect(nuclideUri.extname('C:\\abc.txt!def')).toBe('.txt!def'); - expect(nuclideUri.extname('\\z.zip!abc')).toBe(''); - expect(nuclideUri.extname('\\z.zip!abc.zip')).toBe('.zip'); - expect(nuclideUri.extname('\\abc.txt!def')).toBe('.txt!def'); - - expect(() => nuclideUri.extname(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc.')).toBe('.'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc.txt')).toBe('.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc/def.html')).toBe('.html'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc/def/')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc/def.dir/')).toBe('.dir'); + + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/abc')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/abc.txt')).toBe('.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/abc.')).toBe('.'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/abc/')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/abc/def')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('nuclide://host/abc/def.js')).toBe('.js'); + + expect((_nuclideUri || _load_nuclideUri()).default.extname('/z.zip!abc')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/z.zip!abc.zip')).toBe('.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('/abc.txt!def')).toBe('.txt!def'); + + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc\\')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc.')).toBe('.'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc.js')).toBe('.js'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc\\def')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc\\def\\')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc\\def.')).toBe('.'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc\\def.html')).toBe('.html'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\abc\\def')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\abc\\def.dir\\')).toBe('.dir'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\abc\\def.')).toBe('.'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\abc\\def.xml')).toBe('.xml'); + + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\z.zip!abc')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\z.zip!abc.zip')).toBe('.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('C:\\abc.txt!def')).toBe('.txt!def'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\z.zip!abc')).toBe(''); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\z.zip!abc.zip')).toBe('.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.extname('\\abc.txt!def')).toBe('.txt!def'); + + expect(() => (_nuclideUri || _load_nuclideUri()).default.extname(archiveSuffixUri)).toThrow(); }); it('getParent', () => { - expect(nuclideUri.getParent(localUri)).toBe('/usr/local'); - expect(nuclideUri.getParent(remoteUri)).toBe('nuclide://fb.com/usr'); - expect(nuclideUri.getParent('/etc/file.zip!a')).toBe('/etc/file.zip'); - expect(nuclideUri.getParent(localArchiveUri)).toBe('/etc/file.zip'); - expect(nuclideUri.getParent(remoteArchiveUri)).toBe( - 'nuclide://fb.com/file.zip', - ); - expect(nuclideUri.getParent(endsWithExclamationUri)).toBe('/module'); - expect(nuclideUri.getParent('/abc/def!ghi')).toBe('/abc'); - expect(() => nuclideUri.getParent(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.getParent(localUri)).toBe('/usr/local'); + expect((_nuclideUri || _load_nuclideUri()).default.getParent(remoteUri)).toBe('nuclide://fb.com/usr'); + expect((_nuclideUri || _load_nuclideUri()).default.getParent('/etc/file.zip!a')).toBe('/etc/file.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.getParent(localArchiveUri)).toBe('/etc/file.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.getParent(remoteArchiveUri)).toBe('nuclide://fb.com/file.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.getParent(endsWithExclamationUri)).toBe('/module'); + expect((_nuclideUri || _load_nuclideUri()).default.getParent('/abc/def!ghi')).toBe('/abc'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.getParent(archiveSuffixUri)).toThrow(); }); it('contains', () => { - expect(nuclideUri.contains('/usr/local', localUri)).toBe(true); - expect(nuclideUri.contains('nuclide://fb.com/usr', remoteUri)).toBe(true); - expect(nuclideUri.contains('/foo/bar/', '/foo/bar/abc.txt')).toBe(true); - expect(nuclideUri.contains('/foo/bar', '/foo/bar/')).toBe(true); - expect(nuclideUri.contains('/foo/bar/', '/foo/bar/')).toBe(true); - expect(nuclideUri.contains('/foo/bar/', '/foo/bar')).toBe(true); - - expect(nuclideUri.contains('/z.zip', '/z.zip!abc')).toBe(true); - expect( - nuclideUri.contains( - 'nuclide://fb.com/z.zip', - 'nuclide://fb.com/z.zip!abc', - ), - ).toBe(true); - expect(nuclideUri.contains('/z.zip!abc', '/z.zip!abc/def')).toBe(true); - expect( - nuclideUri.contains( - 'nuclide://fb.com/z.zip!abc', - 'nuclide://fb.com/z.zip!abc/def', - ), - ).toBe(true); - expect(nuclideUri.contains('/abc', '/abc!def')).toBe(false); - - expect(() => nuclideUri.contains(archiveSuffixUri, '/foo/bar')).toThrow(); - expect(() => nuclideUri.contains('/foo/bar', archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/usr/local', localUri)).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('nuclide://fb.com/usr', remoteUri)).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/foo/bar/', '/foo/bar/abc.txt')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/foo/bar', '/foo/bar/')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/foo/bar/', '/foo/bar/')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/foo/bar/', '/foo/bar')).toBe(true); + + expect((_nuclideUri || _load_nuclideUri()).default.contains('/z.zip', '/z.zip!abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('nuclide://fb.com/z.zip', 'nuclide://fb.com/z.zip!abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/z.zip!abc', '/z.zip!abc/def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('nuclide://fb.com/z.zip!abc', 'nuclide://fb.com/z.zip!abc/def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.contains('/abc', '/abc!def')).toBe(false); + + expect(() => (_nuclideUri || _load_nuclideUri()).default.contains(archiveSuffixUri, '/foo/bar')).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.contains('/foo/bar', archiveSuffixUri)).toThrow(); }); it('collapse', () => { - expect(nuclideUri.collapse(['/a', '/b'])).toEqual(['/a', '/b']); - expect(nuclideUri.collapse(['/a/b/c/d', '/a', '/a/b'])).toEqual(['/a']); - expect(nuclideUri.collapse(['/a', '/a/b', '/a/b/c'])).toEqual(['/a']); - expect( - nuclideUri.collapse(['/a/b.zip', '/a/b.zip!c', '/a/b.zip!c/d']), - ).toEqual(['/a/b.zip']); - expect( - nuclideUri.collapse(['/a/b.zip!c', '/a/b.zip!c/d', '/a/b.zip!c/d/e']), - ).toEqual(['/a/b.zip!c']); - expect( - nuclideUri.collapse(['/a/c', '/a/c/d', '/a/b', '/a/b/c/d/e']), - ).toEqual(['/a/c', '/a/b']); - expect(nuclideUri.collapse(['/a/be', '/a/b'])).toEqual(['/a/be', '/a/b']); - expect( - nuclideUri.collapse([ - 'nuclide://fb.com/usr/local', - 'nuclide://fb.com/usr/local/test', - 'nuclide://facebook.com/usr/local/test', - ]), - ).toEqual([ - 'nuclide://fb.com/usr/local', - 'nuclide://facebook.com/usr/local/test', - ]); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a', '/b'])).toEqual(['/a', '/b']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a/b/c/d', '/a', '/a/b'])).toEqual(['/a']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a', '/a/b', '/a/b/c'])).toEqual(['/a']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a/b.zip', '/a/b.zip!c', '/a/b.zip!c/d'])).toEqual(['/a/b.zip']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a/b.zip!c', '/a/b.zip!c/d', '/a/b.zip!c/d/e'])).toEqual(['/a/b.zip!c']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a/c', '/a/c/d', '/a/b', '/a/b/c/d/e'])).toEqual(['/a/c', '/a/b']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['/a/be', '/a/b'])).toEqual(['/a/be', '/a/b']); + expect((_nuclideUri || _load_nuclideUri()).default.collapse(['nuclide://fb.com/usr/local', 'nuclide://fb.com/usr/local/test', 'nuclide://facebook.com/usr/local/test'])).toEqual(['nuclide://fb.com/usr/local', 'nuclide://facebook.com/usr/local/test']); }); it('normalize', () => { - expect(nuclideUri.normalize(localUri)).toBe(localUri); - expect(nuclideUri.normalize(remoteUri)).toBe(remoteUri); - expect(nuclideUri.normalize.bind(null, badRemoteUriNoPath)).toThrow(); - expect(nuclideUri.normalize('/usr/local/..')).toBe('/usr'); - expect(nuclideUri.normalize('nuclide://fb.com/usr/local/..')).toBe( - 'nuclide://fb.com/usr', - ); - expect(nuclideUri.normalize('/a b/c d/..')).toBe('/a b'); - expect(nuclideUri.normalize('/a/b.zip!c/..')).toBe('/a/b.zip'); - expect(nuclideUri.normalize('/a/b.zip!c/d/../../..')).toBe('/a'); - expect(nuclideUri.normalize('/a/b!c/..')).toBe('/a'); - expect(() => nuclideUri.normalize(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.normalize(localUri)).toBe(localUri); + expect((_nuclideUri || _load_nuclideUri()).default.normalize(remoteUri)).toBe(remoteUri); + expect((_nuclideUri || _load_nuclideUri()).default.normalize.bind(null, badRemoteUriNoPath)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.normalize('/usr/local/..')).toBe('/usr'); + expect((_nuclideUri || _load_nuclideUri()).default.normalize('nuclide://fb.com/usr/local/..')).toBe('nuclide://fb.com/usr'); + expect((_nuclideUri || _load_nuclideUri()).default.normalize('/a b/c d/..')).toBe('/a b'); + expect((_nuclideUri || _load_nuclideUri()).default.normalize('/a/b.zip!c/..')).toBe('/a/b.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.normalize('/a/b.zip!c/d/../../..')).toBe('/a'); + expect((_nuclideUri || _load_nuclideUri()).default.normalize('/a/b!c/..')).toBe('/a'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.normalize(archiveSuffixUri)).toThrow(); }); it('relative', () => { - expect(() => nuclideUri.relative(localUri, remoteUri)).toThrow(); - expect(nuclideUri.relative(nuclideUri.dirname(remoteUri), remoteUri)).toBe( - 'local', - ); - expect(nuclideUri.relative(remoteUri, nuclideUri.dirname(remoteUri))).toBe( - '..', - ); - expect( - nuclideUri.relative( - nuclideUri.dirname(remoteUriWithSpaces), - remoteUriWithSpaces, - ), - ).toBe('c d'); - expect( - nuclideUri.relative( - remoteUriWithSpaces, - nuclideUri.dirname(remoteUriWithSpaces), - ), - ).toBe('..'); - expect(nuclideUri.relative(nuclideUri.dirname(localUri), localUri)).toBe( - 'file', - ); - expect(nuclideUri.relative(localUri, nuclideUri.dirname(localUri))).toBe( - '..', - ); - expect( - nuclideUri.relative(nuclideUri.dirname(localArchiveUri), localArchiveUri), - ).toBe('a'); - expect( - nuclideUri.relative(localArchiveUri, nuclideUri.dirname(localArchiveUri)), - ).toBe('..'); - expect( - nuclideUri.relative( - nuclideUri.dirname(endsWithExclamationUri), - endsWithExclamationUri, - ), - ).toBe('!! WARNING !!'); - expect( - nuclideUri.relative( - endsWithExclamationUri, - nuclideUri.dirname(endsWithExclamationUri), - ), - ).toBe('..'); - expect(nuclideUri.relative('/a/b.zip!c', '/a/b.zip!d')).toBe('../d'); - expect(nuclideUri.relative('/a/b!c', '/a/b!d')).toBe('../b!d'); - expect(() => nuclideUri.relative(archiveSuffixUri, 'foo')).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.relative(localUri, remoteUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.relative((_nuclideUri || _load_nuclideUri()).default.dirname(remoteUri), remoteUri)).toBe('local'); + expect((_nuclideUri || _load_nuclideUri()).default.relative(remoteUri, (_nuclideUri || _load_nuclideUri()).default.dirname(remoteUri))).toBe('..'); + expect((_nuclideUri || _load_nuclideUri()).default.relative((_nuclideUri || _load_nuclideUri()).default.dirname(remoteUriWithSpaces), remoteUriWithSpaces)).toBe('c d'); + expect((_nuclideUri || _load_nuclideUri()).default.relative(remoteUriWithSpaces, (_nuclideUri || _load_nuclideUri()).default.dirname(remoteUriWithSpaces))).toBe('..'); + expect((_nuclideUri || _load_nuclideUri()).default.relative((_nuclideUri || _load_nuclideUri()).default.dirname(localUri), localUri)).toBe('file'); + expect((_nuclideUri || _load_nuclideUri()).default.relative(localUri, (_nuclideUri || _load_nuclideUri()).default.dirname(localUri))).toBe('..'); + expect((_nuclideUri || _load_nuclideUri()).default.relative((_nuclideUri || _load_nuclideUri()).default.dirname(localArchiveUri), localArchiveUri)).toBe('a'); + expect((_nuclideUri || _load_nuclideUri()).default.relative(localArchiveUri, (_nuclideUri || _load_nuclideUri()).default.dirname(localArchiveUri))).toBe('..'); + expect((_nuclideUri || _load_nuclideUri()).default.relative((_nuclideUri || _load_nuclideUri()).default.dirname(endsWithExclamationUri), endsWithExclamationUri)).toBe('!! WARNING !!'); + expect((_nuclideUri || _load_nuclideUri()).default.relative(endsWithExclamationUri, (_nuclideUri || _load_nuclideUri()).default.dirname(endsWithExclamationUri))).toBe('..'); + expect((_nuclideUri || _load_nuclideUri()).default.relative('/a/b.zip!c', '/a/b.zip!d')).toBe('../d'); + expect((_nuclideUri || _load_nuclideUri()).default.relative('/a/b!c', '/a/b!d')).toBe('../b!d'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.relative(archiveSuffixUri, 'foo')).toThrow(); }); it('nuclideUriToDisplayString', () => { - expect(nuclideUri.nuclideUriToDisplayString(localUri)).toBe(localUri); - expect(nuclideUri.nuclideUriToDisplayString(remoteUri)).toBe( - 'fb.com:/usr/local', - ); - expect(nuclideUri.nuclideUriToDisplayString(localArchiveUri)).toBe( - '/etc/file.zip!a', - ); - expect(nuclideUri.nuclideUriToDisplayString(remoteArchiveUri)).toBe( - 'fb.com:/file.zip!a.txt', - ); - expect(nuclideUri.nuclideUriToDisplayString(endsWithExclamationUri)).toBe( - '/module/!! WARNING !!', - ); - expect(() => - nuclideUri.nuclideUriToDisplayString(archiveSuffixUri), - ).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToDisplayString(localUri)).toBe(localUri); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToDisplayString(remoteUri)).toBe('fb.com:/usr/local'); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToDisplayString(localArchiveUri)).toBe('/etc/file.zip!a'); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToDisplayString(remoteArchiveUri)).toBe('fb.com:/file.zip!a.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToDisplayString(endsWithExclamationUri)).toBe('/module/!! WARNING !!'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.nuclideUriToDisplayString(archiveSuffixUri)).toThrow(); }); describe('isRoot', () => { - it('plain posix root', () => expect(nuclideUri.isRoot('/')).toBe(true)); - it('double root', () => expect(nuclideUri.isRoot('//')).toBe(false)); - it('/abc', () => expect(nuclideUri.isRoot('/abc')).toBe(false)); - it('abc', () => expect(nuclideUri.isRoot('abc')).toBe(false)); - it('abc/def', () => expect(nuclideUri.isRoot('abc/def')).toBe(false)); - it('/file.zip!', () => - expect(() => nuclideUri.isRoot('/file.zip!')).toThrow()); - it('/file.zip!abc', () => - expect(nuclideUri.isRoot('/file.zip!abc')).toBe(false)); - it('remote root', () => - expect(nuclideUri.isRoot('nuclide://host/')).toBe(true)); - it('remote root with port', () => - expect(nuclideUri.isRoot('nuclide://host/')).toBe(true)); - it('remote non-root', () => - expect(nuclideUri.isRoot('nuclide://host/abc')).toBe(false)); + it('plain posix root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('/')).toBe(true)); + it('double root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('//')).toBe(false)); + it('/abc', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('/abc')).toBe(false)); + it('abc', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('abc')).toBe(false)); + it('abc/def', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('abc/def')).toBe(false)); + it('/file.zip!', () => expect(() => (_nuclideUri || _load_nuclideUri()).default.isRoot('/file.zip!')).toThrow()); + it('/file.zip!abc', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('/file.zip!abc')).toBe(false)); + it('remote root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('nuclide://host/')).toBe(true)); + it('remote root with port', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('nuclide://host/')).toBe(true)); + it('remote non-root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('nuclide://host/abc')).toBe(false)); it('remote non-root no port', () => { - expect(nuclideUri.isRoot('nuclide://host/abc')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isRoot('nuclide://host/abc')).toBe(false); }); - it('win diskless root', () => expect(nuclideUri.isRoot('\\')).toBe(true)); - it('win diskless double root', () => - expect(nuclideUri.isRoot('\\\\')).toBe(false)); - it('win diskless non-root', () => - expect(nuclideUri.isRoot('\\abc')).toBe(false)); - it('win diskful root', () => expect(nuclideUri.isRoot('C:\\')).toBe(true)); - it('win diskful double root', () => - expect(nuclideUri.isRoot('C:\\\\')).toBe(false)); - it('win diskful non-root', () => - expect(nuclideUri.isRoot('C:\\abc')).toBe(false)); - - it('win relative', () => expect(nuclideUri.isRoot('abc\\def')).toBe(false)); + it('win diskless root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('\\')).toBe(true)); + it('win diskless double root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('\\\\')).toBe(false)); + it('win diskless non-root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('\\abc')).toBe(false)); + it('win diskful root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('C:\\')).toBe(true)); + it('win diskful double root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('C:\\\\')).toBe(false)); + it('win diskful non-root', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('C:\\abc')).toBe(false)); + + it('win relative', () => expect((_nuclideUri || _load_nuclideUri()).default.isRoot('abc\\def')).toBe(false)); it('throws on illegal URIs', () => { - expect(() => nuclideUri.basename(archiveSuffixUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.basename(archiveSuffixUri)).toThrow(); }); }); it('adds a proper suffix when needed', () => { - expect(nuclideUri.ensureTrailingSeparator('/')).toBe('/'); - expect(nuclideUri.ensureTrailingSeparator('/abc')).toBe('/abc/'); - expect(nuclideUri.ensureTrailingSeparator('/abc/')).toBe('/abc/'); - expect(nuclideUri.ensureTrailingSeparator('/abc/def')).toBe('/abc/def/'); - expect(nuclideUri.ensureTrailingSeparator('/abc/def/')).toBe('/abc/def/'); - expect(nuclideUri.ensureTrailingSeparator('nuclide://host')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.ensureTrailingSeparator('nuclide://host/')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.ensureTrailingSeparator('nuclide://host/abc')).toBe( - 'nuclide://host/abc/', - ); - expect(nuclideUri.ensureTrailingSeparator('nuclide://host/abc/def')).toBe( - 'nuclide://host/abc/def/', - ); - expect(nuclideUri.ensureTrailingSeparator('nuclide://host/abc/def/')).toBe( - 'nuclide://host/abc/def/', - ); - expect(nuclideUri.ensureTrailingSeparator('C:\\')).toBe('C:\\'); - expect(nuclideUri.ensureTrailingSeparator('C:\\abc')).toBe('C:\\abc\\'); - expect(nuclideUri.ensureTrailingSeparator('C:\\abc\\')).toBe('C:\\abc\\'); - expect(nuclideUri.ensureTrailingSeparator('C:\\abc\\def')).toBe( - 'C:\\abc\\def\\', - ); - expect(nuclideUri.ensureTrailingSeparator('C:\\abc\\def\\')).toBe( - 'C:\\abc\\def\\', - ); - expect(nuclideUri.ensureTrailingSeparator('\\abc\\def')).toBe( - '\\abc\\def\\', - ); - expect(nuclideUri.ensureTrailingSeparator('\\abc\\def\\')).toBe( - '\\abc\\def\\', - ); - expect(() => - nuclideUri.ensureTrailingSeparator(archiveSuffixUri), - ).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('/')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('/abc')).toBe('/abc/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('/abc/')).toBe('/abc/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('/abc/def')).toBe('/abc/def/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('/abc/def/')).toBe('/abc/def/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('nuclide://host')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('nuclide://host/')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('nuclide://host/abc')).toBe('nuclide://host/abc/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('nuclide://host/abc/def')).toBe('nuclide://host/abc/def/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('nuclide://host/abc/def/')).toBe('nuclide://host/abc/def/'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('C:\\')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('C:\\abc')).toBe('C:\\abc\\'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('C:\\abc\\')).toBe('C:\\abc\\'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('C:\\abc\\def')).toBe('C:\\abc\\def\\'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('C:\\abc\\def\\')).toBe('C:\\abc\\def\\'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('\\abc\\def')).toBe('\\abc\\def\\'); + expect((_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator('\\abc\\def\\')).toBe('\\abc\\def\\'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.ensureTrailingSeparator(archiveSuffixUri)).toThrow(); }); it('properly removes suffix when needed', () => { - expect(nuclideUri.trimTrailingSeparator('/')).toBe('/'); - expect(nuclideUri.trimTrailingSeparator('//')).toBe('/'); - expect(nuclideUri.trimTrailingSeparator('/abc')).toBe('/abc'); - expect(nuclideUri.trimTrailingSeparator('/abc/')).toBe('/abc'); - expect(nuclideUri.trimTrailingSeparator('/abc/def')).toBe('/abc/def'); - expect(nuclideUri.trimTrailingSeparator('/abc/def/')).toBe('/abc/def'); - expect(nuclideUri.trimTrailingSeparator('nuclide://host/')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host//')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host/')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host//')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host/abc')).toBe( - 'nuclide://host/abc', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host/abc/')).toBe( - 'nuclide://host/abc', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host/abc/def')).toBe( - 'nuclide://host/abc/def', - ); - expect(nuclideUri.trimTrailingSeparator('nuclide://host/abc/def/')).toBe( - 'nuclide://host/abc/def', - ); - expect(nuclideUri.trimTrailingSeparator('C:\\')).toBe('C:\\'); - expect(nuclideUri.trimTrailingSeparator('C:\\\\')).toBe('C:\\'); - expect(nuclideUri.trimTrailingSeparator('C:\\abc')).toBe('C:\\abc'); - expect(nuclideUri.trimTrailingSeparator('C:\\abc\\')).toBe('C:\\abc'); - expect(nuclideUri.trimTrailingSeparator('C:\\abc\\def')).toBe( - 'C:\\abc\\def', - ); - expect(nuclideUri.trimTrailingSeparator('C:\\abc\\def\\')).toBe( - 'C:\\abc\\def', - ); - expect(nuclideUri.trimTrailingSeparator('\\')).toBe('\\'); - expect(nuclideUri.trimTrailingSeparator('\\\\')).toBe('\\'); - expect(nuclideUri.trimTrailingSeparator('\\abc\\def')).toBe('\\abc\\def'); - expect(nuclideUri.trimTrailingSeparator('\\abc\\def\\')).toBe('\\abc\\def'); - expect(() => nuclideUri.trimTrailingSeparator(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('/')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('//')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('/abc')).toBe('/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('/abc/')).toBe('/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('/abc/def')).toBe('/abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('/abc/def/')).toBe('/abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host/')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host//')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host/')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host//')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host/abc')).toBe('nuclide://host/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host/abc/')).toBe('nuclide://host/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host/abc/def')).toBe('nuclide://host/abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('nuclide://host/abc/def/')).toBe('nuclide://host/abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('C:\\')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('C:\\\\')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('C:\\abc')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('C:\\abc\\')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('C:\\abc\\def')).toBe('C:\\abc\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('C:\\abc\\def\\')).toBe('C:\\abc\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('\\')).toBe('\\'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('\\\\')).toBe('\\'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('\\abc\\def')).toBe('\\abc\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator('\\abc\\def\\')).toBe('\\abc\\def'); + expect(() => (_nuclideUri || _load_nuclideUri()).default.trimTrailingSeparator(archiveSuffixUri)).toThrow(); }); it('isAbsolute', () => { - expect(nuclideUri.isAbsolute('/abc')).toBe(true); - expect(nuclideUri.isAbsolute('/abc/def')).toBe(true); - expect(nuclideUri.isAbsolute('nuclide://host/')).toBe(true); - expect(nuclideUri.isAbsolute('nuclide://host/abc')).toBe(true); - expect(nuclideUri.isAbsolute('nuclide://host/abc/def')).toBe(true); - - expect(nuclideUri.isAbsolute('C:\\abc')).toBe(true); - expect(nuclideUri.isAbsolute('C:\\abc\\def')).toBe(true); - expect(nuclideUri.isAbsolute('\\abc')).toBe(true); - expect(nuclideUri.isAbsolute('\\abc\\def')).toBe(true); - - expect(nuclideUri.isAbsolute('abc')).toBe(false); - expect(nuclideUri.isAbsolute('abc/def')).toBe(false); - - expect(nuclideUri.isAbsolute('abc\\def')).toBe(false); - expect(() => nuclideUri.isAbsolute(archiveSuffixUri)).toThrow(); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('/abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('/abc/def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('nuclide://host/')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('nuclide://host/abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('nuclide://host/abc/def')).toBe(true); + + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('C:\\abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('C:\\abc\\def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('\\abc')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('\\abc\\def')).toBe(true); + + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('abc')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('abc/def')).toBe(false); + + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute('abc\\def')).toBe(false); + expect(() => (_nuclideUri || _load_nuclideUri()).default.isAbsolute(archiveSuffixUri)).toThrow(); }); it('resolve', () => { - expect(nuclideUri.resolve('/abc')).toBe('/abc'); - expect(nuclideUri.resolve('/abc', '..')).toBe('/'); - expect(nuclideUri.resolve('/abc', '..', '..')).toBe('/'); - expect(nuclideUri.resolve('/abc', '../..')).toBe('/'); - - expect(nuclideUri.resolve('/abc/def')).toBe('/abc/def'); - expect(nuclideUri.resolve('/abc/def', 'ghi')).toBe('/abc/def/ghi'); - expect(nuclideUri.resolve('/abc/def', '..', 'ghi')).toBe('/abc/ghi'); - expect(nuclideUri.resolve('/abc/def', '../ghi')).toBe('/abc/ghi'); - expect(nuclideUri.resolve('/abc/def', '/ghi')).toBe('/ghi'); - - expect(nuclideUri.resolve('/z.zip!abc')).toBe('/z.zip!abc'); - expect(nuclideUri.resolve('/z.zip!abc', '..')).toBe('/z.zip'); - expect(nuclideUri.resolve('/z.zip!abc', '..', '..')).toBe('/'); - expect(nuclideUri.resolve('/z.zip!abc', '../..')).toBe('/'); - - expect(nuclideUri.resolve('/z.zip!abc', 'def')).toBe('/z.zip!abc/def'); - expect(nuclideUri.resolve('/z.zip!abc', '..', 'def')).toBe('/z.zip!def'); - expect(nuclideUri.resolve('/z.zip!abc', '../def')).toBe('/z.zip!def'); - expect(nuclideUri.resolve('/z.zip!abc', '/def')).toBe('/def'); - - expect(nuclideUri.resolve('/dir/file!abc')).toBe('/dir/file!abc'); - expect(nuclideUri.resolve('/dir/file!abc', '..')).toBe('/dir'); - expect(nuclideUri.resolve('/dir/file!abc', '..', '..')).toBe('/'); - expect(nuclideUri.resolve('/dir/file!abc', '../..')).toBe('/'); - - expect(nuclideUri.resolve('/dir/file!abc', 'def')).toBe( - '/dir/file!abc/def', - ); - expect(nuclideUri.resolve('/dir/file!abc', '..', 'def')).toBe('/dir/def'); - expect(nuclideUri.resolve('/dir/file!abc', '../def')).toBe('/dir/def'); - expect(nuclideUri.resolve('/dir/file!abc', '/def')).toBe('/def'); - - expect(nuclideUri.resolve('nuclide://host/')).toBe('nuclide://host/'); - expect(nuclideUri.resolve('nuclide://host/', '..')).toBe('nuclide://host/'); - expect(nuclideUri.resolve('nuclide://host/abc')).toBe('nuclide://host/abc'); - expect(nuclideUri.resolve('nuclide://host/abc', '..')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.resolve('nuclide://host/abc', '..', '..')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.resolve('nuclide://host/abc', '../..')).toBe( - 'nuclide://host/', - ); - expect(nuclideUri.resolve('nuclide://host/abc/def', 'ghi')).toBe( - 'nuclide://host/abc/def/ghi', - ); - expect(nuclideUri.resolve('nuclide://host/abc/def', '../ghi')).toBe( - 'nuclide://host/abc/ghi', - ); - expect(nuclideUri.resolve('nuclide://host/abc/def', '..', 'ghi')).toBe( - 'nuclide://host/abc/ghi', - ); - expect(nuclideUri.resolve('nuclide://host/abc/def', '/ghi')).toBe( - 'nuclide://host/ghi', - ); - - expect(nuclideUri.resolve('C:\\abc')).toBe('C:\\abc'); - expect(nuclideUri.resolve('C:\\abc', '..')).toBe('C:\\'); - expect(nuclideUri.resolve('C:\\abc', '..', '..')).toBe('C:\\'); - expect(nuclideUri.resolve('C:\\abc', '..\\..')).toBe('C:\\'); - expect(nuclideUri.resolve('C:\\abc', 'def')).toBe('C:\\abc\\def'); - expect(nuclideUri.resolve('C:\\abc', '..\\def')).toBe('C:\\def'); - expect(nuclideUri.resolve('C:\\abc', '..', 'def')).toBe('C:\\def'); - - expect(nuclideUri.resolve('\\abc', 'def')).toBe('\\abc\\def'); - expect(nuclideUri.resolve('\\abc', '..\\def')).toBe('\\def'); - expect(nuclideUri.resolve('\\abc', '..', 'def')).toBe('\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc')).toBe('/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc', '..')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc', '..', '..')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc', '../..')).toBe('/'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc/def')).toBe('/abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc/def', 'ghi')).toBe('/abc/def/ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc/def', '..', 'ghi')).toBe('/abc/ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc/def', '../ghi')).toBe('/abc/ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/abc/def', '/ghi')).toBe('/ghi'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc')).toBe('/z.zip!abc'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', '..')).toBe('/z.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', '..', '..')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', '../..')).toBe('/'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', 'def')).toBe('/z.zip!abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', '..', 'def')).toBe('/z.zip!def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', '../def')).toBe('/z.zip!def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/z.zip!abc', '/def')).toBe('/def'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc')).toBe('/dir/file!abc'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', '..')).toBe('/dir'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', '..', '..')).toBe('/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', '../..')).toBe('/'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', 'def')).toBe('/dir/file!abc/def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', '..', 'def')).toBe('/dir/def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', '../def')).toBe('/dir/def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('/dir/file!abc', '/def')).toBe('/def'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/', '..')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc')).toBe('nuclide://host/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc', '..')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc', '..', '..')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc', '../..')).toBe('nuclide://host/'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc/def', 'ghi')).toBe('nuclide://host/abc/def/ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc/def', '../ghi')).toBe('nuclide://host/abc/ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc/def', '..', 'ghi')).toBe('nuclide://host/abc/ghi'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('nuclide://host/abc/def', '/ghi')).toBe('nuclide://host/ghi'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc')).toBe('C:\\abc'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc', '..')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc', '..', '..')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc', '..\\..')).toBe('C:\\'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc', 'def')).toBe('C:\\abc\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc', '..\\def')).toBe('C:\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('C:\\abc', '..', 'def')).toBe('C:\\def'); + + expect((_nuclideUri || _load_nuclideUri()).default.resolve('\\abc', 'def')).toBe('\\abc\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('\\abc', '..\\def')).toBe('\\def'); + expect((_nuclideUri || _load_nuclideUri()).default.resolve('\\abc', '..', 'def')).toBe('\\def'); }); describe('expandHomeDir()', () => { it('expands ~ to HOME', () => { - expect(nuclideUri.expandHomeDir('~')).toBe(process.env.HOME); + expect((_nuclideUri || _load_nuclideUri()).default.expandHomeDir('~')).toBe(process.env.HOME); }); it('expands ~/ to HOME', () => { const HOME = process.env.HOME; expect(HOME).not.toBeNull(); - expect(nuclideUri.expandHomeDir('~/abc')).toBe( - path.posix.join(HOME, 'abc'), - ); + expect((_nuclideUri || _load_nuclideUri()).default.expandHomeDir('~/abc')).toBe(_path.default.posix.join(HOME, 'abc')); }); it('keeps ~def to ~def', () => { - expect(nuclideUri.expandHomeDir('~def')).toBe('~def'); + expect((_nuclideUri || _load_nuclideUri()).default.expandHomeDir('~def')).toBe('~def'); }); it('throws on illegal URIs', () => { - expect(() => nuclideUri.expandHomeDir(archiveSuffixUri)).toThrow(); + expect(() => (_nuclideUri || _load_nuclideUri()).default.expandHomeDir(archiveSuffixUri)).toThrow(); }); }); it('detects Windows and Posix paths properly', () => { - expect(__TEST__._pathModuleFor('/')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('/abc')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('/abc/def')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('/abc.txt')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('nuclide://host')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('nuclide://host/')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('nuclide://host/abc')).toEqual(path.posix); - expect(__TEST__._pathModuleFor('nuclide://host/abc/def')).toEqual( - path.posix, - ); - expect(__TEST__._pathModuleFor('nuclide://host/abc/def.txt')).toEqual( - path.posix, - ); - expect(__TEST__._pathModuleFor('C:\\')).toEqual(path.win32); - expect(__TEST__._pathModuleFor('C:\\abc')).toEqual(path.win32); - expect(__TEST__._pathModuleFor('C:\\abc\\def')).toEqual(path.win32); - expect(__TEST__._pathModuleFor('C:\\abc\\def.txt')).toEqual(path.win32); - expect(__TEST__._pathModuleFor('D:\\abc\\aaa bbb')).toEqual(path.win32); - expect(__TEST__._pathModuleFor('\\abc\\def')).toEqual(path.win32); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('/')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('/abc')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('/abc/def')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('/abc.txt')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('nuclide://host')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('nuclide://host/')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('nuclide://host/abc')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('nuclide://host/abc/def')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('nuclide://host/abc/def.txt')).toEqual(_path.default.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('C:\\')).toEqual(_path.default.win32); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('C:\\abc')).toEqual(_path.default.win32); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('C:\\abc\\def')).toEqual(_path.default.win32); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('C:\\abc\\def.txt')).toEqual(_path.default.win32); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('D:\\abc\\aaa bbb')).toEqual(_path.default.win32); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('\\abc\\def')).toEqual(_path.default.win32); // Default to Posix - expect(__TEST__._pathModuleFor('abcdef')).toEqual(path.posix); + expect((_nuclideUri2 || _load_nuclideUri2()).__TEST__._pathModuleFor('abcdef')).toEqual(_path.default.posix); }); it('properly converts file URIs to local paths', () => { - expect(nuclideUri.uriToNuclideUri('\\abc\\def')).toEqual(null); - expect(nuclideUri.uriToNuclideUri('file://somehost/file/path')).toEqual( - '/file/path', - ); - expect( - nuclideUri.uriToNuclideUri( - 'file:///foo/bar/buck-out/flavor%231%232%233%2Cabc', - ), - ).toEqual('/foo/bar/buck-out/flavor#1#2#3,abc'); - expect( - nuclideUri.uriToNuclideUri('file:///file/path/file_%25.ext'), - ).toEqual('/file/path/file_%.ext'); - expect(nuclideUri.uriToNuclideUri('file://C:\\some\\file\\path')).toEqual( - 'C:\\some\\file\\path', - ); + expect((_nuclideUri || _load_nuclideUri()).default.uriToNuclideUri('\\abc\\def')).toEqual(null); + expect((_nuclideUri || _load_nuclideUri()).default.uriToNuclideUri('file://somehost/file/path')).toEqual('/file/path'); + expect((_nuclideUri || _load_nuclideUri()).default.uriToNuclideUri('file:///foo/bar/buck-out/flavor%231%232%233%2Cabc')).toEqual('/foo/bar/buck-out/flavor#1#2#3,abc'); + expect((_nuclideUri || _load_nuclideUri()).default.uriToNuclideUri('file:///file/path/file_%25.ext')).toEqual('/file/path/file_%.ext'); + expect((_nuclideUri || _load_nuclideUri()).default.uriToNuclideUri('file://C:\\some\\file\\path')).toEqual('C:\\some\\file\\path'); }); it('properly converts local paths to file URIs', () => { - expect(nuclideUri.nuclideUriToUri('/foo/bar/file.ext')).toEqual( - 'file:///foo/bar/file.ext', - ); - expect( - nuclideUri.nuclideUriToUri('/foo/bar/buck-out/flavor#1#2#3,abc'), - ).toEqual('file:///foo/bar/buck-out/flavor%231%232%233%2Cabc'); - expect(nuclideUri.nuclideUriToUri('/file/path/file_%.ext')).toEqual( - 'file:///file/path/file_%25.ext', - ); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToUri('/foo/bar/file.ext')).toEqual('file:///foo/bar/file.ext'); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToUri('/foo/bar/buck-out/flavor#1#2#3,abc')).toEqual('file:///foo/bar/buck-out/flavor%231%232%233%2Cabc'); + expect((_nuclideUri || _load_nuclideUri()).default.nuclideUriToUri('/file/path/file_%.ext')).toEqual('file:///file/path/file_%25.ext'); }); it('properly handles backslash-containing remote URIs', () => { - expect(nuclideUri.getPath('nuclide://host/aaa\\bbb.txt')).toBe( - '/aaa\\bbb.txt', - ); - expect(nuclideUri.getPath('nuclide://host/dir/aaa\\bbb.txt')).toBe( - '/dir/aaa\\bbb.txt', - ); - expect(nuclideUri.getPath('nuclide://host/one\\two\\file.txt')).toBe( - '/one\\two\\file.txt', - ); + expect((_nuclideUri || _load_nuclideUri()).default.getPath('nuclide://host/aaa\\bbb.txt')).toBe('/aaa\\bbb.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.getPath('nuclide://host/dir/aaa\\bbb.txt')).toBe('/dir/aaa\\bbb.txt'); + expect((_nuclideUri || _load_nuclideUri()).default.getPath('nuclide://host/one\\two\\file.txt')).toBe('/one\\two\\file.txt'); }); it('correctly distinguishes paths that refer to files in an archive', () => { - expect(nuclideUri.isInArchive('abc')).toBe(false); - expect(nuclideUri.isInArchive('/abc')).toBe(false); - expect(nuclideUri.isInArchive('nuclide://host/abc')).toBe(false); - expect(nuclideUri.isInArchive('abc.zip')).toBe(false); - expect(nuclideUri.isInArchive('abc.jar')).toBe(false); - expect(nuclideUri.isInArchive('abc.zip!def')).toBe(true); - expect(nuclideUri.isInArchive('abc.jar!def')).toBe(true); - expect(nuclideUri.isInArchive('/abc.zip!def')).toBe(true); - expect(nuclideUri.isInArchive('/abc.jar!def')).toBe(true); - expect(nuclideUri.isInArchive('C:\\abc.zip!def')).toBe(true); - expect(nuclideUri.isInArchive('C:\\abc.jar!def')).toBe(true); - expect(nuclideUri.isInArchive('nuclide://host/abc.zip!def')).toBe(true); - expect(nuclideUri.isInArchive('nuclide://host/abc.jar!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('abc')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('/abc')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('nuclide://host/abc')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('abc.zip')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('abc.jar')).toBe(false); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('abc.zip!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('abc.jar!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('/abc.zip!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('/abc.jar!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('C:\\abc.zip!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('C:\\abc.jar!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('nuclide://host/abc.zip!def')).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isInArchive('nuclide://host/abc.jar!def')).toBe(true); }); it('reports first ancestor outside archive', () => { - expect(nuclideUri.ancestorOutsideArchive('abc')).toBe('abc'); - expect(nuclideUri.ancestorOutsideArchive('/abc')).toBe('/abc'); - expect(nuclideUri.ancestorOutsideArchive('nuclide://host/abc')).toBe( - 'nuclide://host/abc', - ); - expect(nuclideUri.ancestorOutsideArchive('abc.zip')).toBe('abc.zip'); - expect(nuclideUri.ancestorOutsideArchive('abc.jar')).toBe('abc.jar'); - expect(nuclideUri.ancestorOutsideArchive('abc.zip!def')).toBe('abc.zip'); - expect(nuclideUri.ancestorOutsideArchive('abc.jar!def')).toBe('abc.jar'); - expect(nuclideUri.ancestorOutsideArchive('/abc.zip!def')).toBe('/abc.zip'); - expect(nuclideUri.ancestorOutsideArchive('/abc.jar!def')).toBe('/abc.jar'); - expect(nuclideUri.ancestorOutsideArchive('C:\\abc.zip!def')).toBe( - 'C:\\abc.zip', - ); - expect(nuclideUri.ancestorOutsideArchive('C:\\abc.jar!def')).toBe( - 'C:\\abc.jar', - ); - expect( - nuclideUri.ancestorOutsideArchive('nuclide://host/abc.zip!def'), - ).toBe('nuclide://host/abc.zip'); - expect( - nuclideUri.ancestorOutsideArchive('nuclide://host/abc.jar!def'), - ).toBe('nuclide://host/abc.jar'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('abc')).toBe('abc'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('/abc')).toBe('/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('nuclide://host/abc')).toBe('nuclide://host/abc'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('abc.zip')).toBe('abc.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('abc.jar')).toBe('abc.jar'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('abc.zip!def')).toBe('abc.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('abc.jar!def')).toBe('abc.jar'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('/abc.zip!def')).toBe('/abc.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('/abc.jar!def')).toBe('/abc.jar'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('C:\\abc.zip!def')).toBe('C:\\abc.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('C:\\abc.jar!def')).toBe('C:\\abc.jar'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('nuclide://host/abc.zip!def')).toBe('nuclide://host/abc.zip'); + expect((_nuclideUri || _load_nuclideUri()).default.ancestorOutsideArchive('nuclide://host/abc.jar!def')).toBe('nuclide://host/abc.jar'); }); }); +// eslint-disable-next-line rulesdir/prefer-nuclide-uri \ No newline at end of file diff --git a/modules/nuclide-commons/spec/observable-spec.js b/modules/nuclide-commons/spec/observable-spec.js index 6b78e4f6..9235a7e0 100644 --- a/modules/nuclide-commons/spec/observable-spec.js +++ b/modules/nuclide-commons/spec/observable-spec.js @@ -1,3 +1,29 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _observable; + +function _load_observable() { + return _observable = require('../observable'); +} + +var _nullthrows; + +function _load_nullthrows() { + return _nullthrows = _interopRequireDefault(require('nullthrows')); +} + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('../UniversalDisposable')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,40 +32,14 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import { - bufferUntil, - cacheWhileSubscribed, - completingSwitchMap, - concatLatest, - diffSets, - fastDebounce, - macrotask, - microtask, - nextAnimationFrame, - poll, - PromiseCanceledError, - reconcileSetDiffs, - SingletonExecutor, - splitStream, - takeWhileInclusive, - throttle, - toCancelablePromise, - toggle, -} from '../observable'; -import nullthrows from 'nullthrows'; -import UniversalDisposable from '../UniversalDisposable'; -import {Observable, Subject} from 'rxjs'; - -const setsAreEqual = (a, b) => - a.size === b.size && Array.from(a).every(b.has.bind(b)); -const diffsAreEqual = (a, b) => - setsAreEqual(a.added, b.added) && setsAreEqual(a.removed, b.removed); +const setsAreEqual = (a, b) => a.size === b.size && Array.from(a).every(b.has.bind(b)); +const diffsAreEqual = (a, b) => setsAreEqual(a.added, b.added) && setsAreEqual(a.removed, b.removed); const createDisposable = () => { - const disposable = new UniversalDisposable(); + const disposable = new (_UniversalDisposable || _load_UniversalDisposable()).default(); spyOn(disposable, 'dispose'); return disposable; }; @@ -47,33 +47,29 @@ const createDisposable = () => { describe('nuclide-commons/observable', () => { describe('splitStream', () => { it('splits streams', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const input = ['foo\nbar', '\n', '\nba', 'z', '\nblar']; - const output = await splitStream(Observable.from(input)) - .toArray() - .toPromise(); + const output = yield (0, (_observable || _load_observable()).splitStream)(_rxjsBundlesRxMinJs.Observable.from(input)).toArray().toPromise(); expect(output).toEqual(['foo\n', 'bar\n', '\n', 'baz\n', 'blar']); - }); + })); }); it('splits streams without the newline', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const input = ['foo\nbar', '\n', '\nba', 'z', '\nblar']; - const output = await splitStream(Observable.from(input), false) - .toArray() - .toPromise(); + const output = yield (0, (_observable || _load_observable()).splitStream)(_rxjsBundlesRxMinJs.Observable.from(input), false).toArray().toPromise(); expect(output).toEqual(['foo', 'bar', '', 'baz', 'blar']); - }); + })); }); }); describe('takeWhileInclusive', () => { it('completes the stream when something matches the predicate', () => { - const source = new Subject(); - const result = source.let(takeWhileInclusive(x => x !== 2)); - const next: (n: number) => mixed = jasmine.createSpy(); - const complete: () => mixed = jasmine.createSpy(); - result.subscribe({next, complete}); + const source = new _rxjsBundlesRxMinJs.Subject(); + const result = source.let((0, (_observable || _load_observable()).takeWhileInclusive)(x => x !== 2)); + const next = jasmine.createSpy(); + const complete = jasmine.createSpy(); + result.subscribe({ next, complete }); source.next(1); source.next(2); source.next(3); @@ -83,15 +79,15 @@ describe('nuclide-commons/observable', () => { }); describe('cacheWhileSubscribed', () => { - let input: Subject = (null: any); - let output: Observable = (null: any); + let input = null; + let output = null; - function subscribeArray(arr: Array): rxjs$ISubscription { + function subscribeArray(arr) { return output.subscribe(x => arr.push(x)); } beforeEach(() => { - input = new Subject(); - output = cacheWhileSubscribed(input); + input = new _rxjsBundlesRxMinJs.Subject(); + output = (0, (_observable || _load_observable()).cacheWhileSubscribed)(input); }); it('should provide cached values to late subscribers', () => { @@ -132,173 +128,150 @@ describe('nuclide-commons/observable', () => { describe('diffSets', () => { it('emits a diff for the first item', () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets()) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)()).toArray().toPromise(); source.next(new Set([1, 2, 3])); source.complete(); - const diffs = await diffsPromise; + const diffs = yield diffsPromise; expect(diffs.length).toBe(1); - expect( - diffsAreEqual(diffs[0], { - added: new Set([1, 2, 3]), - removed: new Set(), - }), - ).toBe(true); - }); + expect(diffsAreEqual(diffs[0], { + added: new Set([1, 2, 3]), + removed: new Set() + })).toBe(true); + })); }); it('correctly identifies removed items', () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets()) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)()).toArray().toPromise(); source.next(new Set([1, 2, 3])); source.next(new Set([1, 2])); source.complete(); - const diffs = await diffsPromise; + const diffs = yield diffsPromise; expect(setsAreEqual(diffs[1].removed, new Set([3]))).toBe(true); - }); + })); }); it('correctly identifies removed items when a hash function is used', () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets(x => x.key)) - .toArray() - .toPromise(); - const firstItems = [{key: 1}, {key: 2}, {key: 3}]; - const secondItems = [{key: 1}, {key: 2}]; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)(function (x) { + return x.key; + })).toArray().toPromise(); + const firstItems = [{ key: 1 }, { key: 2 }, { key: 3 }]; + const secondItems = [{ key: 1 }, { key: 2 }]; source.next(new Set(firstItems)); source.next(new Set(secondItems)); source.complete(); - const diffs = await diffsPromise; - expect(setsAreEqual(diffs[1].removed, new Set([firstItems[2]]))).toBe( - true, - ); - }); + const diffs = yield diffsPromise; + expect(setsAreEqual(diffs[1].removed, new Set([firstItems[2]]))).toBe(true); + })); }); it('correctly identifies added items', () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets()) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)()).toArray().toPromise(); source.next(new Set([1, 2])); source.next(new Set([1, 2, 3])); source.complete(); - const diffs = await diffsPromise; + const diffs = yield diffsPromise; expect(setsAreEqual(diffs[1].added, new Set([3]))).toBe(true); - }); + })); }); it('correctly identifies added items when a hash function is used', () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets(x => x.key)) - .toArray() - .toPromise(); - const firstItems = [{key: 1}, {key: 2}]; - const secondItems = [{key: 1}, {key: 2}, {key: 3}]; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)(function (x) { + return x.key; + })).toArray().toPromise(); + const firstItems = [{ key: 1 }, { key: 2 }]; + const secondItems = [{ key: 1 }, { key: 2 }, { key: 3 }]; source.next(new Set(firstItems)); source.next(new Set(secondItems)); source.complete(); - const diffs = await diffsPromise; - expect(setsAreEqual(diffs[1].added, new Set([secondItems[2]]))).toBe( - true, - ); - }); + const diffs = yield diffsPromise; + expect(setsAreEqual(diffs[1].added, new Set([secondItems[2]]))).toBe(true); + })); }); it("doesn't emit a diff when nothing changes", () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets()) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)()).toArray().toPromise(); source.next(new Set([1, 2, 3])); source.next(new Set([1, 2, 3])); source.complete(); - const diffs = await diffsPromise; + const diffs = yield diffsPromise; // Make sure we only get one diff (from the implicit initial empty set). expect(diffs.length).toBe(1); - }); + })); }); it("doesn't emit a diff when nothing changes and a hash function is used", () => { - waitsForPromise(async () => { - const source = new Subject(); - const diffsPromise = source - .let(diffSets(x => x.key)) - .toArray() - .toPromise(); - const firstItems = [{key: 1}, {key: 2}, {key: 3}]; - const secondItems = [{key: 1}, {key: 2}, {key: 3}]; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const diffsPromise = source.let((0, (_observable || _load_observable()).diffSets)(function (x) { + return x.key; + })).toArray().toPromise(); + const firstItems = [{ key: 1 }, { key: 2 }, { key: 3 }]; + const secondItems = [{ key: 1 }, { key: 2 }, { key: 3 }]; source.next(new Set(firstItems)); source.next(new Set(secondItems)); source.complete(); - const diffs = await diffsPromise; + const diffs = yield diffsPromise; // Make sure we only get one diff (from the implicit initial empty set). expect(diffs.length).toBe(1); - }); + })); }); }); describe('reconcileSetDiffs', () => { it("calls the add action for each item that's added", () => { - const diffs = new Subject(); - const addAction = jasmine - .createSpy() - .andReturn(new UniversalDisposable()); - reconcileSetDiffs(diffs, addAction); + const diffs = new _rxjsBundlesRxMinJs.Subject(); + const addAction = jasmine.createSpy().andReturn(new (_UniversalDisposable || _load_UniversalDisposable()).default()); + (0, (_observable || _load_observable()).reconcileSetDiffs)(diffs, addAction); diffs.next({ added: new Set(['a', 'b']), - removed: new Set(), + removed: new Set() }); expect(addAction.calls.map(call => call.args[0])).toEqual(['a', 'b']); }); it("disposes for each item that's removed", () => { - const diffs = new Subject(); + const diffs = new _rxjsBundlesRxMinJs.Subject(); const disposables = { a: createDisposable(), - b: createDisposable(), + b: createDisposable() }; const addAction = item => disposables[item]; - reconcileSetDiffs(diffs, addAction); + (0, (_observable || _load_observable()).reconcileSetDiffs)(diffs, addAction); diffs.next({ added: new Set(['a', 'b']), - removed: new Set(), + removed: new Set() }); diffs.next({ added: new Set(), - removed: new Set(['a', 'b']), + removed: new Set(['a', 'b']) }); expect(disposables.a.dispose).toHaveBeenCalled(); expect(disposables.b.dispose).toHaveBeenCalled(); }); it('disposes for all items when disposed', () => { - const diffs = new Subject(); + const diffs = new _rxjsBundlesRxMinJs.Subject(); const disposables = { a: createDisposable(), - b: createDisposable(), + b: createDisposable() }; const addAction = item => disposables[item]; - const reconciliationDisposable = reconcileSetDiffs(diffs, addAction); + const reconciliationDisposable = (0, (_observable || _load_observable()).reconcileSetDiffs)(diffs, addAction); diffs.next({ added: new Set(['a', 'b']), - removed: new Set(), + removed: new Set() }); reconciliationDisposable.dispose(); expect(disposables.a.dispose).toHaveBeenCalled(); @@ -306,20 +279,20 @@ describe('nuclide-commons/observable', () => { }); it("disposes for each item that's removed when a hash function is used", () => { - const diffs = new Subject(); + const diffs = new _rxjsBundlesRxMinJs.Subject(); const disposables = { a: createDisposable(), - b: createDisposable(), + b: createDisposable() }; const addAction = item => disposables[item.key]; - reconcileSetDiffs(diffs, addAction, x => x.key); + (0, (_observable || _load_observable()).reconcileSetDiffs)(diffs, addAction, x => x.key); diffs.next({ - added: new Set([{key: 'a'}, {key: 'b'}]), - removed: new Set(), + added: new Set([{ key: 'a' }, { key: 'b' }]), + removed: new Set() }); diffs.next({ added: new Set(), - removed: new Set([{key: 'a'}, {key: 'b'}]), + removed: new Set([{ key: 'a' }, { key: 'b' }]) }); expect(disposables.a.dispose).toHaveBeenCalled(); expect(disposables.b.dispose).toHaveBeenCalled(); @@ -327,22 +300,22 @@ describe('nuclide-commons/observable', () => { }); describe('toggle', () => { - let toggler: Subject = (null: any); - let source: Observable = (null: any); - let output: Observable = (null: any); - let outputArray: Array = (null: any); + let toggler = null; + let source = null; + let output = null; + let outputArray = null; beforeEach(() => { - toggler = new Subject(); + toggler = new _rxjsBundlesRxMinJs.Subject(); // Deferred so individual 'it' blocks can set the source on the fly. - output = Observable.defer(() => source).let(toggle(toggler)); + output = _rxjsBundlesRxMinJs.Observable.defer(() => source).let((0, (_observable || _load_observable()).toggle)(toggler)); }); describe('with a standard source', () => { - let realSource: Subject = (null: any); + let realSource = null; beforeEach(() => { - source = realSource = new Subject(); + source = realSource = new _rxjsBundlesRxMinJs.Subject(); outputArray = []; output.subscribe(x => outputArray.push(x)); }); @@ -370,7 +343,7 @@ describe('nuclide-commons/observable', () => { // that toggling off unsubscribes and then resubscribes. describe('subscription behavior', () => { beforeEach(() => { - source = Observable.of(1, 2, 3); + source = _rxjsBundlesRxMinJs.Observable.of(1, 2, 3); outputArray = []; output.subscribe(x => outputArray.push(x)); }); @@ -398,49 +371,41 @@ describe('nuclide-commons/observable', () => { describe('concatLatest', () => { it('should work with empty input', () => { - waitsForPromise(async () => { - const output = await concatLatest() - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield (0, (_observable || _load_observable()).concatLatest)().toArray().toPromise(); expect(output).toEqual([]); - }); + })); }); it('should work with several observables', () => { - waitsForPromise(async () => { - const output = await concatLatest( - Observable.of([], [1]), - Observable.of([2]), - Observable.of([3], [3, 4]), - ) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield (0, (_observable || _load_observable()).concatLatest)(_rxjsBundlesRxMinJs.Observable.of([], [1]), _rxjsBundlesRxMinJs.Observable.of([2]), _rxjsBundlesRxMinJs.Observable.of([3], [3, 4])).toArray().toPromise(); expect(output).toEqual([[], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]); - }); + })); }); }); describe('throttle', () => { it('emits the leading item immeditately by default', () => { - const source = Observable.of(1, 2).merge(Observable.never()); + const source = _rxjsBundlesRxMinJs.Observable.of(1, 2).merge(_rxjsBundlesRxMinJs.Observable.never()); const spy = jasmine.createSpy(); - source.let(throttle(Observable.never())).subscribe(spy); + source.let((0, (_observable || _load_observable()).throttle)(_rxjsBundlesRxMinJs.Observable.never())).subscribe(spy); expect(spy).toHaveBeenCalledWith(1); }); it("doesn't emit the leading item twice", () => { - const source = Observable.of(1).merge(Observable.never()); - const notifier = Observable.of(null); // emits immediately on subscription. + const source = _rxjsBundlesRxMinJs.Observable.of(1).merge(_rxjsBundlesRxMinJs.Observable.never()); + const notifier = _rxjsBundlesRxMinJs.Observable.of(null); // emits immediately on subscription. const spy = jasmine.createSpy(); - source.let(throttle(notifier)).subscribe(spy); + source.let((0, (_observable || _load_observable()).throttle)(notifier)).subscribe(spy); expect(spy.callCount).toBe(1); }); it('throttles', () => { - const source = new Subject(); - const notifier = new Subject(); + const source = new _rxjsBundlesRxMinJs.Subject(); + const notifier = new _rxjsBundlesRxMinJs.Subject(); const spy = jasmine.createSpy(); - source.let(throttle(notifier)).subscribe(spy); + source.let((0, (_observable || _load_observable()).throttle)(notifier)).subscribe(spy); source.next(1); spy.reset(); source.next(2); @@ -459,8 +424,8 @@ describe('nuclide-commons/observable', () => { it('subscribes to the source once per subscription', () => { const spy = jasmine.createSpy(); - const source = Observable.create(spy); - source.let(throttle(Observable.of(null))).subscribe(); + const source = _rxjsBundlesRxMinJs.Observable.create(spy); + source.let((0, (_observable || _load_observable()).throttle)(_rxjsBundlesRxMinJs.Observable.of(null))).subscribe(); expect(spy.callCount).toBe(1); }); }); @@ -481,13 +446,13 @@ describe('nuclide-commons/observable', () => { }); it('schedules next using requestAnimationFrame', () => { - const sub = nextAnimationFrame.subscribe(); + const sub = (_observable || _load_observable()).nextAnimationFrame.subscribe(); expect(window.requestAnimationFrame).toHaveBeenCalled(); sub.unsubscribe(); }); it('uses cancelAnimationFrame when unsubscribed', () => { - const sub = nextAnimationFrame.subscribe(); + const sub = (_observable || _load_observable()).nextAnimationFrame.subscribe(); expect(window.cancelAnimationFrame).not.toHaveBeenCalled(); sub.unsubscribe(); expect(window.cancelAnimationFrame).toHaveBeenCalled(); @@ -496,64 +461,51 @@ describe('nuclide-commons/observable', () => { describe('bufferUntil', () => { it('buffers based on the predicate', () => { - waitsForPromise(async () => { - const chunks = await Observable.of(1, 2, 3, 4) - .let(bufferUntil(x => x % 2 === 0)) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const chunks = yield _rxjsBundlesRxMinJs.Observable.of(1, 2, 3, 4).let((0, (_observable || _load_observable()).bufferUntil)(function (x) { + return x % 2 === 0; + })).toArray().toPromise(); expect(chunks).toEqual([[1, 2], [3, 4]]); - }); + })); }); it('provides the current buffer', () => { - waitsForPromise(async () => { - const chunks = await Observable.of(1, 2, 3, 4) - .let(bufferUntil((x, buffer) => buffer.length === 2)) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const chunks = yield _rxjsBundlesRxMinJs.Observable.of(1, 2, 3, 4).let((0, (_observable || _load_observable()).bufferUntil)(function (x, buffer) { + return buffer.length === 2; + })).toArray().toPromise(); expect(chunks).toEqual([[1, 2], [3, 4]]); - }); + })); }); }); describe('completingSwitchMap', () => { it('propagates completions to the inner observable', () => { - waitsForPromise(async () => { - const results = await Observable.of(1, 2) - .let( - completingSwitchMap(x => { - return Observable.concat( - Observable.of(x + 1), - Observable.never(), - ); - }), - ) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const results = yield _rxjsBundlesRxMinJs.Observable.of(1, 2).let((0, (_observable || _load_observable()).completingSwitchMap)(function (x) { + return _rxjsBundlesRxMinJs.Observable.concat(_rxjsBundlesRxMinJs.Observable.of(x + 1), _rxjsBundlesRxMinJs.Observable.never()); + })).toArray().toPromise(); expect(results).toEqual([2, 3]); - }); + })); }); }); describe('fastDebounce', () => { it('debounces events', () => { - waitsForPromise(async () => { - let nextSpy: JasmineSpy; - const originalCreate = Observable.create.bind(Observable); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + let nextSpy; + const originalCreate = _rxjsBundlesRxMinJs.Observable.create.bind(_rxjsBundlesRxMinJs.Observable); // Spy on the created observer's next to ensure that we always cancel // the last debounced timer on unsubscribe. - spyOn(Observable, 'create').andCallFake(callback => { - return originalCreate(observer => { + spyOn(_rxjsBundlesRxMinJs.Observable, 'create').andCallFake(function (callback) { + return originalCreate(function (observer) { nextSpy = spyOn(observer, 'next').andCallThrough(); return callback(observer); }); }); - const subject = new Subject(); - const promise = subject - .let(fastDebounce(10)) - .toArray() - .toPromise(); + const subject = new _rxjsBundlesRxMinJs.Subject(); + const promise = subject.let((0, (_observable || _load_observable()).fastDebounce)(10)).toArray().toPromise(); subject.next(1); subject.next(2); @@ -569,45 +521,45 @@ describe('nuclide-commons/observable', () => { subject.complete(); advanceClock(20); - expect(await promise).toEqual([2, 4]); - expect(nullthrows(nextSpy).callCount).toBe(2); - }); + expect((yield promise)).toEqual([2, 4]); + expect((0, (_nullthrows || _load_nullthrows()).default)(nextSpy).callCount).toBe(2); + })); }); it('passes errors through immediately', () => { let caught = false; - Observable.throw(1) - .let(fastDebounce(10)) - .subscribe({ - error() { - caught = true; - }, - }); + _rxjsBundlesRxMinJs.Observable.throw(1).let((0, (_observable || _load_observable()).fastDebounce)(10)).subscribe({ + error() { + caught = true; + } + }); expect(caught).toBe(true); }); }); describe('microtask', () => { it('is cancelable', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const spy = jasmine.createSpy(); - const sub = microtask.subscribe(spy); + const sub = (_observable || _load_observable()).microtask.subscribe(spy); let resolve; - const promise = new Promise(r => (resolve = r)); + const promise = new Promise(function (r) { + return resolve = r; + }); sub.unsubscribe(); - process.nextTick(() => { + process.nextTick(function () { expect(spy).not.toHaveBeenCalled(); resolve(); }); return promise; - }); + })); }); }); describe('macrotask', () => { it('is cancelable', () => { spyOn(global, 'clearImmediate').andCallThrough(); - const sub = macrotask.subscribe(() => {}); + const sub = (_observable || _load_observable()).macrotask.subscribe(() => {}); sub.unsubscribe(); expect(clearImmediate).toHaveBeenCalled(); }); @@ -615,64 +567,64 @@ describe('nuclide-commons/observable', () => { describe('toCancellablePromise', () => { it('completes successfully', () => { - waitsForPromise(async () => { - const source = new Subject(); - const cancelable = toCancelablePromise(source); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const cancelable = (0, (_observable || _load_observable()).toCancelablePromise)(source); source.next(42); source.complete(); - const result = await cancelable.promise; + const result = yield cancelable.promise; expect(result).toBe(42); - }); + })); }); it('error throws from promise', () => { - waitsForPromise(async () => { - const source = new Subject(); - const cancelable = toCancelablePromise(source); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const cancelable = (0, (_observable || _load_observable()).toCancelablePromise)(source); source.error(42); let thrown = false; try { - await cancelable.promise; + yield cancelable.promise; } catch (e) { expect(e).toBe(42); thrown = true; } expect(thrown).toBe(true); - }); + })); }); it('cancel causes promise to throw', () => { - waitsForPromise(async () => { - const source = new Subject(); - const cancelable = toCancelablePromise(source); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const cancelable = (0, (_observable || _load_observable()).toCancelablePromise)(source); cancelable.cancel(); let thrown = false; try { - await cancelable.promise; + yield cancelable.promise; } catch (e) { thrown = true; - expect(e instanceof PromiseCanceledError).toBe(true); + expect(e instanceof (_observable || _load_observable()).PromiseCanceledError).toBe(true); } expect(thrown).toBe(true); - }); + })); }); it('cancel after complete is a noop', () => { - waitsForPromise(async () => { - const source = new Subject(); - const cancelable = toCancelablePromise(source); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const cancelable = (0, (_observable || _load_observable()).toCancelablePromise)(source); source.next(42); source.complete(); cancelable.cancel(); - const result = await cancelable.promise; + const result = yield cancelable.promise; expect(result).toBe(42); - }); + })); }); it('cancel after error is a noop', () => { - waitsForPromise(async () => { - const source = new Subject(); - const cancelable = toCancelablePromise(source); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const source = new _rxjsBundlesRxMinJs.Subject(); + const cancelable = (0, (_observable || _load_observable()).toCancelablePromise)(source); source.error(42); let thrown = false; @@ -680,22 +632,22 @@ describe('nuclide-commons/observable', () => { cancelable.cancel(); try { - await cancelable.promise; + yield cancelable.promise; } catch (e) { expect(e).toBe(42); thrown = true; } expect(thrown).toBe(true); - }); + })); }); }); describe('SingletonExecutor', () => { it('isExecuting()', () => { - const executor = new SingletonExecutor(); + const executor = new (_observable || _load_observable()).SingletonExecutor(); expect(executor.isExecuting()).toBe(false); - const source = new Subject(); + const source = new _rxjsBundlesRxMinJs.Subject(); const result = executor.execute(source); result.catch(() => 'silence unhandled promise rejection warning'); expect(executor.isExecuting()).toBe(true); @@ -705,24 +657,24 @@ describe('nuclide-commons/observable', () => { }); it('completing task normally', () => { - waitsForPromise(async () => { - const executor = new SingletonExecutor(); - const source = new Subject(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const executor = new (_observable || _load_observable()).SingletonExecutor(); + const source = new _rxjsBundlesRxMinJs.Subject(); const result = executor.execute(source); expect(executor.isExecuting()).toBe(true); source.next(42); source.complete(); - expect(await result).toBe(42); + expect((yield result)).toBe(42); expect(executor.isExecuting()).toBe(false); - }); + })); }); it('completing task by error', () => { - waitsForPromise(async () => { - const executor = new SingletonExecutor(); - const source = new Subject(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const executor = new (_observable || _load_observable()).SingletonExecutor(); + const source = new _rxjsBundlesRxMinJs.Subject(); const result = executor.execute(source); expect(executor.isExecuting()).toBe(true); @@ -730,33 +682,33 @@ describe('nuclide-commons/observable', () => { source.error(42); let thrown = false; try { - await result; + yield result; } catch (e) { expect(e).toBe(42); thrown = true; } expect(executor.isExecuting()).toBe(false); expect(thrown).toBe(true); - }); + })); }); it('scheduling second task while first is in flight', () => { - waitsForPromise(async () => { - const executor = new SingletonExecutor(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const executor = new (_observable || _load_observable()).SingletonExecutor(); - const source1 = new Subject(); + const source1 = new _rxjsBundlesRxMinJs.Subject(); const result1 = executor.execute(source1); expect(executor.isExecuting()).toBe(true); - const source2 = new Subject(); + const source2 = new _rxjsBundlesRxMinJs.Subject(); const result2 = executor.execute(source2); expect(executor.isExecuting()).toBe(true); let thrown = false; try { - await result1; + yield result1; } catch (e) { - expect(e instanceof PromiseCanceledError).toBe(true); + expect(e instanceof (_observable || _load_observable()).PromiseCanceledError).toBe(true); thrown = true; } expect(executor.isExecuting()).toBe(true); @@ -765,9 +717,9 @@ describe('nuclide-commons/observable', () => { source2.next(42); source2.complete(); - expect(await result2).toBe(42); + expect((yield result2)).toBe(42); expect(executor.isExecuting()).toBe(false); - }); + })); }); }); @@ -778,9 +730,9 @@ describe('nuclide-commons/observable', () => { }); it('subscribes to the observable synchronously', () => { - const source = Observable.never(); + const source = _rxjsBundlesRxMinJs.Observable.never(); const spy = spyOn(source, 'subscribe').andCallThrough(); - const sub = source.let(poll(10)).subscribe(); + const sub = source.let((0, (_observable || _load_observable()).poll)(10)).subscribe(); expect(spy.callCount).toBe(1); sub.unsubscribe(); }); @@ -790,11 +742,11 @@ describe('nuclide-commons/observable', () => { let spy; let mostRecentObserver; runs(() => { - const source = Observable.create(observer => { + const source = _rxjsBundlesRxMinJs.Observable.create(observer => { mostRecentObserver = observer; }); spy = spyOn(source, 'subscribe').andCallThrough(); - sub = source.let(poll(10)).subscribe(); + sub = source.let((0, (_observable || _load_observable()).poll)(10)).subscribe(); expect(spy.callCount).toBe(1); mostRecentObserver.next(); }); @@ -819,12 +771,10 @@ describe('nuclide-commons/observable', () => { it("doesn't resubscribe to the source when you unsubscribe", () => { let spy; runs(() => { - const source = new Subject(); + const source = new _rxjsBundlesRxMinJs.Subject(); spy = spyOn(source, 'subscribe').andCallThrough(); - source - .let(poll(10)) - .take(1) // This will unsubscribe after the first element. - .subscribe(); + source.let((0, (_observable || _load_observable()).poll)(10)).take(1) // This will unsubscribe after the first element. + .subscribe(); expect(spy.callCount).toBe(1); source.next(); }); @@ -835,19 +785,14 @@ describe('nuclide-commons/observable', () => { }); it('polls synchronously completing observables', () => { - waitsForPromise(async () => { - const result = await Observable.of('hi') - .let(poll(10)) - .take(2) - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const result = yield _rxjsBundlesRxMinJs.Observable.of('hi').let((0, (_observable || _load_observable()).poll)(10)).take(2).toArray().toPromise(); expect(result).toEqual(['hi', 'hi']); - }); + })); }); }); }); -const sleep = n => - new Promise(resolve => { - setTimeout(resolve, n); - }); +const sleep = n => new Promise(resolve => { + setTimeout(resolve, n); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/process-spec.js b/modules/nuclide-commons/spec/process-spec.js index 91bd32e9..c049ac2b 100644 --- a/modules/nuclide-commons/spec/process-spec.js +++ b/modules/nuclide-commons/spec/process-spec.js @@ -1,41 +1,32 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {ProcessExitMessage} from '../process'; - -import EventEmitter from 'events'; -import {getLogger} from 'log4js'; -import {sleep} from '../promise'; -import child_process from 'child_process'; -import invariant from 'assert'; -import {Observable, Scheduler, Subject} from 'rxjs'; - -import { - spawn, - getOutputStream, - killProcess, - killUnixProcessTree, - logStreamErrors, - observeProcess, - observeProcessRaw, - parsePsOutput, - preventStreamsFromThrowing, - ProcessSystemError, - runCommand, - runCommandDetailed, - scriptifyCommand, - exitEventToMessage, - LOG_CATEGORY, -} from '../process'; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _events = _interopRequireDefault(require('events')); + +var _log4js; + +function _load_log4js() { + return _log4js = require('log4js'); +} + +var _promise; + +function _load_promise() { + return _promise = require('../promise'); +} + +var _child_process = _interopRequireDefault(require('child_process')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _process; + +function _load_process() { + return _process = require('../process'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('commons-node/process', () => { let origPlatform; @@ -44,214 +35,177 @@ describe('commons-node/process', () => { origPlatform = process.platform; // Use a fake platform so the platform's PATH is not used in case the test is run on a platform // that requires special handling (like OS X). - Object.defineProperty(process, 'platform', {value: 'MockMock'}); + Object.defineProperty(process, 'platform', { value: 'MockMock' }); }); afterEach(() => { - Object.defineProperty(process, 'platform', {value: origPlatform}); + Object.defineProperty(process, 'platform', { value: origPlatform }); }); describe('process.killProcess', () => { it('should only kill the process when `killTree` is false', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const proc = { - kill: jasmine.createSpy(), + kill: jasmine.createSpy() }; spyOn(console, 'log'); // suppress log printing - await killProcess((proc: any), false); + yield (0, (_process || _load_process()).killProcess)(proc, false); expect(proc.kill).toHaveBeenCalled(); - }); + })); }); it('should kill the process tree when `killTree` is true', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { jasmine.useRealClock(); // Create a tree that's more than level child deep. - const proc = child_process.spawn('bash', [ - '-c', - '( (sleep 1000)& sleep 1000 )& wait', - ]); + const proc = _child_process.default.spawn('bash', ['-c', '( (sleep 1000)& sleep 1000 )& wait']); spyOn(console, 'log'); // suppress log printing spyOn(process, 'kill').andCallThrough(); - await sleep(250); // Give some time for the processes to spawn. - await killUnixProcessTree(proc); + yield (0, (_promise || _load_promise()).sleep)(250); // Give some time for the processes to spawn. + yield (0, (_process || _load_process()).killUnixProcessTree)(proc); expect(process.kill.callCount).toBeGreaterThan(2); - }); + })); }); it('should kill the process tree on windows when `killTree` is true', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const proc = { - pid: 123, + pid: 123 }; spyOn(console, 'log'); // suppress log printing - Object.defineProperty(process, 'platform', {value: 'win32'}); - spyOn(child_process, 'exec'); - await killProcess((proc: any), true); - expect(child_process.exec.calls.length).toBe(1); - expect(child_process.exec.calls[0].args[0]).toBe( - `taskkill /pid ${proc.pid} /T /F`, - ); - }); + Object.defineProperty(process, 'platform', { value: 'win32' }); + spyOn(_child_process.default, 'exec'); + yield (0, (_process || _load_process()).killProcess)(proc, true); + expect(_child_process.default.exec.calls.length).toBe(1); + expect(_child_process.default.exec.calls[0].args[0]).toBe(`taskkill /pid ${proc.pid} /T /F`); + })); }); }); describe('process.parsePsOutput', () => { it('parse `ps` unix output', () => { - const unixPsOut = - ' PPID PID COMM\n' + - ' 0 1 /sbin/launchd\n' + - ' 1 42 command with spaces'; - const processList = parsePsOutput(unixPsOut); - expect(processList).toEqual([ - { - command: '/sbin/launchd', - pid: 1, - parentPid: 0, - commandWithArgs: '/sbin/launchd', - }, - { - command: 'command with spaces', - pid: 42, - parentPid: 1, - commandWithArgs: 'command with spaces', - }, - ]); + const unixPsOut = ' PPID PID COMM\n' + ' 0 1 /sbin/launchd\n' + ' 1 42 command with spaces'; + const processList = (0, (_process || _load_process()).parsePsOutput)(unixPsOut); + expect(processList).toEqual([{ + command: '/sbin/launchd', + pid: 1, + parentPid: 0, + commandWithArgs: '/sbin/launchd' + }, { + command: 'command with spaces', + pid: 42, + parentPid: 1, + commandWithArgs: 'command with spaces' + }]); }); it('parse `ps` unix output with command arguments', () => { - const unixPsOut = - ' PPID PID COMM\n' + - ' 0 1 /sbin/launchd\n' + - ' 1 42 command with spaces'; - - const unixPsOutWithArgs = - ' PID ARGS\n' + - ' 1 /sbin/launchd\n' + - ' 42 command with spaces and some more arguments'; - - const processList = parsePsOutput(unixPsOut, unixPsOutWithArgs); - expect(processList).toEqual([ - { - command: '/sbin/launchd', - pid: 1, - parentPid: 0, - commandWithArgs: '/sbin/launchd', - }, - { - command: 'command with spaces', - pid: 42, - parentPid: 1, - commandWithArgs: 'command with spaces and some more arguments', - }, - ]); + const unixPsOut = ' PPID PID COMM\n' + ' 0 1 /sbin/launchd\n' + ' 1 42 command with spaces'; + + const unixPsOutWithArgs = ' PID ARGS\n' + ' 1 /sbin/launchd\n' + ' 42 command with spaces and some more arguments'; + + const processList = (0, (_process || _load_process()).parsePsOutput)(unixPsOut, unixPsOutWithArgs); + expect(processList).toEqual([{ + command: '/sbin/launchd', + pid: 1, + parentPid: 0, + commandWithArgs: '/sbin/launchd' + }, { + command: 'command with spaces', + pid: 42, + parentPid: 1, + commandWithArgs: 'command with spaces and some more arguments' + }]); }); it('parse `ps` windows output', () => { - const windowsProcessOut = - 'ParentProcessId ProcessId Name\r\n' + - ' 0 4 System Process\r\n' + - ' 4 228 smss.exe'; - - const processList = parsePsOutput(windowsProcessOut); - expect(processList).toEqual([ - { - command: 'System Process', - pid: 4, - parentPid: 0, - commandWithArgs: 'System Process', - }, - { - command: 'smss.exe', - pid: 228, - parentPid: 4, - commandWithArgs: 'smss.exe', - }, - ]); + const windowsProcessOut = 'ParentProcessId ProcessId Name\r\n' + ' 0 4 System Process\r\n' + ' 4 228 smss.exe'; + + const processList = (0, (_process || _load_process()).parsePsOutput)(windowsProcessOut); + expect(processList).toEqual([{ + command: 'System Process', + pid: 4, + parentPid: 0, + commandWithArgs: 'System Process' + }, { + command: 'smss.exe', + pid: 228, + parentPid: 4, + commandWithArgs: 'smss.exe' + }]); }); }); describe('getOutputStream', () => { it('captures stdout, stderr and exitCode', () => { - waitsForPromise(async () => { - const child = child_process.spawn(process.execPath, [ - '-e', - 'console.error("stderr"); console.log("std out"); process.exit(0);', - ]); - const results = await getOutputStream(child) - .toArray() - .toPromise(); - expect(results).toEqual([ - {kind: 'stderr', data: 'stderr\n'}, - {kind: 'stdout', data: 'std out\n'}, - {kind: 'exit', exitCode: 0, signal: null}, - ]); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const child = _child_process.default.spawn(process.execPath, ['-e', 'console.error("stderr"); console.log("std out"); process.exit(0);']); + const results = yield (0, (_process || _load_process()).getOutputStream)(child).toArray().toPromise(); + expect(results).toEqual([{ kind: 'stderr', data: 'stderr\n' }, { kind: 'stdout', data: 'std out\n' }, { kind: 'exit', exitCode: 0, signal: null }]); + })); }); it('errors on nonzero exit codes by default', () => { - waitsForPromise(async () => { - const child = child_process.spawn(process.execPath, [ - '-e', - 'console.error("stderr"); console.log("std out"); process.exit(42);', - ]); - const results = await getOutputStream(child) - // $FlowIssue: Add materialize to type defs - .materialize() - .toArray() - .toPromise(); - expect(results.map(notification => notification.kind)).toEqual([ - 'N', - 'N', - 'E', - ]); - const {error} = results[2]; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const child = _child_process.default.spawn(process.execPath, ['-e', 'console.error("stderr"); console.log("std out"); process.exit(42);']); + const results = yield (0, (_process || _load_process()).getOutputStream)(child) + // $FlowIssue: Add materialize to type defs + .materialize().toArray().toPromise(); + expect(results.map(function (notification) { + return notification.kind; + })).toEqual(['N', 'N', 'E']); + const { error } = results[2]; expect(error.name).toBe('ProcessExitError'); expect(error.exitCode).toBe(42); expect(error.stderr).toBe('stderr\n'); - }); + })); }); it('accumulates the first `exitErrorBufferSize` bytes of stderr for the exit error', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; - const child = child_process.spawn(process.execPath, [ - '-e', - 'console.error("stderr"); process.exit(42);', - ]); + const child = _child_process.default.spawn(process.execPath, ['-e', 'console.error("stderr"); process.exit(42);']); try { - await getOutputStream(child, { + yield (0, (_process || _load_process()).getOutputStream)(child, { exitErrorBufferSize: 2, - isExitError: () => true, - }) - .toArray() - .toPromise(); + isExitError: function () { + return true; + } + }).toArray().toPromise(); } catch (err) { error = err; } expect(error).toBeDefined(); - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.stderr).toBe('st'); - }); + })); }); }); describe('spawn', () => { it('errors when the process does', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { spyOn(console, 'log'); // suppress log printing - const processStream = spawn('fakeCommand'); + const processStream = (0, (_process || _load_process()).spawn)('fakeCommand'); let error; try { - await processStream.toPromise(); + yield processStream.toPromise(); } catch (err) { error = err; } expect(error).toBeDefined(); - invariant(error); + + if (!error) { + throw new Error('Invariant violation: "error"'); + } + expect(error.code).toBe('ENOENT'); expect(error.name).toBe('ProcessSystemError'); - }); + })); }); // Node delays the emission of the error until after the process is returned so that you have a @@ -259,184 +213,174 @@ describe('commons-node/process', () => { // event-emitter APIs, so we can do better and not emit the process if there was an error // spawning it. it('errors before emitting the process', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { spyOn(console, 'log'); // suppress log printing let proc; - await spawn('fakeCommand') - .do(p => { - proc = p; - }) - .catch(err => { - expect(proc).toBeUndefined(); - expect(err.code).toBe('ENOENT'); - expect(err.name).toBe('ProcessSystemError'); - return Observable.empty(); - }) - .toPromise(); - }); + yield (0, (_process || _load_process()).spawn)('fakeCommand').do(function (p) { + proc = p; + }).catch(function (err) { + expect(proc).toBeUndefined(); + expect(err.code).toBe('ENOENT'); + expect(err.name).toBe('ProcessSystemError'); + return _rxjsBundlesRxMinJs.Observable.empty(); + }).toPromise(); + })); }); it('leaves an error handler when you unsubscribe', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { spyOn(console, 'log'); // suppress log printing let resolve; - const promise = new Promise(r => { + const promise = new Promise(function (r) { resolve = r; }); - const sub = spawn('cat') - // If we subscribe synchronously, and it emits synchronously, `sub` won't have been - // assigned yet in our `subscribe()` callback, so we use the async scheduler. - .subscribeOn(Scheduler.async) - .subscribe(proc => { - // As soon as we have a process, unsubscribe. This will happen before the error is - // thrown. - sub.unsubscribe(); - - // Make sure that the error handler is still registered. If it isn't, and the process - // errors, node will consider the error unhandled and we'll get a redbox. - expect(proc.listenerCount('error')).toBe(1); - - resolve(); - }); - await promise; - }); + const sub = (0, (_process || _load_process()).spawn)('cat') + // If we subscribe synchronously, and it emits synchronously, `sub` won't have been + // assigned yet in our `subscribe()` callback, so we use the async scheduler. + .subscribeOn(_rxjsBundlesRxMinJs.Scheduler.async).subscribe(function (proc) { + // As soon as we have a process, unsubscribe. This will happen before the error is + // thrown. + sub.unsubscribe(); + + // Make sure that the error handler is still registered. If it isn't, and the process + // errors, node will consider the error unhandled and we'll get a redbox. + expect(proc.listenerCount('error')).toBe(1); + + resolve(); + }); + yield promise; + })); }); it('can be retried', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { spyOn(console, 'log'); // suppress log printing - spyOn(child_process, 'spawn'); + spyOn(_child_process.default, 'spawn'); try { - await spawn('fakeCommand') - .retryWhen(errors => - errors.scan((errorCount, err) => { - // If this is the third time the process has errored (i.e. the have already been - // two errors before), stop retrying. (We try 3 times because because Rx 3 and 4 - // have bugs with retrying shared observables that would give false negatives for - // this test if we only tried twice.) - if (errorCount === 2) { - throw err; - } - return errorCount + 1; - }, 0), - ) - .toPromise(); + yield (0, (_process || _load_process()).spawn)('fakeCommand').retryWhen(function (errors) { + return errors.scan(function (errorCount, err) { + // If this is the third time the process has errored (i.e. the have already been + // two errors before), stop retrying. (We try 3 times because because Rx 3 and 4 + // have bugs with retrying shared observables that would give false negatives for + // this test if we only tried twice.) + if (errorCount === 2) { + throw err; + } + return errorCount + 1; + }, 0); + }).toPromise(); } catch (err) {} - expect(child_process.spawn.callCount).toBe(3); - }); + expect(_child_process.default.spawn.callCount).toBe(3); + })); }); it('can be timed out', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; let proc; try { - await spawn('sleep', ['10000'], {timeout: 1}) - .do(p => { - proc = p; - spyOn(proc, 'kill'); - }) - .toPromise(); + yield (0, (_process || _load_process()).spawn)('sleep', ['10000'], { timeout: 1 }).do(function (p) { + proc = p; + spyOn(proc, 'kill'); + }).toPromise(); } catch (err) { error = err; } - invariant(proc != null); - invariant(error != null); + + if (!(proc != null)) { + throw new Error('Invariant violation: "proc != null"'); + } + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.name).toBe('ProcessTimeoutError'); expect(proc.kill).toHaveBeenCalled(); - }); + })); }); }); describe('observeProcess', () => { it('errors when the process does', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { spyOn(console, 'log'); // suppress log printing - const processStream = observeProcess('fakeCommand', []); + const processStream = (0, (_process || _load_process()).observeProcess)('fakeCommand', []); let error; try { - await processStream.toPromise(); + yield processStream.toPromise(); } catch (err) { error = err; } expect(error).toBeDefined(); - invariant(error); + + if (!error) { + throw new Error('Invariant violation: "error"'); + } + expect(error.code).toBe('ENOENT'); expect(error.name).toBe('ProcessSystemError'); - }); + })); }); it('errors on nonzero exit codes by default', () => { - waitsForPromise(async () => { - const results = await observeProcess(process.execPath, [ - '-e', - 'console.error("stderr"); console.log("std out"); process.exit(42);', - ]) - // $FlowIssue: Add materialize to type defs - .materialize() - .toArray() - .toPromise(); - expect(results.map(notification => notification.kind)).toEqual([ - 'N', - 'N', - 'E', - ]); - const {error} = results[2]; + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const results = yield (0, (_process || _load_process()).observeProcess)(process.execPath, ['-e', 'console.error("stderr"); console.log("std out"); process.exit(42);']) + // $FlowIssue: Add materialize to type defs + .materialize().toArray().toPromise(); + expect(results.map(function (notification) { + return notification.kind; + })).toEqual(['N', 'N', 'E']); + const { error } = results[2]; expect(error.name).toBe('ProcessExitError'); expect(error.exitCode).toBe(42); expect(error.stderr).toBe('stderr\n'); - }); + })); }); it("doesn't get an exit message when there's an exit error", () => { - waitsForPromise(async () => { - const results = await observeProcess(process.execPath, [ - '-e', - 'process.exit(42);', - ]) - // $FlowIssue: Add materialize to type defs - .materialize() - .toArray() - .toPromise(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const results = yield (0, (_process || _load_process()).observeProcess)(process.execPath, ['-e', 'process.exit(42);']) + // $FlowIssue: Add materialize to type defs + .materialize().toArray().toPromise(); expect(results.length).toBe(1); expect(results[0].kind).toBe('E'); - }); + })); }); it('accumulates the first `exitErrorBufferSize` bytes of stderr for the exit error', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await observeProcess( - process.execPath, - ['-e', 'console.error("stderr"); process.exit(42);'], - {exitErrorBufferSize: 2, isExitError: () => true}, - ) - .toArray() - .toPromise(); + yield (0, (_process || _load_process()).observeProcess)(process.execPath, ['-e', 'console.error("stderr"); process.exit(42);'], { exitErrorBufferSize: 2, isExitError: function () { + return true; + } }).toArray().toPromise(); } catch (err) { error = err; } expect(error).toBeDefined(); - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.stderr).toBe('st'); - }); + })); }); }); describe('observeProcessRaw', () => { it("doesn't split on line breaks", () => { spyOn(console, 'log'); // suppress log printing - waitsForPromise({timeout: 1000}, async () => { - const event = await observeProcessRaw(process.execPath, [ - '-e', - 'process.stdout.write("stdout1\\nstdout2\\n"); process.exit(1)', - ]) - .take(1) - .toPromise(); - invariant(event.kind === 'stdout'); + waitsForPromise({ timeout: 1000 }, (0, _asyncToGenerator.default)(function* () { + const event = yield (0, (_process || _load_process()).observeProcessRaw)(process.execPath, ['-e', 'process.stdout.write("stdout1\\nstdout2\\n"); process.exit(1)']).take(1).toPromise(); + + if (!(event.kind === 'stdout')) { + throw new Error('Invariant violation: "event.kind === \'stdout\'"'); + } + expect(event.data).toBe('stdout1\nstdout2\n'); - }); + })); }); }); @@ -451,145 +395,150 @@ describe('commons-node/process', () => { } it('sends the stdin to the process', () => { - waitsForPromise(async () => { - const output = await runCommand('cat', [], { - input: 'hello', + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield (0, (_process || _load_process()).runCommand)('cat', [], { + input: 'hello' }).toPromise(); expect(output).toBe('hello'); - }); + })); }); it('sends a stream of stdin to the process', () => { - waitsForPromise(async () => { - const input = new Subject(); - const outputPromise = runCommand('cat', [], { - input, + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const input = new _rxjsBundlesRxMinJs.Subject(); + const outputPromise = (0, (_process || _load_process()).runCommand)('cat', [], { + input }).toPromise(); input.next('hello'); input.next(' '); input.next('world'); input.complete(); - expect(await outputPromise).toBe('hello world'); - }); + expect((yield outputPromise)).toBe('hello world'); + })); }); it('enforces maxBuffer', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommand('yes', [], {maxBuffer: 100}).toPromise(); + yield (0, (_process || _load_process()).runCommand)('yes', [], { maxBuffer: 100 }).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.message).toContain('maxBuffer'); - }); + })); }); it('returns stdout of the running process', () => { - waitsForPromise(async () => { - const val = await runCommand('echo', ['-n', 'foo'], { - env: process.env, + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const val = yield (0, (_process || _load_process()).runCommand)('echo', ['-n', 'foo'], { + env: process.env }).toPromise(); expect(val).toEqual('foo'); - }); + })); }); it("throws an error if the process can't be spawned", () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommand('fakeCommand').toPromise(); + yield (0, (_process || _load_process()).runCommand)('fakeCommand').toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.code).toBe('ENOENT'); expect(error.name).toBe('ProcessSystemError'); - }); + })); }); it('throws an error if the exit code !== 0', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommand(process.execPath, [ - '-e', - 'process.exit(1)', - ]).toPromise(); + yield (0, (_process || _load_process()).runCommand)(process.execPath, ['-e', 'process.exit(1)']).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.name).toBe('ProcessExitError'); expect(error.exitCode).toBe(1); - }); + })); }); it('includes stdout and stderr in ProcessExitErrors', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommand(process.execPath, [ - '-e', - 'process.stderr.write("oopsy"); process.stdout.write("daisy"); process.exit(1)', - ]).toPromise(); + yield (0, (_process || _load_process()).runCommand)(process.execPath, ['-e', 'process.stderr.write("oopsy"); process.stdout.write("daisy"); process.exit(1)']).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.name).toBe('ProcessExitError'); expect(error.stderr).toBe('oopsy'); expect(error.stdout).toBe('daisy'); - }); + })); }); it('accumulates the stderr if the process exits with a non-zero code', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommand(process.execPath, [ - '-e', - 'process.stderr.write("oopsy"); process.exit(1)', - ]).toPromise(); + yield (0, (_process || _load_process()).runCommand)(process.execPath, ['-e', 'process.stderr.write("oopsy"); process.exit(1)']).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.stderr).toBe('oopsy'); - }); + })); }); // Previously we had a bug where we mutated the seed and subsequent subscriptions would use the // mutated value. it("doesn't share a mutable seed (regression test)", () => { - waitsForPromise(async () => { - const observable = runCommand(process.execPath, [ - '-e', - 'process.stdout.write("hello"); process.exit(0)', - ]); - await observable.toPromise(); - expect(await observable.toPromise()).toBe('hello'); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const observable = (0, (_process || _load_process()).runCommand)(process.execPath, ['-e', 'process.stdout.write("hello"); process.exit(0)']); + yield observable.toPromise(); + expect((yield observable.toPromise())).toBe('hello'); + })); }); describe('checkOutput compatibility', () => { if (origPlatform !== 'win32') { it('returns stdout of the running process', () => { - waitsForPromise(async () => { - const val = await runCommand('echo', ['-n', 'foo'], { - env: process.env, + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const val = yield (0, (_process || _load_process()).runCommand)('echo', ['-n', 'foo'], { + env: process.env }).toPromise(); expect(val).toEqual('foo'); - }); + })); }); it('throws an error if the exit code !== 0', () => { - waitsForPromise({shouldReject: true}, async () => { - await runCommand(process.execPath, [ - '-e', - 'process.exit(1)', - ]).toPromise(); - }); + waitsForPromise({ shouldReject: true }, (0, _asyncToGenerator.default)(function* () { + yield (0, (_process || _load_process()).runCommand)(process.execPath, ['-e', 'process.exit(1)']).toPromise(); + })); }); } }); @@ -606,105 +555,110 @@ describe('commons-node/process', () => { } it('sends the stdin to the process', () => { - waitsForPromise(async () => { - const output = await runCommandDetailed('cat', [], { - input: 'hello', + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield (0, (_process || _load_process()).runCommandDetailed)('cat', [], { + input: 'hello' }).toPromise(); expect(output.stdout).toBe('hello'); - }); + })); }); it('enforces maxBuffer', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommandDetailed('yes', [], {maxBuffer: 100}).toPromise(); + yield (0, (_process || _load_process()).runCommandDetailed)('yes', [], { maxBuffer: 100 }).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.message).toContain('maxBuffer'); - }); + })); }); it('returns stdout, stderr, and the exit code of the running process', () => { - waitsForPromise(async () => { - const val = await runCommandDetailed(process.execPath, [ - '-e', - 'process.stdout.write("out"); process.stderr.write("err"); process.exit(0)', - ]).toPromise(); - expect(val).toEqual({stdout: 'out', stderr: 'err', exitCode: 0}); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const val = yield (0, (_process || _load_process()).runCommandDetailed)(process.execPath, ['-e', 'process.stdout.write("out"); process.stderr.write("err"); process.exit(0)']).toPromise(); + expect(val).toEqual({ stdout: 'out', stderr: 'err', exitCode: 0 }); + })); }); it("throws an error if the process can't be spawned", () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommandDetailed('fakeCommand').toPromise(); + yield (0, (_process || _load_process()).runCommandDetailed)('fakeCommand').toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.code).toBe('ENOENT'); expect(error.name).toBe('ProcessSystemError'); - }); + })); }); it('throws an error if the exit code !== 0', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommandDetailed(process.execPath, [ - '-e', - 'process.exit(1)', - ]).toPromise(); + yield (0, (_process || _load_process()).runCommandDetailed)(process.execPath, ['-e', 'process.exit(1)']).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.name).toBe('ProcessExitError'); expect(error.exitCode).toBe(1); - }); + })); }); it('accumulates the stderr if the process exits with a non-zero code', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let error; try { - await runCommandDetailed(process.execPath, [ - '-e', - 'process.stderr.write("oopsy"); process.exit(1)', - ]).toPromise(); + yield (0, (_process || _load_process()).runCommandDetailed)(process.execPath, ['-e', 'process.stderr.write("oopsy"); process.exit(1)']).toPromise(); } catch (err) { error = err; } - invariant(error != null); + + if (!(error != null)) { + throw new Error('Invariant violation: "error != null"'); + } + expect(error.stderr).toBe('oopsy'); - }); + })); }); }); describe('exitEventToMessage', () => { it('exitCode', () => { - expect(exitEventToMessage(makeExitMessage(1))).toBe('exit code 1'); + expect((0, (_process || _load_process()).exitEventToMessage)(makeExitMessage(1))).toBe('exit code 1'); }); it('signal', () => { - expect( - exitEventToMessage({kind: 'exit', exitCode: null, signal: 'SIGTERM'}), - ).toBe('signal SIGTERM'); + expect((0, (_process || _load_process()).exitEventToMessage)({ kind: 'exit', exitCode: null, signal: 'SIGTERM' })).toBe('signal SIGTERM'); }); }); describe('preventStreamsFromThrowing', () => { - let proc: child_process$ChildProcess; + let proc; beforeEach(() => { - proc = ({ - stdin: new EventEmitter(), - stdout: new EventEmitter(), - stderr: new EventEmitter(), - }: any); + proc = { + stdin: new _events.default(), + stdout: new _events.default(), + stderr: new _events.default() + }; spyOn(proc.stdin, 'addListener').andCallThrough(); spyOn(proc.stdout, 'addListener').andCallThrough(); spyOn(proc.stderr, 'addListener').andCallThrough(); @@ -714,48 +668,30 @@ describe('commons-node/process', () => { }); it('adds listeners', () => { - preventStreamsFromThrowing(proc); - expect(proc.stdin.addListener).toHaveBeenCalledWith( - 'error', - jasmine.any(Function), - ); - expect(proc.stdout.addListener).toHaveBeenCalledWith( - 'error', - jasmine.any(Function), - ); - expect(proc.stderr.addListener).toHaveBeenCalledWith( - 'error', - jasmine.any(Function), - ); + (0, (_process || _load_process()).preventStreamsFromThrowing)(proc); + expect(proc.stdin.addListener).toHaveBeenCalledWith('error', jasmine.any(Function)); + expect(proc.stdout.addListener).toHaveBeenCalledWith('error', jasmine.any(Function)); + expect(proc.stderr.addListener).toHaveBeenCalledWith('error', jasmine.any(Function)); }); it('removes listeners when disposed', () => { - const disposable = preventStreamsFromThrowing(proc); + const disposable = (0, (_process || _load_process()).preventStreamsFromThrowing)(proc); disposable.dispose(); - expect(proc.stdin.removeListener).toHaveBeenCalledWith( - 'error', - jasmine.any(Function), - ); - expect(proc.stdout.removeListener).toHaveBeenCalledWith( - 'error', - jasmine.any(Function), - ); - expect(proc.stderr.removeListener).toHaveBeenCalledWith( - 'error', - jasmine.any(Function), - ); + expect(proc.stdin.removeListener).toHaveBeenCalledWith('error', jasmine.any(Function)); + expect(proc.stdout.removeListener).toHaveBeenCalledWith('error', jasmine.any(Function)); + expect(proc.stderr.removeListener).toHaveBeenCalledWith('error', jasmine.any(Function)); }); }); describe('logStreamErrors', () => { - const logger = getLogger(LOG_CATEGORY); - let proc: child_process$ChildProcess; + const logger = (0, (_log4js || _load_log4js()).getLogger)((_process || _load_process()).LOG_CATEGORY); + let proc; beforeEach(() => { - proc = ({ - stdin: new EventEmitter(), - stdout: new EventEmitter(), - stderr: new EventEmitter(), - }: any); + proc = { + stdin: new _events.default(), + stdout: new _events.default(), + stderr: new _events.default() + }; // Add a no-op listener so the error events aren't thrown. proc.stdin.on('error', () => {}); @@ -764,14 +700,14 @@ describe('commons-node/process', () => { }); it('logs errors', () => { - logStreamErrors(proc, 'test', [], {}); + (0, (_process || _load_process()).logStreamErrors)(proc, 'test', [], {}); spyOn(logger, 'error'); proc.stderr.emit('error', new Error('Test error')); expect(logger.error).toHaveBeenCalled(); }); it("doesn't log when disposed", () => { - const disposable = logStreamErrors(proc, 'test', [], {}); + const disposable = (0, (_process || _load_process()).logStreamErrors)(proc, 'test', [], {}); spyOn(logger, 'error'); disposable.dispose(); proc.stderr.emit('error', new Error('Test error')); @@ -781,14 +717,14 @@ describe('commons-node/process', () => { describe('ProcessSystemError', () => { it('contains the correct properties', () => { - const proc = (({}: any): child_process$ChildProcess); + const proc = {}; const originalError = { errno: 2, code: 'ETEST', path: 'path value', - syscall: 'syscall value', + syscall: 'syscall value' }; - const err = new ProcessSystemError(originalError, proc); + const err = new (_process || _load_process()).ProcessSystemError(originalError, proc); expect(err.errno).toBe(2); expect(err.code).toBe('ETEST'); expect(err.path).toBe('path value'); @@ -800,26 +736,29 @@ describe('commons-node/process', () => { describe('scriptifyCommand', () => { if (process.platform === 'linux') { it('escapes correctly on linux', () => { - waitsForPromise(async () => { - const output = await runCommand( - ...scriptifyCommand('echo', [ - 'a\\b c\\\\d e\\\\\\f g\\\\\\\\h "dubs" \'singles\'', - 'one two', - ]), - ).toPromise(); - expect(output.trim()).toBe( - 'a\\b c\\\\d e\\\\\\f g\\\\\\\\h "dubs" \'singles\' one two', - ); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const output = yield (0, (_process || _load_process()).runCommand)(...(0, (_process || _load_process()).scriptifyCommand)('echo', ['a\\b c\\\\d e\\\\\\f g\\\\\\\\h "dubs" \'singles\'', 'one two'])).toPromise(); + expect(output.trim()).toBe('a\\b c\\\\d e\\\\\\f g\\\\\\\\h "dubs" \'singles\' one two'); + })); }); } }); -}); - -function makeExitMessage(exitCode: number): ProcessExitMessage { +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function makeExitMessage(exitCode) { return { kind: 'exit', exitCode, - signal: null, + signal: null }; -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/spec/promise-spec.js b/modules/nuclide-commons/spec/promise-spec.js index 04348598..39a4abed 100644 --- a/modules/nuclide-commons/spec/promise-spec.js +++ b/modules/nuclide-commons/spec/promise-spec.js @@ -1,3 +1,52 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +let captureParallelismHistory = (() => { + var _ref34 = (0, _asyncToGenerator.default)(function* (asyncFunction, args) { + const parallelismHistory = []; + let parralelism = 0; + const result = yield asyncFunction(...args.map(function (arg) { + if (typeof arg !== 'function') { + return arg; + } + const func = arg; + return (() => { + var _ref35 = (0, _asyncToGenerator.default)(function* (item) { + ++parralelism; + parallelismHistory.push(parralelism); + const value = yield func(item); + --parralelism; + return value; + }); + + return function (_x4) { + return _ref35.apply(this, arguments); + }; + })(); + })); + return { result, parallelismHistory }; + }); + + return function captureParallelismHistory(_x2, _x3) { + return _ref34.apply(this, arguments); + }; +})(); + +var _promise; + +function _load_promise() { + return _promise = require('../promise'); +} + +var _testHelpers; + +function _load_testHelpers() { + return _testHelpers = require('../test-helpers'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,29 +55,12 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ /* eslint-disable prefer-promise-reject-errors */ -import { - asyncFind, - denodeify, - serializeAsyncCall, - asyncLimit, - asyncFilter, - asyncObjFilter, - asyncSome, - lastly, - retryLimit, - RequestSerializer, - TimedOutError, - timeoutPromise, -} from '../promise'; -import invariant from 'assert'; -import {expectAsyncFailure} from '../test-helpers'; - describe('promises::asyncFind()', () => { it('Empty list of items should resolve to null.', () => { let isResolved = false; @@ -42,15 +74,13 @@ describe('promises::asyncFind()', () => { }; runs(() => { - asyncFind(args, test) - .then(result => { - observedResult = result; - isResolved = true; - }) - .catch(error => { - observedError = error; - isRejected = true; - }); + (0, (_promise || _load_promise()).asyncFind)(args, test).then(result => { + observedResult = result; + isResolved = true; + }).catch(error => { + observedError = error; + isRejected = true; + }); }); waitsFor(() => isResolved || isRejected); @@ -81,15 +111,13 @@ describe('promises::asyncFind()', () => { }; runs(() => { - asyncFind(args, test) - .then(result => { - observedResult = result; - isResolved = true; - }) - .catch(error => { - observedError = error; - isRejected = true; - }); + (0, (_promise || _load_promise()).asyncFind)(args, test).then(result => { + observedResult = result; + isResolved = true; + }).catch(error => { + observedError = error; + isRejected = true; + }); }); waitsFor(() => isResolved || isRejected); @@ -116,7 +144,7 @@ describe('promises::denodeify()', () => { * rather than at the end. The type signature of this function cannot be * expressed in Flow. */ - function asyncProduct(...factors): void { + function asyncProduct(...factors) { const callback = factors.pop(); const product = factors.reduce((previousValue, currentValue) => { return previousValue * currentValue; @@ -130,26 +158,23 @@ describe('promises::denodeify()', () => { } it('resolves Promise when callback succeeds', () => { - const denodeifiedAsyncProduct = denodeify(asyncProduct); - waitsForPromise(async () => { - const trivialProduct = await denodeifiedAsyncProduct(); + const denodeifiedAsyncProduct = (0, (_promise || _load_promise()).denodeify)(asyncProduct); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const trivialProduct = yield denodeifiedAsyncProduct(); expect(trivialProduct).toBe(1); - const product = await denodeifiedAsyncProduct(1, 2, 3, 4, 5); + const product = yield denodeifiedAsyncProduct(1, 2, 3, 4, 5); expect(product).toBe(120); - }); + })); }); it('rejects Promise when callback fails', () => { - const denodeifiedAsyncProduct = denodeify(asyncProduct); - waitsForPromise(async () => { - await expectAsyncFailure( - denodeifiedAsyncProduct('a', 'b'), - (error: Error) => { - expect(error.message).toBe('product was NaN'); - }, - ); - }); + const denodeifiedAsyncProduct = (0, (_promise || _load_promise()).denodeify)(asyncProduct); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(denodeifiedAsyncProduct('a', 'b'), function (error) { + expect(error.message).toBe('product was NaN'); + }); + })); }); function checksReceiver(expectedReceiver, callback) { @@ -161,23 +186,20 @@ describe('promises::denodeify()', () => { } it('result of denodeify propagates receiver as expected', () => { - const denodeifiedChecksReceiver = denodeify(checksReceiver); + const denodeifiedChecksReceiver = (0, (_promise || _load_promise()).denodeify)(checksReceiver); - waitsForPromise(async () => { - const receiver = {denodeifiedChecksReceiver}; - const result = await receiver.denodeifiedChecksReceiver(receiver); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const receiver = { denodeifiedChecksReceiver }; + const result = yield receiver.denodeifiedChecksReceiver(receiver); expect(result).toBe('winner'); - }); + })); - waitsForPromise(async () => { - const receiver = {denodeifiedChecksReceiver}; - await expectAsyncFailure( - receiver.denodeifiedChecksReceiver(null), - (error: Error) => { - expect(error.message).toBe('unexpected receiver'); - }, - ); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const receiver = { denodeifiedChecksReceiver }; + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(receiver.denodeifiedChecksReceiver(null), function (error) { + expect(error.message).toBe('unexpected receiver'); + }); + })); }); }); @@ -185,7 +207,7 @@ describe('promises::serializeAsyncCall()', () => { it('Returns the same result when called after scheduled', () => { let i = 0; const asyncFunSpy = jasmine.createSpy('async'); - const oneAsyncCallAtATime = serializeAsyncCall(() => { + const oneAsyncCallAtATime = (0, (_promise || _load_promise()).serializeAsyncCall)(() => { i++; const resultPromise = waitPromise(10, i); asyncFunSpy(); @@ -202,21 +224,17 @@ describe('promises::serializeAsyncCall()', () => { // Wait for the promise to call the next chain // That isn't synchrnously guranteed because it happens on `process.nextTick`. waitsFor(() => asyncFunSpy.callCount === 2); - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { advanceClock(11); - const results = await Promise.all([ - result1Promise, - result2Promise, - result3Promise, - ]); + const results = yield Promise.all([result1Promise, result2Promise, result3Promise]); expect(results).toEqual([1, 2, 2]); - }); + })); }); it('Calls and returns (even if errors) the same number of times if serially called', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let i = 0; - const oneAsyncCallAtATime = serializeAsyncCall(() => { + const oneAsyncCallAtATime = (0, (_promise || _load_promise()).serializeAsyncCall)(function () { i++; if (i === 4) { return Promise.reject('ERROR'); @@ -225,27 +243,27 @@ describe('promises::serializeAsyncCall()', () => { }); const result1Promise = oneAsyncCallAtATime(); advanceClock(11); - const result1 = await result1Promise; + const result1 = yield result1Promise; const result2Promise = oneAsyncCallAtATime(); advanceClock(11); - const result2 = await result2Promise; + const result2 = yield result2Promise; const result3Promise = oneAsyncCallAtATime(); advanceClock(11); - const result3 = await result3Promise; + const result3 = yield result3Promise; const errorPromoise = oneAsyncCallAtATime(); advanceClock(11); - await expectAsyncFailure(errorPromoise, error => { + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(errorPromoise, function (error) { expect(error).toBe('ERROR'); }); const result5Promise = oneAsyncCallAtATime(); advanceClock(11); - const result5 = await result5Promise; + const result5 = yield result5Promise; expect([result1, result2, result3, result5]).toEqual([1, 2, 3, 5]); - }); + })); }); }); @@ -255,58 +273,57 @@ describe('promises::asyncLimit()', () => { }); it('runs in series if limit is 1', () => { - waitsForPromise(async () => { - const {result, parallelismHistory} = await captureParallelismHistory( - asyncLimit, - [[1, 2, 3], 1, item => waitPromise(10, item + 1)], - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const { result, parallelismHistory } = yield captureParallelismHistory((_promise || _load_promise()).asyncLimit, [[1, 2, 3], 1, function (item) { + return waitPromise(10, item + 1); + }]); expect(parallelismHistory).toEqual([1, 1, 1]); expect(result).toEqual([2, 3, 4]); - }); + })); }); it('runs with the specified limit, until finishing', () => { - waitsForPromise(async () => { - const {result, parallelismHistory} = await captureParallelismHistory( - asyncLimit, - [ - [1, 2, 3, 4, 5, 6, 7, 8, 9], - 3, - item => waitPromise(10 + item, item - 1), - ], - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const { result, parallelismHistory } = yield captureParallelismHistory((_promise || _load_promise()).asyncLimit, [[1, 2, 3, 4, 5, 6, 7, 8, 9], 3, function (item) { + return waitPromise(10 + item, item - 1); + }]); expect(result).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8]); expect(parallelismHistory).toEqual([1, 2, 3, 3, 3, 3, 3, 3, 3]); - }); + })); }); it('works when the limit is bigger than the array length', () => { - waitsForPromise(async () => { - const result = await asyncLimit([1, 2, 3], 10, item => - waitPromise(10, item * 2), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const result = yield (0, (_promise || _load_promise()).asyncLimit)([1, 2, 3], 10, function (item) { + return waitPromise(10, item * 2); + }); expect(result).toEqual([2, 4, 6]); - }); + })); }); it('a rejected promise rejects the whole call with the error', () => { - waitsForPromise(async () => { - await expectAsyncFailure( - asyncLimit([1], 1, async item => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)((0, (_promise || _load_promise()).asyncLimit)([1], 1, (() => { + var _ref11 = (0, _asyncToGenerator.default)(function* (item) { throw new Error('rejected iterator promise'); - }), - (error: Error) => { - expect(error.message).toBe('rejected iterator promise'); - }, - ); - }); + }); + + return function (_x) { + return _ref11.apply(this, arguments); + }; + })()), function (error) { + expect(error.message).toBe('rejected iterator promise'); + }); + })); }); it('works when the array is empty', () => { - waitsForPromise(async () => { - const result = await asyncLimit([], 1, () => Promise.resolve()); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const result = yield (0, (_promise || _load_promise()).asyncLimit)([], 1, function () { + return Promise.resolve(); + }); expect(result).toEqual([]); - }); + })); }); }); @@ -317,33 +334,30 @@ describe('promises::asyncFilter()', () => { // eslint-disable-next-line max-len it('filters an array with an async iterator and maximum parallelization when no limit is specified', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const { result: filtered, - parallelismHistory, - } = await captureParallelismHistory(asyncFilter, [ - [1, 2, 3, 4, 5], - item => waitPromise(10 + item, item > 2), - ]); + parallelismHistory + } = yield captureParallelismHistory((_promise || _load_promise()).asyncFilter, [[1, 2, 3, 4, 5], function (item) { + return waitPromise(10 + item, item > 2); + }]); expect(filtered).toEqual([3, 4, 5]); expect(parallelismHistory).toEqual([1, 2, 3, 4, 5]); - }); + })); }); it('filters an array with a limit on parallelization', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const { result: filtered, - parallelismHistory, - } = await captureParallelismHistory(asyncFilter, [ - [1, 2, 3, 4, 5], - item => waitPromise(10 + item, item > 2), - 3, - ]); + parallelismHistory + } = yield captureParallelismHistory((_promise || _load_promise()).asyncFilter, [[1, 2, 3, 4, 5], function (item) { + return waitPromise(10 + item, item > 2); + }, 3]); expect(filtered).toEqual([3, 4, 5]); // Increasing promise resolve time will gurantee maximum parallelization. expect(parallelismHistory).toEqual([1, 2, 3, 3, 3]); - }); + })); }); }); @@ -354,33 +368,30 @@ describe('promises::asyncObjFilter()', () => { // eslint-disable-next-line max-len it('filters an object with an async iterator and maximum parallelization when no limit is specified', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const { result: filtered, - parallelismHistory, - } = await captureParallelismHistory(asyncObjFilter, [ - {a: 1, b: 2, c: 3, d: 4, e: 5}, - (value, key) => waitPromise(5 + value, value > 2), - ]); - expect(filtered).toEqual({c: 3, d: 4, e: 5}); + parallelismHistory + } = yield captureParallelismHistory((_promise || _load_promise()).asyncObjFilter, [{ a: 1, b: 2, c: 3, d: 4, e: 5 }, function (value, key) { + return waitPromise(5 + value, value > 2); + }]); + expect(filtered).toEqual({ c: 3, d: 4, e: 5 }); expect(parallelismHistory).toEqual([1, 2, 3, 4, 5]); - }); + })); }); it('filters an array with a limit on parallelization', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const { result: filtered, - parallelismHistory, - } = await captureParallelismHistory(asyncObjFilter, [ - {a: 1, b: 2, c: 3, d: 4, e: 5}, - (value, key) => waitPromise(5 + value, value > 2), - 3, - ]); - expect(filtered).toEqual({c: 3, d: 4, e: 5}); + parallelismHistory + } = yield captureParallelismHistory((_promise || _load_promise()).asyncObjFilter, [{ a: 1, b: 2, c: 3, d: 4, e: 5 }, function (value, key) { + return waitPromise(5 + value, value > 2); + }, 3]); + expect(filtered).toEqual({ c: 3, d: 4, e: 5 }); // Increasing promise resolve time will gurantee maximum parallelization. expect(parallelismHistory).toEqual([1, 2, 3, 3, 3]); - }); + })); }); }); @@ -391,57 +402,55 @@ describe('promises::asyncSome()', () => { // eslint-disable-next-line max-len it('some an array with an async iterator and maximum parallelization when no limit is specified', () => { - waitsForPromise(async () => { - const {result, parallelismHistory} = await captureParallelismHistory( - asyncSome, - [[1, 2, 3, 4, 5], item => waitPromise(10, item === 6)], - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const { result, parallelismHistory } = yield captureParallelismHistory((_promise || _load_promise()).asyncSome, [[1, 2, 3, 4, 5], function (item) { + return waitPromise(10, item === 6); + }]); expect(result).toEqual(false); expect(parallelismHistory).toEqual([1, 2, 3, 4, 5]); - }); + })); }); it('some an array with a limit on parallelization', () => { - waitsForPromise(async () => { - const {result, parallelismHistory} = await captureParallelismHistory( - asyncSome, - [[1, 2, 3, 4, 5], item => waitPromise(10 + item, item === 5), 3], - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const { result, parallelismHistory } = yield captureParallelismHistory((_promise || _load_promise()).asyncSome, [[1, 2, 3, 4, 5], function (item) { + return waitPromise(10 + item, item === 5); + }, 3]); expect(result).toEqual(true); expect(parallelismHistory).toEqual([1, 2, 3, 3, 3]); - }); + })); }); }); describe('promises::lastly', () => { it('executes after a resolved promise', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const spy = jasmine.createSpy('spy'); - const result = await lastly(Promise.resolve(1), spy); + const result = yield (0, (_promise || _load_promise()).lastly)(Promise.resolve(1), spy); expect(result).toBe(1); expect(spy).toHaveBeenCalled(); - }); + })); }); it('executes after a rejected promise', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const spy = jasmine.createSpy('spy'); - await expectAsyncFailure(lastly(Promise.reject(2), spy), err => { + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)((0, (_promise || _load_promise()).lastly)(Promise.reject(2), spy), function (err) { expect(err).toBe(2); }); expect(spy).toHaveBeenCalled(); - }); + })); }); it('works for async functions', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const spy = jasmine.createSpy('spy'); - const result = await lastly(Promise.resolve(1), async () => { + const result = yield (0, (_promise || _load_promise()).lastly)(Promise.resolve(1), (0, _asyncToGenerator.default)(function* () { spy(); - }); + })); expect(result).toBe(1); expect(spy).toHaveBeenCalled(); - }); + })); }); }); @@ -451,205 +460,175 @@ describe('promises::retryLimit()', () => { }); it('retries and fails 2 times before resolving to an acceptable result where limit = 5', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let succeedAfter = 2; let calls = 0; let validationCalls = 0; - const retrialsResult = await retryLimit( - () => { - return new Promise((resolve, reject) => { - calls++; - if (succeedAfter-- === 0) { - resolve('RESULT'); - } else { - reject('ERROR'); - } - }); - }, - result => { - validationCalls++; - return result === 'RESULT'; - }, - 5, - ); + const retrialsResult = yield (0, (_promise || _load_promise()).retryLimit)(function () { + return new Promise(function (resolve, reject) { + calls++; + if (succeedAfter-- === 0) { + resolve('RESULT'); + } else { + reject('ERROR'); + } + }); + }, function (result) { + validationCalls++; + return result === 'RESULT'; + }, 5); expect(calls).toBe(3); expect(validationCalls).toBe(1); expect(retrialsResult).toBe('RESULT'); - }); + })); }); it('retries and fails consistently', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let calls = 0; let validationCalls = 0; - const failRetriesPromise = retryLimit( - () => { - calls++; - return Promise.reject('ERROR'); - }, - result => { - validationCalls++; - return result != null; - }, - 2, - ); - await expectAsyncFailure(failRetriesPromise, error => { + const failRetriesPromise = (0, (_promise || _load_promise()).retryLimit)(function () { + calls++; + return Promise.reject('ERROR'); + }, function (result) { + validationCalls++; + return result != null; + }, 2); + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(failRetriesPromise, function (error) { expect(error).toBe('ERROR'); }); expect(calls).toBe(2); expect(validationCalls).toBe(0); - }); + })); }); it('accepts a null response', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { let succeedAfter = 2; let calls = 0; let validationCalls = 0; - const retryResult = await retryLimit( - () => { - calls++; - if (succeedAfter-- === 0) { - return Promise.resolve(null); - } else { - return Promise.resolve('NOT_GOOD'); - } - }, - result => { - validationCalls++; - return result == null; - }, - 5, - ); + const retryResult = yield (0, (_promise || _load_promise()).retryLimit)(function () { + calls++; + if (succeedAfter-- === 0) { + return Promise.resolve(null); + } else { + return Promise.resolve('NOT_GOOD'); + } + }, function (result) { + validationCalls++; + return result == null; + }, 5); expect(retryResult).toBe(null); expect(calls).toBe(3); expect(validationCalls).toBe(3); - }); + })); }); it('no valid response is ever got', () => { - waitsForPromise(async () => { - const nonValidRetriesPromise = retryLimit( - () => { - return Promise.resolve('A'); - }, - result => { - return result === 'B'; - }, - 2, - ); - await expectAsyncFailure(nonValidRetriesPromise, error => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const nonValidRetriesPromise = (0, (_promise || _load_promise()).retryLimit)(function () { + return Promise.resolve('A'); + }, function (result) { + return result === 'B'; + }, 2); + yield (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(nonValidRetriesPromise, function (error) { expect(error.message).toBe('No valid response found!'); }); - }); + })); }); }); describe('promises::RequestSerializer()', () => { - let requestSerializer: RequestSerializer = (null: any); + let requestSerializer = null; beforeEach(() => { jasmine.useRealClock(); - requestSerializer = new RequestSerializer(); + requestSerializer = new (_promise || _load_promise()).RequestSerializer(); }); it('gets outdated result for old promises resolving after newer calls', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const oldPromise = requestSerializer.run(waitPromise(10, 'OLD')); const newPromise = requestSerializer.run(waitPromise(5, 'NEW')); - const {status: oldStatus} = await oldPromise; + const { status: oldStatus } = yield oldPromise; expect(oldStatus).toBe('outdated'); - const newResult = await newPromise; - invariant(newResult.status === 'success'); + const newResult = yield newPromise; + + if (!(newResult.status === 'success')) { + throw new Error('Invariant violation: "newResult.status === \'success\'"'); + } + expect(newResult.result).toBe('NEW'); - }); + })); }); it('waitForLatestResult: waits for the latest result', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { requestSerializer.run(waitPromise(5, 'OLD')); requestSerializer.run(waitPromise(10, 'NEW')); - const latestResult = await requestSerializer.waitForLatestResult(); + const latestResult = yield requestSerializer.waitForLatestResult(); expect(latestResult).toBe('NEW'); - }); + })); }); it('waitForLatestResult: waits even if the first run did not kick off', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const latestResultPromise = requestSerializer.waitForLatestResult(); requestSerializer.run(waitPromise(10, 'RESULT')); - const latestResult = await latestResultPromise; + const latestResult = yield latestResultPromise; expect(latestResult).toBe('RESULT'); - }); + })); }); it('waitForLatestResult: does not wait for the first, if the second resolves faster', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { requestSerializer.run(waitPromise(1000000, 'OLD')); // This will never resolve. requestSerializer.run(waitPromise(10, 'NEW')); - const latestResult = await requestSerializer.waitForLatestResult(); + const latestResult = yield requestSerializer.waitForLatestResult(); expect(latestResult).toBe('NEW'); - }); + })); }); }); describe('timeoutPromise', () => { it('should resolve normally if within the timeout', () => { - waitsForPromise(async () => { - const inputPromise = new Promise(resolve => resolve('foo')); - const outputPromise = timeoutPromise(inputPromise, 1000); - expect(await outputPromise).toBe('foo'); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const inputPromise = new Promise(function (resolve) { + return resolve('foo'); + }); + const outputPromise = (0, (_promise || _load_promise()).timeoutPromise)(inputPromise, 1000); + expect((yield outputPromise)).toBe('foo'); + })); }); it('should reject if the given promise rejects', () => { - waitsForPromise(async () => { - const inputPromise = new Promise((resolve, reject) => reject('foo')); - const outputPromise = timeoutPromise(inputPromise, 1000).catch( - value => `rejected with ${value}`, - ); - expect(await outputPromise).toBe('rejected with foo'); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const inputPromise = new Promise(function (resolve, reject) { + return reject('foo'); + }); + const outputPromise = (0, (_promise || _load_promise()).timeoutPromise)(inputPromise, 1000).catch(function (value) { + return `rejected with ${value}`; + }); + expect((yield outputPromise)).toBe('rejected with foo'); + })); }); it('should reject if the given promise takes too long', () => { - waitsForPromise(async () => { - const inputPromise = new Promise(resolve => setTimeout(resolve, 2000)); - const outputPromise = timeoutPromise(inputPromise, 1000).catch( - value => value, - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const inputPromise = new Promise(function (resolve) { + return setTimeout(resolve, 2000); + }); + const outputPromise = (0, (_promise || _load_promise()).timeoutPromise)(inputPromise, 1000).catch(function (value) { + return value; + }); advanceClock(1500); - expect(await outputPromise).toEqual(new TimedOutError(1000)); - }); + expect((yield outputPromise)).toEqual(new (_promise || _load_promise()).TimedOutError(1000)); + })); }); }); -async function captureParallelismHistory( - asyncFunction: (...args: Array) => Promise, - args: Array, -): Promise<{result: mixed, parallelismHistory: Array}> { - const parallelismHistory = []; - let parralelism = 0; - const result = await asyncFunction( - ...args.map(arg => { - if (typeof arg !== 'function') { - return arg; - } - const func = arg; - return async item => { - ++parralelism; - parallelismHistory.push(parralelism); - const value = await func(item); - --parralelism; - return value; - }; - }), - ); - return {result, parallelismHistory}; -} - -function waitPromise(timeoutMs: number, value: any): Promise { +function waitPromise(timeoutMs, value) { return new Promise((resolve, reject) => { setTimeout(() => resolve(value), timeoutMs); }); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/spec/range-spec.js b/modules/nuclide-commons/spec/range-spec.js index e2cef1f7..f89fd321 100644 --- a/modules/nuclide-commons/spec/range-spec.js +++ b/modules/nuclide-commons/spec/range-spec.js @@ -1,33 +1,53 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import invariant from 'assert'; -import {default as TextBuffer, Range} from 'simple-text-buffer'; -import {wordAtPositionFromBuffer} from '../range'; +'use strict'; + +var _simpleTextBuffer; + +function _load_simpleTextBuffer() { + return _simpleTextBuffer = _interopRequireDefault(require('simple-text-buffer')); +} + +var _simpleTextBuffer2; + +function _load_simpleTextBuffer2() { + return _simpleTextBuffer2 = require('simple-text-buffer'); +} + +var _range; + +function _load_range() { + return _range = require('../range'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('wordAtPositionFromBuffer', () => { it('matches a word in a buffer', () => { - const buffer = new TextBuffer('word1 word2 word3\n'); - const match = wordAtPositionFromBuffer(buffer, {row: 0, column: 6}, /\S+/g); + const buffer = new (_simpleTextBuffer || _load_simpleTextBuffer()).default('word1 word2 word3\n'); + const match = (0, (_range || _load_range()).wordAtPositionFromBuffer)(buffer, { row: 0, column: 6 }, /\S+/g); expect(match).not.toBeNull(); - invariant(match != null); + + if (!(match != null)) { + throw new Error('Invariant violation: "match != null"'); + } + expect(match.wordMatch.length).toBe(1); expect(match.wordMatch[0]).toBe('word2'); - expect(match.range).toEqual(new Range([0, 6], [0, 11])); + expect(match.range).toEqual(new (_simpleTextBuffer2 || _load_simpleTextBuffer2()).Range([0, 6], [0, 11])); }); it('should not include endpoints', () => { - const buffer = new TextBuffer('word1 word2 word3\n'); - const match = wordAtPositionFromBuffer(buffer, {row: 0, column: 5}, /\S+/g); + const buffer = new (_simpleTextBuffer || _load_simpleTextBuffer()).default('word1 word2 word3\n'); + const match = (0, (_range || _load_range()).wordAtPositionFromBuffer)(buffer, { row: 0, column: 5 }, /\S+/g); expect(match).toBeNull(); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/shell-quote-spec.js b/modules/nuclide-commons/spec/shell-quote-spec.js index f542088c..5bf8b5ed 100644 --- a/modules/nuclide-commons/spec/shell-quote-spec.js +++ b/modules/nuclide-commons/spec/shell-quote-spec.js @@ -1,16 +1,10 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; + +var _shellQuote; -import {parse, quote} from '../_shell-quote'; +function _load_shellQuote() { + return _shellQuote = require('../_shell-quote'); +} /** * The rest of shell-quote has been verified to work correctly. @@ -20,23 +14,28 @@ import {parse, quote} from '../_shell-quote'; describe('shell-quote', () => { describe('parse', () => { it('parses comments correctly', () => { - expect(parse('beep#boop')).toEqual(['beep#boop']); - expect(parse('beep #boop')).toEqual(['beep', {comment: 'boop'}]); - expect(parse('beep # boop')).toEqual(['beep', {comment: 'boop'}]); - expect(parse('beep # > boop')).toEqual(['beep', {comment: '> boop'}]); - expect(parse('beep # "> boop"')).toEqual(['beep', {comment: '"> boop"'}]); - expect(parse('beep "#"')).toEqual(['beep', '#']); - expect(parse('beep #"#"#')).toEqual(['beep', {comment: '"#"#'}]); - expect(parse('beep > boop # > foo')).toEqual([ - 'beep', - {op: '>'}, - 'boop', - {comment: '> foo'}, - ]); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep#boop')).toEqual(['beep#boop']); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep #boop')).toEqual(['beep', { comment: 'boop' }]); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep # boop')).toEqual(['beep', { comment: 'boop' }]); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep # > boop')).toEqual(['beep', { comment: '> boop' }]); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep # "> boop"')).toEqual(['beep', { comment: '"> boop"' }]); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep "#"')).toEqual(['beep', '#']); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep #"#"#')).toEqual(['beep', { comment: '"#"#' }]); + expect((0, (_shellQuote || _load_shellQuote()).parse)('beep > boop # > foo')).toEqual(['beep', { op: '>' }, 'boop', { comment: '> foo' }]); }); }); describe('quote', () => { - expect(quote(['X#(){}*|][!'])).toBe('X\\#\\(\\)\\{\\}\\*\\|\\]\\[\\!'); + expect((0, (_shellQuote || _load_shellQuote()).quote)(['X#(){}*|][!'])).toBe('X\\#\\(\\)\\{\\}\\*\\|\\]\\[\\!'); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-commons/spec/stream-spec.js b/modules/nuclide-commons/spec/stream-spec.js index f6eb3a5f..c5447627 100644 --- a/modules/nuclide-commons/spec/stream-spec.js +++ b/modules/nuclide-commons/spec/stream-spec.js @@ -1,3 +1,25 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _stream; + +function _load_stream() { + return _stream = require('../stream'); +} + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('../fsPromise')); +} + +var _stream2 = _interopRequireDefault(require('stream')); + +var _fs = _interopRequireDefault(require('fs')); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,72 +28,63 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import {observeStream, observeRawStream, writeToStream} from '../stream'; -import fsPromise from '../fsPromise'; -import Stream from 'stream'; -import fs from 'fs'; - describe('commons-node/stream', () => { it('observeStream', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { const input = ['foo\nbar', '\n', '\nba', 'z', '\nblar']; - const stream = new Stream.PassThrough(); - const promise = observeStream(stream) - .toArray() - .toPromise(); - input.forEach(value => { + const stream = new _stream2.default.PassThrough(); + const promise = (0, (_stream || _load_stream()).observeStream)(stream).toArray().toPromise(); + input.forEach(function (value) { stream.write(value, 'utf8'); }); stream.end(); - const output = await promise; + const output = yield promise; expect(output.join('')).toEqual(input.join('')); - }); + })); }); it('observeStream - error', () => { - waitsForPromise(async () => { - const stream = new Stream.PassThrough(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const stream = new _stream2.default.PassThrough(); const input = ['foo\nbar', '\n', '\nba', 'z', '\nblar']; const output = []; - const promise = new Promise((resolve, reject) => { - observeStream(stream).subscribe( - v => output.push(v), - e => resolve(e), - () => {}, - ); + const promise = new Promise(function (resolve, reject) { + (0, (_stream || _load_stream()).observeStream)(stream).subscribe(function (v) { + return output.push(v); + }, function (e) { + return resolve(e); + }, function () {}); }); const error = new Error('Had an error'); - input.forEach(value => { + input.forEach(function (value) { stream.write(value, 'utf8'); }); stream.emit('error', error); - const result = await promise; + const result = yield promise; expect(output).toEqual(input); expect(result).toBe(error); - }); + })); }); it('writeToStream', () => { - waitsForPromise(async () => { - const tempPath = await fsPromise.tempfile(); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const tempPath = yield (_fsPromise || _load_fsPromise()).default.tempfile(); const fixturePath = 'spec/fixtures/lyrics'; - const stream = fs.createWriteStream(tempPath, {highWaterMark: 10}); + const stream = _fs.default.createWriteStream(tempPath, { highWaterMark: 10 }); // Read faster than we write to test buffering - const observable = observeRawStream( - fs.createReadStream(fixturePath, {highWaterMark: 100}), - ); + const observable = (0, (_stream || _load_stream()).observeRawStream)(_fs.default.createReadStream(fixturePath, { highWaterMark: 100 })); - await writeToStream(observable, stream).toPromise(); + yield (0, (_stream || _load_stream()).writeToStream)(observable, stream).toPromise(); - const writtenFile = await fsPromise.readFile(tempPath); - const fixtureFile = await fsPromise.readFile(fixturePath); + const writtenFile = yield (_fsPromise || _load_fsPromise()).default.readFile(tempPath); + const fixtureFile = yield (_fsPromise || _load_fsPromise()).default.readFile(fixturePath); expect(writtenFile).toEqual(fixtureFile); - }); + })); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/string-spec.js b/modules/nuclide-commons/spec/string-spec.js index 10ccdedc..8637a55c 100644 --- a/modules/nuclide-commons/spec/string-spec.js +++ b/modules/nuclide-commons/spec/string-spec.js @@ -1,29 +1,10 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import { - capitalize, - countOccurrences, - getMatchRanges, - indent, - maybeToString, - pluralize, - relativeDate, - removeCommonPrefix, - removeCommonSuffix, - shellParse, - shorten, - splitOnce, -} from '../string'; +var _string; + +function _load_string() { + return _string = require('../string'); +} describe('relativeDate', () => { it('works', () => { @@ -39,267 +20,207 @@ describe('relativeDate', () => { const now = new Date().getTime(); // test long format - expect(relativeDate(0)).toEqual(Math.round(now / YEAR) + ' years ago'); - expect(relativeDate(reference * SECOND, reference)).toEqual('just now'); - expect(relativeDate(reference - 41 * SECOND, reference)).toEqual( - 'just now', - ); - expect(relativeDate(reference - 42 * SECOND, reference)).toEqual( - 'a minute ago', - ); - expect(relativeDate(reference - MINUTE, reference)).toEqual('a minute ago'); - expect(relativeDate(reference - MINUTE * 1.5, reference)).toEqual( - '2 minutes ago', - ); - expect(relativeDate(reference - MINUTE * 59, reference)).toEqual( - '59 minutes ago', - ); - expect(relativeDate(reference - HOUR, reference)).toEqual('an hour ago'); - expect(relativeDate(reference - HOUR * 1.5, reference)).toEqual( - '2 hours ago', - ); - expect(relativeDate(reference - HOUR * 16, reference)).toEqual( - '16 hours ago', - ); - expect(relativeDate(reference - HOUR * 23, reference)).toEqual( - '23 hours ago', - ); - expect(relativeDate(reference - DAY * 1.8, reference)).toEqual('yesterday'); - expect(relativeDate(reference - DAY * 3, reference)).toEqual('3 days ago'); - expect(relativeDate(reference - DAY * 6, reference)).toEqual('6 days ago'); - expect(relativeDate(reference - WEEK, reference)).toEqual('a week ago'); - expect(relativeDate(reference - WEEK * 2, reference)).toEqual( - '2 weeks ago', - ); - expect(relativeDate(reference - WEEK * 4, reference)).toEqual( - '4 weeks ago', - ); - expect(relativeDate(reference - MONTH * 1.2, reference)).toEqual( - 'a month ago', - ); - expect(relativeDate(reference - YEAR + HOUR, reference)).toEqual( - '12 months ago', - ); - expect(relativeDate(reference - YEAR, reference)).toEqual('a year ago'); - expect(relativeDate(reference - YEAR * 2, reference)).toEqual( - '2 years ago', - ); - expect(relativeDate(0, reference)).toEqual('5 years ago'); + expect((0, (_string || _load_string()).relativeDate)(0)).toEqual(Math.round(now / YEAR) + ' years ago'); + expect((0, (_string || _load_string()).relativeDate)(reference * SECOND, reference)).toEqual('just now'); + expect((0, (_string || _load_string()).relativeDate)(reference - 41 * SECOND, reference)).toEqual('just now'); + expect((0, (_string || _load_string()).relativeDate)(reference - 42 * SECOND, reference)).toEqual('a minute ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - MINUTE, reference)).toEqual('a minute ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - MINUTE * 1.5, reference)).toEqual('2 minutes ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - MINUTE * 59, reference)).toEqual('59 minutes ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR, reference)).toEqual('an hour ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR * 1.5, reference)).toEqual('2 hours ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR * 16, reference)).toEqual('16 hours ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR * 23, reference)).toEqual('23 hours ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - DAY * 1.8, reference)).toEqual('yesterday'); + expect((0, (_string || _load_string()).relativeDate)(reference - DAY * 3, reference)).toEqual('3 days ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - DAY * 6, reference)).toEqual('6 days ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - WEEK, reference)).toEqual('a week ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - WEEK * 2, reference)).toEqual('2 weeks ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - WEEK * 4, reference)).toEqual('4 weeks ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - MONTH * 1.2, reference)).toEqual('a month ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - YEAR + HOUR, reference)).toEqual('12 months ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - YEAR, reference)).toEqual('a year ago'); + expect((0, (_string || _load_string()).relativeDate)(reference - YEAR * 2, reference)).toEqual('2 years ago'); + expect((0, (_string || _load_string()).relativeDate)(0, reference)).toEqual('5 years ago'); // test short format - expect(relativeDate(0, undefined, /* short */ true)).toEqual( - Math.round(now / YEAR) + 'y', - ); - expect( - relativeDate(reference * SECOND, reference, /* short */ true), - ).toEqual('now'); - expect( - relativeDate(reference - 41 * SECOND, reference, /* short */ true), - ).toEqual('now'); - expect( - relativeDate(reference - 42 * SECOND, reference, /* short */ true), - ).toEqual('1m'); - expect( - relativeDate(reference - MINUTE, reference, /* short */ true), - ).toEqual('1m'); - expect( - relativeDate(reference - MINUTE * 1.5, reference, /* short */ true), - ).toEqual('2m'); - expect( - relativeDate(reference - MINUTE * 59, reference, /* short */ true), - ).toEqual('59m'); - expect(relativeDate(reference - HOUR, reference, /* short */ true)).toEqual( - '1h', - ); - expect( - relativeDate(reference - HOUR * 1.5, reference, /* short */ true), - ).toEqual('2h'); - expect( - relativeDate(reference - HOUR * 16, reference, /* short */ true), - ).toEqual('16h'); - expect( - relativeDate(reference - HOUR * 23, reference, /* short */ true), - ).toEqual('23h'); - expect( - relativeDate(reference - DAY * 1.8, reference, /* short */ true), - ).toEqual('1d'); - expect( - relativeDate(reference - DAY * 3, reference, /* short */ true), - ).toEqual('3d'); - expect( - relativeDate(reference - DAY * 6, reference, /* short */ true), - ).toEqual('6d'); - expect(relativeDate(reference - WEEK, reference, /* short */ true)).toEqual( - '1w', - ); - expect( - relativeDate(reference - WEEK * 2, reference, /* short */ true), - ).toEqual('2w'); - expect( - relativeDate(reference - WEEK * 4, reference, /* short */ true), - ).toEqual('4w'); - expect( - relativeDate(reference - MONTH * 1.2, reference, /* short */ true), - ).toEqual('1mo'); - expect( - relativeDate(reference - YEAR + HOUR, reference, /* short */ true), - ).toEqual('12mo'); - expect(relativeDate(reference - YEAR, reference, /* short */ true)).toEqual( - '1y', - ); - expect( - relativeDate(reference - YEAR * 2, reference, /* short */ true), - ).toEqual('2y'); - expect(relativeDate(0, reference, /* short */ true)).toEqual('5y'); - }); -}); + expect((0, (_string || _load_string()).relativeDate)(0, undefined, /* short */true)).toEqual(Math.round(now / YEAR) + 'y'); + expect((0, (_string || _load_string()).relativeDate)(reference * SECOND, reference, /* short */true)).toEqual('now'); + expect((0, (_string || _load_string()).relativeDate)(reference - 41 * SECOND, reference, /* short */true)).toEqual('now'); + expect((0, (_string || _load_string()).relativeDate)(reference - 42 * SECOND, reference, /* short */true)).toEqual('1m'); + expect((0, (_string || _load_string()).relativeDate)(reference - MINUTE, reference, /* short */true)).toEqual('1m'); + expect((0, (_string || _load_string()).relativeDate)(reference - MINUTE * 1.5, reference, /* short */true)).toEqual('2m'); + expect((0, (_string || _load_string()).relativeDate)(reference - MINUTE * 59, reference, /* short */true)).toEqual('59m'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR, reference, /* short */true)).toEqual('1h'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR * 1.5, reference, /* short */true)).toEqual('2h'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR * 16, reference, /* short */true)).toEqual('16h'); + expect((0, (_string || _load_string()).relativeDate)(reference - HOUR * 23, reference, /* short */true)).toEqual('23h'); + expect((0, (_string || _load_string()).relativeDate)(reference - DAY * 1.8, reference, /* short */true)).toEqual('1d'); + expect((0, (_string || _load_string()).relativeDate)(reference - DAY * 3, reference, /* short */true)).toEqual('3d'); + expect((0, (_string || _load_string()).relativeDate)(reference - DAY * 6, reference, /* short */true)).toEqual('6d'); + expect((0, (_string || _load_string()).relativeDate)(reference - WEEK, reference, /* short */true)).toEqual('1w'); + expect((0, (_string || _load_string()).relativeDate)(reference - WEEK * 2, reference, /* short */true)).toEqual('2w'); + expect((0, (_string || _load_string()).relativeDate)(reference - WEEK * 4, reference, /* short */true)).toEqual('4w'); + expect((0, (_string || _load_string()).relativeDate)(reference - MONTH * 1.2, reference, /* short */true)).toEqual('1mo'); + expect((0, (_string || _load_string()).relativeDate)(reference - YEAR + HOUR, reference, /* short */true)).toEqual('12mo'); + expect((0, (_string || _load_string()).relativeDate)(reference - YEAR, reference, /* short */true)).toEqual('1y'); + expect((0, (_string || _load_string()).relativeDate)(reference - YEAR * 2, reference, /* short */true)).toEqual('2y'); + expect((0, (_string || _load_string()).relativeDate)(0, reference, /* short */true)).toEqual('5y'); + }); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('maybeToString', () => { it("returns 'undefined'", () => { - expect(maybeToString(undefined)).toEqual('undefined'); + expect((0, (_string || _load_string()).maybeToString)(undefined)).toEqual('undefined'); }); it("returns 'null'", () => { - expect(maybeToString(null)).toEqual('null'); + expect((0, (_string || _load_string()).maybeToString)(null)).toEqual('null'); }); it('returns an ordinary string', () => { - expect(maybeToString('foo')).toEqual('foo'); + expect((0, (_string || _load_string()).maybeToString)('foo')).toEqual('foo'); }); }); describe('countOccurrences', () => { it('counts the number of characters', () => { - expect(countOccurrences('abcaaa', 'a')).toBe(4); + expect((0, (_string || _load_string()).countOccurrences)('abcaaa', 'a')).toBe(4); }); it('throws for non-length-1 searches', () => { expect(() => { - countOccurrences('abc', 'abc'); + (0, (_string || _load_string()).countOccurrences)('abc', 'abc'); }).toThrow(); }); }); describe('shellParse', () => { it('parses a list of arguments', () => { - expect(shellParse('1 2 3 "a b c"')).toEqual(['1', '2', '3', 'a b c']); + expect((0, (_string || _load_string()).shellParse)('1 2 3 "a b c"')).toEqual(['1', '2', '3', 'a b c']); }); it('throws if operators are given', () => { expect(() => { - shellParse('a | b'); + (0, (_string || _load_string()).shellParse)('a | b'); }).toThrow(Error('Unexpected operator "|" provided to shellParse')); expect(() => { - shellParse('a > b'); + (0, (_string || _load_string()).shellParse)('a > b'); }).toThrow(Error('Unexpected operator ">" provided to shellParse')); }); }); describe('removeCommonPrefix', () => { it('does nothing if there is no common prefix', () => { - expect(removeCommonPrefix('foo', 'bar')).toEqual(['foo', 'bar']); + expect((0, (_string || _load_string()).removeCommonPrefix)('foo', 'bar')).toEqual(['foo', 'bar']); }); it('removes a common prefix', () => { - expect(removeCommonPrefix('foo', 'fbar')).toEqual(['oo', 'bar']); - expect(removeCommonPrefix('asdffoo', 'asdfbar')).toEqual(['foo', 'bar']); + expect((0, (_string || _load_string()).removeCommonPrefix)('foo', 'fbar')).toEqual(['oo', 'bar']); + expect((0, (_string || _load_string()).removeCommonPrefix)('asdffoo', 'asdfbar')).toEqual(['foo', 'bar']); }); it('works with the empty string', () => { - expect(removeCommonPrefix('', 'bar')).toEqual(['', 'bar']); - expect(removeCommonPrefix('foo', '')).toEqual(['foo', '']); - expect(removeCommonPrefix('', '')).toEqual(['', '']); + expect((0, (_string || _load_string()).removeCommonPrefix)('', 'bar')).toEqual(['', 'bar']); + expect((0, (_string || _load_string()).removeCommonPrefix)('foo', '')).toEqual(['foo', '']); + expect((0, (_string || _load_string()).removeCommonPrefix)('', '')).toEqual(['', '']); }); it('returns empty strings for identical strings', () => { - expect(removeCommonPrefix('foo', 'foo')).toEqual(['', '']); + expect((0, (_string || _load_string()).removeCommonPrefix)('foo', 'foo')).toEqual(['', '']); }); }); describe('removeCommonSuffix', () => { it('does nothing if there is no common suffix', () => { - expect(removeCommonSuffix('foo', 'bar')).toEqual(['foo', 'bar']); + expect((0, (_string || _load_string()).removeCommonSuffix)('foo', 'bar')).toEqual(['foo', 'bar']); }); it('removes a common suffix', () => { - expect(removeCommonSuffix('foo', 'baro')).toEqual(['fo', 'bar']); - expect(removeCommonSuffix('fooasdf', 'baroasdf')).toEqual(['fo', 'bar']); + expect((0, (_string || _load_string()).removeCommonSuffix)('foo', 'baro')).toEqual(['fo', 'bar']); + expect((0, (_string || _load_string()).removeCommonSuffix)('fooasdf', 'baroasdf')).toEqual(['fo', 'bar']); }); it('works with the empty string', () => { - expect(removeCommonSuffix('', 'bar')).toEqual(['', 'bar']); - expect(removeCommonSuffix('foo', '')).toEqual(['foo', '']); - expect(removeCommonSuffix('', '')).toEqual(['', '']); + expect((0, (_string || _load_string()).removeCommonSuffix)('', 'bar')).toEqual(['', 'bar']); + expect((0, (_string || _load_string()).removeCommonSuffix)('foo', '')).toEqual(['foo', '']); + expect((0, (_string || _load_string()).removeCommonSuffix)('', '')).toEqual(['', '']); }); it('returns empty strings for identical strings', () => { - expect(removeCommonSuffix('foo', 'foo')).toEqual(['', '']); + expect((0, (_string || _load_string()).removeCommonSuffix)('foo', 'foo')).toEqual(['', '']); }); }); describe('shorten', () => { it('works', () => { - expect(shorten('', 1)).toEqual(''); - expect(shorten('test', 3)).toEqual('tes'); - expect(shorten('test', 100)).toEqual('test'); - expect(shorten('test', 1, '...')).toEqual('t...'); + expect((0, (_string || _load_string()).shorten)('', 1)).toEqual(''); + expect((0, (_string || _load_string()).shorten)('test', 3)).toEqual('tes'); + expect((0, (_string || _load_string()).shorten)('test', 100)).toEqual('test'); + expect((0, (_string || _load_string()).shorten)('test', 1, '...')).toEqual('t...'); }); }); describe('splitOnce', () => { it('splits once', () => { - expect(splitOnce('ab-cd-ef', '-')).toEqual(['ab', 'cd-ef']); + expect((0, (_string || _load_string()).splitOnce)('ab-cd-ef', '-')).toEqual(['ab', 'cd-ef']); }); it("handles when there's no match", () => { - expect(splitOnce('ab-cd-ef', '_')).toEqual(['ab-cd-ef', null]); + expect((0, (_string || _load_string()).splitOnce)('ab-cd-ef', '_')).toEqual(['ab-cd-ef', null]); }); }); describe('indent', () => { it('indents lines', () => { - expect(indent('a\nb')).toBe(' a\n b'); + expect((0, (_string || _load_string()).indent)('a\nb')).toBe(' a\n b'); }); it("doesn't indent empty lines", () => { - expect(indent('a\n\nb')).toBe(' a\n\n b'); + expect((0, (_string || _load_string()).indent)('a\n\nb')).toBe(' a\n\n b'); }); it('uses the provided level', () => { - expect(indent('a\n\nb', 4)).toBe(' a\n\n b'); + expect((0, (_string || _load_string()).indent)('a\n\nb', 4)).toBe(' a\n\n b'); }); it('uses the provided character', () => { - expect(indent('a\n\nb', 1, '\t')).toBe('\ta\n\n\tb'); + expect((0, (_string || _load_string()).indent)('a\n\nb', 1, '\t')).toBe('\ta\n\n\tb'); }); }); describe('pluralize', () => { it('works', () => { - expect(pluralize('test', 0)).toEqual('tests'); - expect(pluralize('test', 1)).toEqual('test'); - expect(pluralize('test', 2)).toEqual('tests'); - expect(pluralize('test', 123)).toEqual('tests'); + expect((0, (_string || _load_string()).pluralize)('test', 0)).toEqual('tests'); + expect((0, (_string || _load_string()).pluralize)('test', 1)).toEqual('test'); + expect((0, (_string || _load_string()).pluralize)('test', 2)).toEqual('tests'); + expect((0, (_string || _load_string()).pluralize)('test', 123)).toEqual('tests'); }); }); describe('capitalize', () => { it('works', () => { - expect(capitalize('')).toEqual(''); - expect(capitalize('t')).toEqual('T'); - expect(capitalize('te')).toEqual('Te'); - expect(capitalize('test')).toEqual('Test'); + expect((0, (_string || _load_string()).capitalize)('')).toEqual(''); + expect((0, (_string || _load_string()).capitalize)('t')).toEqual('T'); + expect((0, (_string || _load_string()).capitalize)('te')).toEqual('Te'); + expect((0, (_string || _load_string()).capitalize)('test')).toEqual('Test'); }); }); describe('getMatchRanges', () => { it('works', () => { - expect(getMatchRanges('test1test2test3', 'test')).toEqual([ - [0, 4], - [5, 9], - [10, 14], - ]); - expect(getMatchRanges('ttttttt', 'ttt')).toEqual([[0, 6]]); - expect(getMatchRanges('test1test2test3', 'none')).toEqual([]); - expect(getMatchRanges('test1test2test3', '')).toEqual([]); + expect((0, (_string || _load_string()).getMatchRanges)('test1test2test3', 'test')).toEqual([[0, 4], [5, 9], [10, 14]]); + expect((0, (_string || _load_string()).getMatchRanges)('ttttttt', 'ttt')).toEqual([[0, 6]]); + expect((0, (_string || _load_string()).getMatchRanges)('test1test2test3', 'none')).toEqual([]); + expect((0, (_string || _load_string()).getMatchRanges)('test1test2test3', '')).toEqual([]); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/symbol-definition-preview-spec.js b/modules/nuclide-commons/spec/symbol-definition-preview-spec.js index 6635046b..1fe9873b 100644 --- a/modules/nuclide-commons/spec/symbol-definition-preview-spec.js +++ b/modules/nuclide-commons/spec/symbol-definition-preview-spec.js @@ -1,3 +1,33 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('../nuclideUri')); +} + +var _dedent; + +function _load_dedent() { + return _dedent = _interopRequireDefault(require('dedent')); +} + +var _simpleTextBuffer; + +function _load_simpleTextBuffer() { + return _simpleTextBuffer = require('simple-text-buffer'); +} + +var _symbolDefinitionPreview; + +function _load_symbolDefinitionPreview() { + return _symbolDefinitionPreview = require('../symbol-definition-preview'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,198 +36,190 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import nuclideUri from '../nuclideUri'; -import dedent from 'dedent'; -import {Point} from 'simple-text-buffer'; -import {getDefinitionPreview} from '../symbol-definition-preview'; -import invariant from 'assert'; - -function javascriptFixtureDefinitionWithPoint(point: Point) { +function javascriptFixtureDefinitionWithPoint(point) { return { - path: nuclideUri.join( - __dirname, - 'fixtures', - 'symbol-definition-preview-sample.js', - ), + path: (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures', 'symbol-definition-preview-sample.js'), language: 'javascript', - position: point, + position: point }; } -function pythonFixtureDefinitionWithPoint(point: Point) { +function pythonFixtureDefinitionWithPoint(point) { return { - path: nuclideUri.join( - __dirname, - 'fixtures', - 'symbol-definition-preview-sample.py', - ), + path: (_nuclideUri || _load_nuclideUri()).default.join(__dirname, 'fixtures', 'symbol-definition-preview-sample.py'), language: 'python', - position: point, + position: point }; } describe('getDefinitionPreview', () => { describe('Constant symbols', () => { it('returns the only line of a one-line symbol', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(11, 6)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(11, 6))); expect(preview).not.toBeNull(); - invariant(preview != null); + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + expect(preview.contents).toEqual('const A_CONSTANT = 42;'); - }); + })); }); it('returns the entire multi-line symbol', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(15, 6)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(15, 6))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - dedent`const A_MULTILINE_CONST = \` + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual((_dedent || _load_dedent()).default`const A_MULTILINE_CONST = \` hey look I span multiple lines - \`;`, - ); - }); + \`;`); + })); }); }); describe('Type symbols', () => { it('returns an entire multi-line type', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(21, 5)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(21, 5))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - dedent`type Something = { + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual((_dedent || _load_dedent()).default`type Something = { name: string, age?: number, - };`, - ); - }); + };`); + })); }); it('returns only the property from within a type', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(44, 4)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(44, 4))); expect(preview).not.toBeNull(); - invariant(preview != null); + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + expect(preview.contents).toEqual('name: string,'); - }); + })); }); it('returns property and value of a complex type within a type', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(43, 2)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(43, 2))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - dedent`properties: { + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual((_dedent || _load_dedent()).default`properties: { name: string, age?: number, - },`, - ); - }); + },`); + })); }); }); describe('Function symbols', () => { it('returns just one line if parens are balanced on the first line', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(26, 16)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(26, 16))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - 'export function aSingleLineFunctionSignature() {', - ); - }); + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual('export function aSingleLineFunctionSignature() {'); + })); }); it('works without parentheses as with python', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - pythonFixtureDefinitionWithPoint(new Point(7, 4)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(pythonFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(7, 4))); expect(preview).not.toBeNull(); - invariant(preview != null); + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + expect(preview.contents).toEqual('def foo(bar=27):'); - }); + })); }); it('works without parentheses but with braces as with python', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - pythonFixtureDefinitionWithPoint(new Point(11, 4)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(pythonFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(11, 4))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - dedent`def baz(test={ + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual((_dedent || _load_dedent()).default`def baz(test={ 'one': 'two' - }):`, - ); - }); + }):`); + })); }); it("doesn't dedent beyond the current lines indentation level", () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(36, 18)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(36, 18))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - dedent` + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual((_dedent || _load_dedent()).default` export function aPoorlyIndentedFunction( aReallyReallyLongArgumentNameThatWouldRequireThisToBreakAcrossMultipleLines: Something, ): number { - `, - ); - }); + `); + })); }); it('reads until the indentation returns to initial and parens are balanced', () => { - waitsForPromise(async () => { - const preview = await getDefinitionPreview( - javascriptFixtureDefinitionWithPoint(new Point(30, 16)), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const preview = yield (0, (_symbolDefinitionPreview || _load_symbolDefinitionPreview()).getDefinitionPreview)(javascriptFixtureDefinitionWithPoint(new (_simpleTextBuffer || _load_simpleTextBuffer()).Point(30, 16))); expect(preview).not.toBeNull(); - invariant(preview != null); - expect(preview.contents).toEqual( - dedent` + + if (!(preview != null)) { + throw new Error('Invariant violation: "preview != null"'); + } + + expect(preview.contents).toEqual((_dedent || _load_dedent()).default` export function aMultiLineFunctionSignature( aReallyReallyLongArgumentNameThatWouldRequireThisToBreakAcrossMultipleLines: Something, ): number { - `, - ); - }); + `); + })); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/test-helpers-spec.js b/modules/nuclide-commons/spec/test-helpers-spec.js index 17071821..b02e58d4 100644 --- a/modules/nuclide-commons/spec/test-helpers-spec.js +++ b/modules/nuclide-commons/spec/test-helpers-spec.js @@ -1,64 +1,72 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import typeof * as TestModuleType from './fixtures/toBeTested'; - -import fs from 'fs'; -import glob from 'glob'; -import nuclideUri from '../nuclideUri'; -import { - arePropertiesEqual, - clearRequireCache, - expectAsyncFailure, - generateFixture, - uncachedRequire, -} from '../test-helpers'; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _fs = _interopRequireDefault(require('fs')); + +var _glob; + +function _load_glob() { + return _glob = _interopRequireDefault(require('glob')); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('../nuclideUri')); +} + +var _testHelpers; + +function _load_testHelpers() { + return _testHelpers = require('../test-helpers'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } describe('arePropertiesEqual', () => { it('correctly compares empty objects', () => { - expect(arePropertiesEqual({}, {})).toBe(true); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({}, {})).toBe(true); }); it('correctly compares objects with the same properties', () => { - expect(arePropertiesEqual({foo: 5}, {foo: 5})).toBe(true); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({ foo: 5 }, { foo: 5 })).toBe(true); }); it('allows one property to be undefined while another does not exist at all', () => { - expect(arePropertiesEqual({foo: undefined}, {})).toBe(true); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({ foo: undefined }, {})).toBe(true); }); it('returns false when properties are not equal', () => { - expect(arePropertiesEqual({foo: 5}, {foo: 4})).toBe(false); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({ foo: 5 }, { foo: 4 })).toBe(false); }); it('returns false when one property is undefined and another is defined', () => { - expect(arePropertiesEqual({foo: 5}, {foo: undefined})).toBe(false); - expect(arePropertiesEqual({foo: undefined}, {foo: 5})).toBe(false); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({ foo: 5 }, { foo: undefined })).toBe(false); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({ foo: undefined }, { foo: 5 })).toBe(false); }); it('returns false when one property exists but the other does not', () => { - expect(arePropertiesEqual({foo: 5}, {})).toBe(false); - expect(arePropertiesEqual({}, {foo: 5})).toBe(false); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({ foo: 5 }, {})).toBe(false); + expect((0, (_testHelpers || _load_testHelpers()).arePropertiesEqual)({}, { foo: 5 })).toBe(false); }); -}); +}); /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ describe('expectAsyncFailure', () => { it('fails when provided Promise succeeds', () => { - const verify: any = jasmine.createSpy(); - waitsForPromise({shouldReject: true}, () => { - return expectAsyncFailure( - Promise.resolve('resolved, not rejected!'), - verify, - ); + const verify = jasmine.createSpy(); + waitsForPromise({ shouldReject: true }, () => { + return (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(Promise.resolve('resolved, not rejected!'), verify); }); runs(() => { expect(verify.callCount).toBe(0); @@ -75,8 +83,8 @@ describe('expectAsyncFailure', () => { } } - waitsForPromise({shouldReject: true}, () => { - return expectAsyncFailure(Promise.reject(Error('I failed.')), verify); + waitsForPromise({ shouldReject: true }, () => { + return (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(Promise.reject(Error('I failed.')), verify); }); runs(() => { expect(callCount).toBe(1); @@ -93,11 +101,8 @@ describe('expectAsyncFailure', () => { } } - waitsForPromise({shouldReject: false}, () => { - return expectAsyncFailure( - Promise.reject(Error('I failed badly.')), - verify, - ); + waitsForPromise({ shouldReject: false }, () => { + return (0, (_testHelpers || _load_testHelpers()).expectAsyncFailure)(Promise.reject(Error('I failed badly.')), verify); }); runs(() => { expect(callCount).toBe(1); @@ -107,58 +112,53 @@ describe('expectAsyncFailure', () => { describe('generateFixture', () => { it('should create the directory hierarchy', () => { - waitsForPromise(async () => { - const fixturePath = await generateFixture( - 'fixture-to-generate', - new Map([['foo.js', undefined], ['bar/baz.txt', 'some text']]), - ); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const fixturePath = yield (0, (_testHelpers || _load_testHelpers()).generateFixture)('fixture-to-generate', new Map([['foo.js', undefined], ['bar/baz.txt', 'some text']])); - expect(nuclideUri.isAbsolute(fixturePath)).toBe(true); - expect(fs.statSync(fixturePath).isDirectory()).toBe(true); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute(fixturePath)).toBe(true); + expect(_fs.default.statSync(fixturePath).isDirectory()).toBe(true); - const fooPath = nuclideUri.join(fixturePath, 'foo.js'); - const bazPath = nuclideUri.join(fixturePath, 'bar/baz.txt'); + const fooPath = (_nuclideUri || _load_nuclideUri()).default.join(fixturePath, 'foo.js'); + const bazPath = (_nuclideUri || _load_nuclideUri()).default.join(fixturePath, 'bar/baz.txt'); - expect(fs.statSync(fooPath).isFile()).toBe(true); - expect(fs.statSync(bazPath).isFile()).toBe(true); + expect(_fs.default.statSync(fooPath).isFile()).toBe(true); + expect(_fs.default.statSync(bazPath).isFile()).toBe(true); - expect(fs.readFileSync(fooPath, 'utf8')).toBe(''); - expect(fs.readFileSync(bazPath, 'utf8')).toBe('some text'); - }); + expect(_fs.default.readFileSync(fooPath, 'utf8')).toBe(''); + expect(_fs.default.readFileSync(bazPath, 'utf8')).toBe('some text'); + })); }); it('should work with lots of files', () => { - waitsForPromise({timeout: 10000}, async () => { + waitsForPromise({ timeout: 10000 }, (0, _asyncToGenerator.default)(function* () { const files = new Map(); for (let i = 0; i < 10; i++) { for (let j = 0; j < 1000; j++) { files.set(`dir_${i}/file_${j}.txt`, `${i} + ${j} = ${i + j}`); } } - const fixturePath = await generateFixture('lots-of-files', files); - const fixtureFiles = glob.sync( - nuclideUri.join(fixturePath, 'dir_*/file_*.txt'), - ); + const fixturePath = yield (0, (_testHelpers || _load_testHelpers()).generateFixture)('lots-of-files', files); + const fixtureFiles = (_glob || _load_glob()).default.sync((_nuclideUri || _load_nuclideUri()).default.join(fixturePath, 'dir_*/file_*.txt')); expect(fixtureFiles.length).toBe(10000); - }); + })); }); it('should work with no files', () => { - waitsForPromise(async () => { - const fixturePath = await generateFixture('fixture-empty', new Map()); - expect(nuclideUri.isAbsolute(fixturePath)).toBe(true); - expect(fs.statSync(fixturePath).isDirectory()).toBe(true); - expect(fs.readdirSync(fixturePath)).toEqual([]); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const fixturePath = yield (0, (_testHelpers || _load_testHelpers()).generateFixture)('fixture-empty', new Map()); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute(fixturePath)).toBe(true); + expect(_fs.default.statSync(fixturePath).isDirectory()).toBe(true); + expect(_fs.default.readdirSync(fixturePath)).toEqual([]); + })); }); it('works with no files arg', () => { - waitsForPromise(async () => { - const fixturePath = await generateFixture('fixture-empty'); - expect(nuclideUri.isAbsolute(fixturePath)).toBe(true); - expect(fs.statSync(fixturePath).isDirectory()).toBe(true); - expect(fs.readdirSync(fixturePath)).toEqual([]); - }); + waitsForPromise((0, _asyncToGenerator.default)(function* () { + const fixturePath = yield (0, (_testHelpers || _load_testHelpers()).generateFixture)('fixture-empty'); + expect((_nuclideUri || _load_nuclideUri()).default.isAbsolute(fixturePath)).toBe(true); + expect(_fs.default.statSync(fixturePath).isDirectory()).toBe(true); + expect(_fs.default.readdirSync(fixturePath)).toEqual([]); + })); }); }); @@ -166,19 +166,13 @@ describe('Mocking Imports test suite', () => { // Tests ToBeTested.functionToTest while mocking imported function toBeMocked. it('Mocking imported dependencies', () => { // 1 - First mock all functions imported by the module under test - const mock = spyOn( - require('./fixtures/toBeMocked'), - 'importedFunction', - ).andReturn(45); + const mock = spyOn(require('./fixtures/toBeMocked'), 'importedFunction').andReturn(45); // 2 - Do an uncachedRequire of the module to test // Note the 'import typeof * as ... ' above to get type checking // for the functions to be tested. // You may want to put steps 1 & 2 in your beforeEach. - const moduleToTest: TestModuleType = (uncachedRequire( - require, - './fixtures/toBeTested', - ): any); + const moduleToTest = (0, (_testHelpers || _load_testHelpers()).uncachedRequire)(require, './fixtures/toBeTested'); // 3 - Perform your test const result = moduleToTest.functionToTest(); @@ -187,6 +181,6 @@ describe('Mocking Imports test suite', () => { // 4 - Reset the require cache so your mocks don't get used for other tests. // You may want to put this in your afterEach. - clearRequireCache(require, './fixtures/toBeTested'); + (0, (_testHelpers || _load_testHelpers()).clearRequireCache)(require, './fixtures/toBeTested'); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/spec/which-spec.js b/modules/nuclide-commons/spec/which-spec.js index 230ee102..35d91c2c 100644 --- a/modules/nuclide-commons/spec/which-spec.js +++ b/modules/nuclide-commons/spec/which-spec.js @@ -1,3 +1,17 @@ +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _which; + +function _load_which() { + return _which = _interopRequireDefault(require('../which')); +} + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,22 +20,17 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import which from '../which'; -import {Observable} from 'rxjs'; - describe('which', () => { - let runCommand: JasmineSpy; + let runCommand; let runCommandReturn = ''; beforeEach(() => { runCommandReturn = ''; - runCommand = spyOn(require('../process'), 'runCommand').andCallFake(() => - Observable.of(runCommandReturn), - ); + runCommand = spyOn(require('../process'), 'runCommand').andCallFake(() => _rxjsBundlesRxMinJs.Observable.of(runCommandReturn)); }); afterEach(() => { @@ -29,60 +38,60 @@ describe('which', () => { }); describe('on windows', () => { - const real_platform: string = process.platform; + const real_platform = process.platform; const eol = '\r\n'; const os = require('os'); const real_eol = os.EOL; beforeEach(() => { - Object.defineProperty(process, 'platform', {value: 'win32'}); + Object.defineProperty(process, 'platform', { value: 'win32' }); os.EOL = eol; }); afterEach(() => { - Object.defineProperty(process, 'platform', {value: real_platform}); + Object.defineProperty(process, 'platform', { value: real_platform }); os.EOL = real_eol; }); it('calls where on Windows', () => { - const param: string = ''; - which(param); + const param = ''; + (0, (_which || _load_which()).default)(param); expect(runCommand).toHaveBeenCalledWith('where', ['']); }); it('returns the first match', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { runCommandReturn = 'hello' + os.EOL + 'hello.exe' + os.EOL; - const ret = await which('bla'); + const ret = yield (0, (_which || _load_which()).default)('bla'); expect(ret).toEqual('hello'); - }); + })); }); }); describe('on linux', () => { - const real_platform: string = process.platform; + const real_platform = process.platform; const eol = '\n'; const os = require('os'); const real_eol = os.EOL; beforeEach(() => { - Object.defineProperty(process, 'platform', {value: 'linux'}); + Object.defineProperty(process, 'platform', { value: 'linux' }); os.EOL = eol; }); afterEach(() => { - Object.defineProperty(process, 'platform', {value: real_platform}); + Object.defineProperty(process, 'platform', { value: real_platform }); os.EOL = real_eol; }); it('calls which', () => { - const param: string = ''; - which(param); + const param = ''; + (0, (_which || _load_which()).default)(param); expect(runCommand).toHaveBeenCalledWith('which', [param]); }); it('returns the first match', () => { - waitsForPromise(async () => { + waitsForPromise((0, _asyncToGenerator.default)(function* () { runCommandReturn = 'hello' + os.EOL + '/bin/hello' + os.EOL; - const ret = await which('bla'); + const ret = yield (0, (_which || _load_which()).default)('bla'); expect(ret).toEqual('hello'); - }); + })); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-commons/stream.js b/modules/nuclide-commons/stream.js index 936d0f1d..a4dae557 100644 --- a/modules/nuclide-commons/stream.js +++ b/modules/nuclide-commons/stream.js @@ -1,3 +1,33 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.observeStream = observeStream; +exports.observeRawStream = observeRawStream; +exports.writeToStream = writeToStream; + +var _stream = _interopRequireDefault(require('stream')); + +var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); + +var _UniversalDisposable; + +function _load_UniversalDisposable() { + return _UniversalDisposable = _interopRequireDefault(require('./UniversalDisposable')); +} + +var _event; + +function _load_event() { + return _event = require('./event'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Observe a stream like stdout or stderr. + */ /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,69 +36,47 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import Stream from 'stream'; -import {Observable} from 'rxjs'; - -import UniversalDisposable from './UniversalDisposable'; -import {attachEvent} from './event'; - -/** - * Observe a stream like stdout or stderr. - */ -export function observeStream(stream: stream$Readable): Observable { +function observeStream(stream) { return observeRawStream(stream).map(data => data.toString()); } -export function observeRawStream(stream: stream$Readable): Observable { - const error = Observable.fromEvent(stream, 'error').flatMap(Observable.throw); - return Observable.fromEvent(stream, 'data') - .merge(error) - .takeUntil(Observable.fromEvent(stream, 'end')); +function observeRawStream(stream) { + const error = _rxjsBundlesRxMinJs.Observable.fromEvent(stream, 'error').flatMap(_rxjsBundlesRxMinJs.Observable.throw); + return _rxjsBundlesRxMinJs.Observable.fromEvent(stream, 'data').merge(error).takeUntil(_rxjsBundlesRxMinJs.Observable.fromEvent(stream, 'end')); } /** * Write an observed readable stream into a writable stream. Effectively a pipe() for observables. * Returns an observable accumulating the number of bytes processed. */ -export function writeToStream( - source: Observable, - destStream: stream$Writable, -): Observable { - return Observable.create(observer => { +function writeToStream(source, destStream) { + return _rxjsBundlesRxMinJs.Observable.create(observer => { let byteCount = 0; - const byteCounterStream = new Stream.Transform({ + const byteCounterStream = new _stream.default.Transform({ transform(chunk, encoding, cb) { byteCount += chunk.byteLength; observer.next(byteCount); cb(null, chunk); - }, + } }); byteCounterStream.pipe(destStream); - return new UniversalDisposable( - attachEvent(destStream, 'error', err => { - observer.error(err); - }), - attachEvent(destStream, 'close', () => { - observer.complete(); - }), - source.subscribe( - buffer => { - byteCounterStream.write(buffer); - }, - err => { - observer.error(err); - }, - () => { - byteCounterStream.end(); - }, - ), - ); + return new (_UniversalDisposable || _load_UniversalDisposable()).default((0, (_event || _load_event()).attachEvent)(destStream, 'error', err => { + observer.error(err); + }), (0, (_event || _load_event()).attachEvent)(destStream, 'close', () => { + observer.complete(); + }), source.subscribe(buffer => { + byteCounterStream.write(buffer); + }, err => { + observer.error(err); + }, () => { + byteCounterStream.end(); + })); }).share(); -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/string.js b/modules/nuclide-commons/string.js index 49feba6a..1500d125 100644 --- a/modules/nuclide-commons/string.js +++ b/modules/nuclide-commons/string.js @@ -1,3 +1,30 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ELLIPSIS_CHAR = exports.URL_REGEX = undefined; +exports.stringifyError = stringifyError; +exports.maybeToString = maybeToString; +exports.relativeDate = relativeDate; +exports.countOccurrences = countOccurrences; +exports.shellParse = shellParse; +exports.shellQuote = shellQuote; +exports.removeCommonPrefix = removeCommonPrefix; +exports.removeCommonSuffix = removeCommonSuffix; +exports.shorten = shorten; +exports.splitOnce = splitOnce; +exports.indent = indent; +exports.pluralize = pluralize; +exports.capitalize = capitalize; +exports.getMatchRanges = getMatchRanges; + +var _shellQuote; + +function _load_shellQuote() { + return _shellQuote = require('./_shell-quote'); +} + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,22 +33,17 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -import invariant from 'assert'; -import {parse, quote} from './_shell-quote'; - -export function stringifyError(error: Error): string { - return `name: ${error.name}, message: ${error.message}, stack: ${ - error.stack - }.`; +function stringifyError(error) { + return `name: ${error.name}, message: ${error.message}, stack: ${error.stack}.`; } // As of Flow v0.28, Flow does not alllow implicit string coercion of null or undefined. Use this to // make it explicit. -export function maybeToString(str: ?string): string { +function maybeToString(str) { // We don't want to encourage the use of this function directly because it coerces anything to a // string. We get stricter typechecking by using maybeToString, so it should generally be // preferred. @@ -40,43 +62,11 @@ const WEEK = 7 * DAY; const YEAR = DAY * 365; const MONTH = YEAR / 12; -const shortFormats = [ - [0.7 * MINUTE, 'now'], - [1.5 * MINUTE, '1m'], - [60 * MINUTE, 'm', MINUTE], - [1.5 * HOUR, '1h'], - [DAY, 'h', HOUR], - [2 * DAY, '1d'], - [7 * DAY, 'd', DAY], - [1.5 * WEEK, '1w'], - [MONTH, 'w', WEEK], - [1.5 * MONTH, '1mo'], - [YEAR, 'mo', MONTH], - [1.5 * YEAR, '1y'], - [Number.MAX_VALUE, 'y', YEAR], -]; +const shortFormats = [[0.7 * MINUTE, 'now'], [1.5 * MINUTE, '1m'], [60 * MINUTE, 'm', MINUTE], [1.5 * HOUR, '1h'], [DAY, 'h', HOUR], [2 * DAY, '1d'], [7 * DAY, 'd', DAY], [1.5 * WEEK, '1w'], [MONTH, 'w', WEEK], [1.5 * MONTH, '1mo'], [YEAR, 'mo', MONTH], [1.5 * YEAR, '1y'], [Number.MAX_VALUE, 'y', YEAR]]; -const longFormats = [ - [0.7 * MINUTE, 'just now'], - [1.5 * MINUTE, 'a minute ago'], - [60 * MINUTE, 'minutes ago', MINUTE], - [1.5 * HOUR, 'an hour ago'], - [DAY, 'hours ago', HOUR], - [2 * DAY, 'yesterday'], - [7 * DAY, 'days ago', DAY], - [1.5 * WEEK, 'a week ago'], - [MONTH, 'weeks ago', WEEK], - [1.5 * MONTH, 'a month ago'], - [YEAR, 'months ago', MONTH], - [1.5 * YEAR, 'a year ago'], - [Number.MAX_VALUE, 'years ago', YEAR], -]; +const longFormats = [[0.7 * MINUTE, 'just now'], [1.5 * MINUTE, 'a minute ago'], [60 * MINUTE, 'minutes ago', MINUTE], [1.5 * HOUR, 'an hour ago'], [DAY, 'hours ago', HOUR], [2 * DAY, 'yesterday'], [7 * DAY, 'days ago', DAY], [1.5 * WEEK, 'a week ago'], [MONTH, 'weeks ago', WEEK], [1.5 * MONTH, 'a month ago'], [YEAR, 'months ago', MONTH], [1.5 * YEAR, 'a year ago'], [Number.MAX_VALUE, 'years ago', YEAR]]; -export function relativeDate( - input_: number | Date, - reference_?: number | Date, - useShortVariant?: boolean = false, -): string { +function relativeDate(input_, reference_, useShortVariant = false) { let input = input_; let reference = reference_; if (input instanceof Date) { @@ -95,11 +85,7 @@ export function relativeDate( for (const [limit, relativeFormat, remainder] of formats) { if (delta < limit) { if (typeof remainder === 'number') { - return ( - Math.round(delta / remainder) + - (useShortVariant ? '' : ' ') + - relativeFormat - ); + return Math.round(delta / remainder) + (useShortVariant ? '' : ' ') + relativeFormat; } else { return relativeFormat; } @@ -113,8 +99,10 @@ export function relativeDate( * Count the number of occurrences of `char` in `str`. * `char` must be a string of length 1. */ -export function countOccurrences(haystack: string, char: string) { - invariant(char.length === 1, 'char must be a string of length 1'); +function countOccurrences(haystack, char) { + if (!(char.length === 1)) { + throw new Error('char must be a string of length 1'); + } let count = 0; const code = char.charCodeAt(0); @@ -130,18 +118,14 @@ export function countOccurrences(haystack: string, char: string) { * shell-quote's parse allows pipe operators and comments. * Generally users don't care about this, so throw if we encounter any operators. */ -export function shellParse(str: string, env?: Object): Array { - const result = parse(str, env); +function shellParse(str, env) { + const result = (0, (_shellQuote || _load_shellQuote()).parse)(str, env); for (let i = 0; i < result.length; i++) { if (typeof result[i] !== 'string') { if (result[i].op != null) { - throw new Error( - `Unexpected operator "${result[i].op}" provided to shellParse`, - ); + throw new Error(`Unexpected operator "${result[i].op}" provided to shellParse`); } else { - throw new Error( - `Unexpected comment "${result[i].comment}" provided to shellParse`, - ); + throw new Error(`Unexpected comment "${result[i].comment}" provided to shellParse`); } } } @@ -152,11 +136,11 @@ export function shellParse(str: string, env?: Object): Array { * Technically you can pass in { operator: string } here, * but we don't use that in most APIs. */ -export function shellQuote(args: Array): string { - return quote(args); +function shellQuote(args) { + return (0, (_shellQuote || _load_shellQuote()).quote)(args); } -export function removeCommonPrefix(a: string, b: string): [string, string] { +function removeCommonPrefix(a, b) { let i = 0; while (a[i] === b[i] && i < a.length && i < b.length) { i++; @@ -164,73 +148,47 @@ export function removeCommonPrefix(a: string, b: string): [string, string] { return [a.substring(i), b.substring(i)]; } -export function removeCommonSuffix(a: string, b: string): [string, string] { +function removeCommonSuffix(a, b) { let i = 0; - while ( - a[a.length - 1 - i] === b[b.length - 1 - i] && - i < a.length && - i < b.length - ) { + while (a[a.length - 1 - i] === b[b.length - 1 - i] && i < a.length && i < b.length) { i++; } return [a.substring(0, a.length - i), b.substring(0, b.length - i)]; } -export function shorten( - str: string, - maxLength: number, - suffix?: string, -): string { - return str.length < maxLength - ? str - : str.slice(0, maxLength) + (suffix || ''); +function shorten(str, maxLength, suffix) { + return str.length < maxLength ? str : str.slice(0, maxLength) + (suffix || ''); } /** * Like String.split, but only splits once. */ -export function splitOnce(str: string, separator: string): [string, ?string] { +function splitOnce(str, separator) { const index = str.indexOf(separator); - return index === -1 - ? [str, null] - : [str.slice(0, index), str.slice(index + separator.length)]; + return index === -1 ? [str, null] : [str.slice(0, index), str.slice(index + separator.length)]; } /** * Indents each line by the specified number of characters. */ -export function indent( - str: string, - level: number = 2, - char: string = ' ', -): string { +function indent(str, level = 2, char = ' ') { return str.replace(/^([^\n])/gm, char.repeat(level) + '$1'); } -export function pluralize(noun: string, count: number) { +function pluralize(noun, count) { return count === 1 ? noun : noun + 's'; } -export function capitalize(str: string): string { - return str.length === 0 - ? str - : str - .charAt(0) - .toUpperCase() - .concat(str.slice(1)); +function capitalize(str) { + return str.length === 0 ? str : str.charAt(0).toUpperCase().concat(str.slice(1)); } -type MatchRange = [/* start */ number, /* end */ number]; - /** * Returns a list of ranges where needle occurs in haystack. * This will *not* return overlapping matches; i.e. the returned list will be disjoint. * This makes it easier to use for e.g. highlighting matches in a UI. */ -export function getMatchRanges( - haystack: string, - needle: string, -): Array { +function getMatchRanges(haystack, needle) { if (needle === '') { // Not really a valid use. return []; @@ -257,6 +215,6 @@ export function getMatchRanges( // Then optimized with https://www.npmjs.com/package/regexp-tree. // Added a single matching group for use with String.split. // eslint-disable-next-line max-len -export const URL_REGEX = /(https?:\/\/(?:www\.)?[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*|www\.[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*)/; +const URL_REGEX = exports.URL_REGEX = /(https?:\/\/(?:www\.)?[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*|www\.[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*)/; -export const ELLIPSIS_CHAR = '\u2026'; +const ELLIPSIS_CHAR = exports.ELLIPSIS_CHAR = '\u2026'; \ No newline at end of file diff --git a/modules/nuclide-commons/symbol-definition-preview.js b/modules/nuclide-commons/symbol-definition-preview.js index 9371c3cf..3560a059 100644 --- a/modules/nuclide-commons/symbol-definition-preview.js +++ b/modules/nuclide-commons/symbol-definition-preview.js @@ -1,101 +1,114 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {NuclideUri} from './nuclideUri'; -import mimeTypes from 'mime-types'; -import fsPromise from './fsPromise'; -import {countOccurrences} from './string'; -import nuclideUri from './nuclideUri'; - -type Definition = { - path: NuclideUri, - position: atom$Point, -}; - -const MAX_PREVIEW_LINES = 10; -const MAX_FILESIZE = 100000; -const WHITESPACE_REGEX = /^\s*/; -function getIndentLevel(line: string) { - return WHITESPACE_REGEX.exec(line)[0].length; -} +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getDefinitionPreview = undefined; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +let getDefinitionPreview = exports.getDefinitionPreview = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (definition) { + // ensure filesize not too big before reading in whole file + const stats = yield (_fsPromise || _load_fsPromise()).default.stat(definition.path); + if (stats.size > MAX_FILESIZE) { + return null; + } + + // if file is image, return base-64 encoded contents + const fileBuffer = yield (_fsPromise || _load_fsPromise()).default.readFile(definition.path); -export async function getDefinitionPreview( - definition: Definition, -): Promise { - // ensure filesize not too big before reading in whole file - const stats = await fsPromise.stat(definition.path); - if (stats.size > MAX_FILESIZE) { - return null; - } - - // if file is image, return base-64 encoded contents - const fileBuffer = await fsPromise.readFile(definition.path); - - const mime = - mimeTypes.contentType(nuclideUri.extname(definition.path)) || 'text/plain'; - if (mime.startsWith('image/')) { - return {mime, contents: fileBuffer.toString('base64'), encoding: 'base64'}; - } - - const contents = fileBuffer.toString('utf8'); - const lines = contents.split('\n'); - - const start = definition.position.row; - const initialIndentLevel = getIndentLevel(lines[start]); - - const buffer = []; - for ( - let i = start, - openParenCount = 0, - closedParenCount = 0, - openCurlyCount = 0, - closedCurlyCount = 0; - i < start + MAX_PREVIEW_LINES && i < lines.length; - i++ - ) { - const line = lines[i]; - const indentLevel = getIndentLevel(line); - openParenCount += countOccurrences(line, '('); - closedParenCount += countOccurrences(line, ')'); - openCurlyCount += countOccurrences(line, '{'); - closedCurlyCount += countOccurrences(line, '}'); - - buffer.push(line.substr(Math.min(indentLevel, initialIndentLevel))); // dedent - - // heuristic for the end of a function signature: - if (indentLevel <= initialIndentLevel) { - // we've returned back to the original indentation level - if (openParenCount > 0 && openParenCount === closedParenCount) { - // if we're in a fn definition, make sure we have balanced pairs of parens - break; - } else if (line.trim().endsWith(';')) { - // c-style statement ending - break; - } else if ( + const mime = (_mimeTypes || _load_mimeTypes()).default.contentType((_nuclideUri || _load_nuclideUri()).default.extname(definition.path)) || 'text/plain'; + if (mime.startsWith('image/')) { + return { mime, contents: fileBuffer.toString('base64'), encoding: 'base64' }; + } + + const contents = fileBuffer.toString('utf8'); + const lines = contents.split('\n'); + + const start = definition.position.row; + const initialIndentLevel = getIndentLevel(lines[start]); + + const buffer = []; + for (let i = start, openParenCount = 0, closedParenCount = 0, openCurlyCount = 0, closedCurlyCount = 0; i < start + MAX_PREVIEW_LINES && i < lines.length; i++) { + const line = lines[i]; + const indentLevel = getIndentLevel(line); + openParenCount += (0, (_string || _load_string()).countOccurrences)(line, '('); + closedParenCount += (0, (_string || _load_string()).countOccurrences)(line, ')'); + openCurlyCount += (0, (_string || _load_string()).countOccurrences)(line, '{'); + closedCurlyCount += (0, (_string || _load_string()).countOccurrences)(line, '}'); + + buffer.push(line.substr(Math.min(indentLevel, initialIndentLevel))); // dedent + + // heuristic for the end of a function signature: + if (indentLevel <= initialIndentLevel) { + // we've returned back to the original indentation level + if (openParenCount > 0 && openParenCount === closedParenCount) { + // if we're in a fn definition, make sure we have balanced pairs of parens + break; + } else if (line.trim().endsWith(';')) { + // c-style statement ending + break; + } else if ( // end of a property definition line.trim().endsWith(',') && // including complex types as values openCurlyCount === closedCurlyCount && // but still not before function signatures are closed - openParenCount === closedParenCount - ) { - break; + openParenCount === closedParenCount) { + break; + } } } - } - return {mime, contents: buffer.join('\n'), encoding: 'utf8'}; + return { mime, contents: buffer.join('\n'), encoding: 'utf8' }; + }); + + return function getDefinitionPreview(_x) { + return _ref.apply(this, arguments); + }; +})(); + +var _mimeTypes; + +function _load_mimeTypes() { + return _mimeTypes = _interopRequireDefault(require('mime-types')); +} + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('./fsPromise')); +} + +var _string; + +function _load_string() { + return _string = require('./string'); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('./nuclideUri')); } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const MAX_PREVIEW_LINES = 10; /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +const MAX_FILESIZE = 100000; +const WHITESPACE_REGEX = /^\s*/; +function getIndentLevel(line) { + return WHITESPACE_REGEX.exec(line)[0].length; +} \ No newline at end of file diff --git a/modules/nuclide-commons/test-helpers.js b/modules/nuclide-commons/test-helpers.js index 6136555d..01564594 100644 --- a/modules/nuclide-commons/test-helpers.js +++ b/modules/nuclide-commons/test-helpers.js @@ -1,30 +1,11 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import type {Observable} from 'rxjs'; +'use strict'; -import invariant from 'assert'; -import fs from 'fs'; -import temp from 'temp'; -import uuid from 'uuid'; -import fsPromise from './fsPromise'; -import nuclideUri from './nuclideUri'; -import {asyncLimit} from './promise'; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.generateFixture = exports.expectObservableToStartWith = exports.expectAsyncFailure = undefined; -invariant( - (typeof atom !== 'undefined' && atom.inSpecMode()) || - process.env.NODE_ENV === 'test', - 'Test helpers should only be used in spec mode', -); +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); /** * Verifies that a Promise fails with an Error with specific expectations. When @@ -39,19 +20,20 @@ invariant( * rejection of `promise`. If these expectations are not met, then * `verify()` must throw an exception. */ -export async function expectAsyncFailure( - promise: Promise, - verify: (error: Error) => void, -): Promise { - try { - await promise; - return Promise.reject( - new Error('Promise should have failed, but did not.'), - ); - } catch (e) { - verify(e); - } -} +let expectAsyncFailure = exports.expectAsyncFailure = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (promise, verify) { + try { + yield promise; + return Promise.reject(new Error('Promise should have failed, but did not.')); + } catch (e) { + verify(e); + } + }); + + return function expectAsyncFailure(_x, _x2) { + return _ref.apply(this, arguments); + }; +})(); /** * This is useful for mocking a module that the module under test requires. @@ -62,11 +44,153 @@ export async function expectAsyncFailure( * The require parameter is needed because require is bound differently in each * file, and we need to execute this in the caller's context. */ -export function clearRequireCache(require: Object, module: string): void { + + +/** + * Warning: Callsites *must* await the resulting promise, or test failures may go unreported or + * misattributed. + */ +let expectObservableToStartWith = exports.expectObservableToStartWith = (() => { + var _ref2 = (0, _asyncToGenerator.default)(function* (source, expected) { + const actual = yield source.take(expected.length).toArray().toPromise(); + expect(actual).toEqual(expected); + }); + + return function expectObservableToStartWith(_x3, _x4) { + return _ref2.apply(this, arguments); + }; +})(); + +/** + * Takes of Map of file/file-content pairs, and creates a temp dir that matches + * the file structure of the Map. Example: + * + * generateFixture('myfixture', new Map([ + * ['foo.js'], + * ['bar/baz.txt', 'some text'], + * ])); + * + * Creates: + * + * /tmp/myfixture_1/foo.js (empty file) + * /tmp/myfixture_1/bar/baz.txt (with 'some text') + */ + + +let generateFixture = exports.generateFixture = (() => { + var _ref3 = (0, _asyncToGenerator.default)(function* (fixtureName, files) { + (_temp || _load_temp()).default.track(); + + const MAX_CONCURRENT_FILE_OPS = 100; + const tempDir = yield (_fsPromise || _load_fsPromise()).default.tempdir(fixtureName); + + if (files == null) { + return tempDir; + } + + // Map -> Array with full paths + const fileTuples = Array.from(files, function (tuple) { + // It's our own array - it's ok to mutate it + tuple[0] = (_nuclideUri || _load_nuclideUri()).default.join(tempDir, tuple[0]); + return tuple; + }); + + // Dedupe the dirs that we have to make. + const dirsToMake = fileTuples.map(function ([filename]) { + return (_nuclideUri || _load_nuclideUri()).default.dirname(filename); + }).filter(function (dirname, i, arr) { + return arr.indexOf(dirname) === i; + }); + + yield (0, (_promise || _load_promise()).asyncLimit)(dirsToMake, MAX_CONCURRENT_FILE_OPS, function (dirname) { + return (_fsPromise || _load_fsPromise()).default.mkdirp(dirname); + }); + + yield (0, (_promise || _load_promise()).asyncLimit)(fileTuples, MAX_CONCURRENT_FILE_OPS, function ([filename, contents]) { + // We can't use fsPromise/fs-plus because it does too much extra work. + // They call `mkdirp` before `writeFile`. We know that the target dir + // exists, so we can optimize by going straight to `fs`. When you're + // making 10k files, this adds ~500ms. + return new Promise(function (resolve, reject) { + _fs.default.writeFile(filename, contents || '', function (err) { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + }); + + return tempDir; + }); + + return function generateFixture(_x5, _x6) { + return _ref3.apply(this, arguments); + }; +})(); + +exports.clearRequireCache = clearRequireCache; +exports.uncachedRequire = uncachedRequire; +exports.spyOnGetterValue = spyOnGetterValue; +exports.arePropertiesEqual = arePropertiesEqual; +exports.writeCoverage = writeCoverage; + +var _fs = _interopRequireDefault(require('fs')); + +var _temp; + +function _load_temp() { + return _temp = _interopRequireDefault(require('temp')); +} + +var _uuid; + +function _load_uuid() { + return _uuid = _interopRequireDefault(require('uuid')); +} + +var _fsPromise; + +function _load_fsPromise() { + return _fsPromise = _interopRequireDefault(require('./fsPromise')); +} + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('./nuclideUri')); +} + +var _promise; + +function _load_promise() { + return _promise = require('./promise'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +if (!(typeof atom !== 'undefined' && atom.inSpecMode() || process.env.NODE_ENV === 'test')) { + throw new Error('Test helpers should only be used in spec mode'); +} + +function clearRequireCache(require, module) { delete require.cache[require.resolve(module)]; } -export function uncachedRequire(require: Object, module: string): mixed { +function uncachedRequire(require, module) { clearRequireCache(require, module); // $FlowIgnore return require(module); @@ -83,7 +207,7 @@ export function uncachedRequire(require: Object, module: string): mixed { * - The getter returns a function (otherwise, it doesn't make sense to spy on * it) */ -export function spyOnGetterValue(object: Object, f: string): JasmineSpy { +function spyOnGetterValue(object, f) { const value = object[f]; delete object[f]; object[f] = value; @@ -94,7 +218,7 @@ export function spyOnGetterValue(object: Object, f: string): JasmineSpy { * Checks if the two objects have equal properties. This considers a property * set to undefined to be equivalent to a property that was not set at all. */ -export function arePropertiesEqual(obj1: Object, obj2: Object): boolean { +function arePropertiesEqual(obj1, obj2) { const allProps = new Set(); function addAllProps(obj) { for (const prop of Object.keys(obj)) { @@ -108,98 +232,12 @@ export function arePropertiesEqual(obj1: Object, obj2: Object): boolean { } } return true; -} - -/** - * Warning: Callsites *must* await the resulting promise, or test failures may go unreported or - * misattributed. - */ -export async function expectObservableToStartWith( - source: Observable, - expected: Array, -): Promise { - const actual: Array = await source - .take(expected.length) - .toArray() - .toPromise(); - expect(actual).toEqual(expected); -} - -/** - * Takes of Map of file/file-content pairs, and creates a temp dir that matches - * the file structure of the Map. Example: - * - * generateFixture('myfixture', new Map([ - * ['foo.js'], - * ['bar/baz.txt', 'some text'], - * ])); - * - * Creates: - * - * /tmp/myfixture_1/foo.js (empty file) - * /tmp/myfixture_1/bar/baz.txt (with 'some text') - */ -export async function generateFixture( - fixtureName: string, - files: ?Map, -): Promise { - temp.track(); - - const MAX_CONCURRENT_FILE_OPS = 100; - const tempDir = await fsPromise.tempdir(fixtureName); - - if (files == null) { - return tempDir; - } - - // Map -> Array with full paths - const fileTuples = Array.from(files, tuple => { - // It's our own array - it's ok to mutate it - tuple[0] = nuclideUri.join(tempDir, tuple[0]); - return tuple; - }); - - // Dedupe the dirs that we have to make. - const dirsToMake = fileTuples - .map(([filename]) => nuclideUri.dirname(filename)) - .filter((dirname, i, arr) => arr.indexOf(dirname) === i); - - await asyncLimit(dirsToMake, MAX_CONCURRENT_FILE_OPS, dirname => - fsPromise.mkdirp(dirname), - ); - - await asyncLimit( - fileTuples, - MAX_CONCURRENT_FILE_OPS, - ([filename, contents]) => { - // We can't use fsPromise/fs-plus because it does too much extra work. - // They call `mkdirp` before `writeFile`. We know that the target dir - // exists, so we can optimize by going straight to `fs`. When you're - // making 10k files, this adds ~500ms. - return new Promise((resolve, reject) => { - fs.writeFile(filename, contents || '', err => { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); - }, - ); - - return tempDir; -} - -export function writeCoverage(): void { - const {COVERAGE_DIR} = process.env; +}function writeCoverage() { + const { COVERAGE_DIR } = process.env; if (COVERAGE_DIR != null) { const coverage = global.__coverage__; if (coverage != null) { - fs.writeFileSync( - nuclideUri.join(COVERAGE_DIR, uuid.v4() + '.json'), - JSON.stringify(coverage), - ); + _fs.default.writeFileSync((_nuclideUri || _load_nuclideUri()).default.join(COVERAGE_DIR, (_uuid || _load_uuid()).default.v4() + '.json'), JSON.stringify(coverage)); } } -} +} \ No newline at end of file diff --git a/modules/nuclide-commons/tokenized-text.js b/modules/nuclide-commons/tokenized-text.js index 41b8ced0..055d4ce7 100644 --- a/modules/nuclide-commons/tokenized-text.js +++ b/modules/nuclide-commons/tokenized-text.js @@ -1,69 +1,63 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -export type TokenKind = - | 'keyword' - | 'class-name' - | 'constructor' - | 'method' - | 'param' - | 'string' - | 'whitespace' - | 'plain' - | 'type'; - -export type TextToken = { - kind: TokenKind, - value: string, -}; - -export type TokenizedText = Array; - -export function keyword(value: string): TextToken { +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.keyword = keyword; +exports.className = className; +exports.constructor = constructor; +exports.method = method; +exports.param = param; +exports.string = string; +exports.whitespace = whitespace; +exports.plain = plain; +exports.type = type; +function keyword(value) { return _buildToken('keyword', value); -} - -export function className(value: string): TextToken { +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +function className(value) { return _buildToken('class-name', value); } -export function constructor(value: string): TextToken { +function constructor(value) { return _buildToken('constructor', value); } -export function method(value: string): TextToken { +function method(value) { return _buildToken('method', value); } -export function param(value: string): TextToken { +function param(value) { return _buildToken('param', value); } -export function string(value: string): TextToken { +function string(value) { return _buildToken('string', value); } -export function whitespace(value: string): TextToken { +function whitespace(value) { return _buildToken('whitespace', value); } -export function plain(value: string): TextToken { +function plain(value) { return _buildToken('plain', value); } -export function type(value: string): TextToken { +function type(value) { return _buildToken('type', value); } -function _buildToken(kind: TokenKind, value: string): TextToken { - return {kind, value}; -} +function _buildToken(kind, value) { + return { kind, value }; +} \ No newline at end of file diff --git a/modules/nuclide-commons/which.js b/modules/nuclide-commons/which.js index abd320e7..4ff4b39f 100644 --- a/modules/nuclide-commons/which.js +++ b/modules/nuclide-commons/which.js @@ -1,19 +1,26 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import os from 'os'; -import nuclideUri from './nuclideUri'; +Object.defineProperty(exports, "__esModule", { + value: true +}); -import {runCommand} from './process'; +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _os = _interopRequireDefault(require('os')); + +var _nuclideUri; + +function _load_nuclideUri() { + return _nuclideUri = _interopRequireDefault(require('./nuclideUri')); +} + +var _process; + +function _load_process() { + return _process = require('./process'); +} + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Provides a cross-platform way to check whether a binary is available. @@ -22,23 +29,41 @@ import {runCommand} from './process'; * remember) so we can use this for now. */ -function sanitizePathForWindows(path: string): string { - if (nuclideUri.basename(path) === path) { +function sanitizePathForWindows(path) { + if ((_nuclideUri || _load_nuclideUri()).default.basename(path) === path) { // simple binary in $PATH like `flow` return path; } else { - return `${nuclideUri.dirname(path)}:${nuclideUri.basename(path)}`; + return `${(_nuclideUri || _load_nuclideUri()).default.dirname(path)}:${(_nuclideUri || _load_nuclideUri()).default.basename(path)}`; } -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + +exports.default = (() => { + var _ref = (0, _asyncToGenerator.default)(function* (path) { + const isWindows = process.platform === 'win32'; + const whichCommand = isWindows ? 'where' : 'which'; + const searchPath = isWindows ? sanitizePathForWindows(path) : path; + try { + const result = yield (0, (_process || _load_process()).runCommand)(whichCommand, [searchPath]).toPromise(); + return result.split(_os.default.EOL)[0]; + } catch (e) { + return null; + } + }); -export default (async function which(path: string): Promise { - const isWindows = process.platform === 'win32'; - const whichCommand = isWindows ? 'where' : 'which'; - const searchPath = isWindows ? sanitizePathForWindows(path) : path; - try { - const result = await runCommand(whichCommand, [searchPath]).toPromise(); - return result.split(os.EOL)[0]; - } catch (e) { - return null; + function which(_x) { + return _ref.apply(this, arguments); } -}); + + return which; +})(); \ No newline at end of file diff --git a/modules/nuclide-jasmine/lib/faketimer.js b/modules/nuclide-jasmine/lib/faketimer.js index 0334965f..541a7da2 100644 --- a/modules/nuclide-jasmine/lib/faketimer.js +++ b/modules/nuclide-jasmine/lib/faketimer.js @@ -1,3 +1,5 @@ +'use strict'; + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +8,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -23,7 +25,7 @@ let intervalCount = 0; let timeouts = []; let intervalTimeouts = {}; -function resetTimeouts(): void { +function resetTimeouts() { now = 0; timeoutCount = 0; intervalCount = 0; @@ -31,20 +33,18 @@ function resetTimeouts(): void { intervalTimeouts = {}; } -function fakeSetTimeout(callback: () => ?any, ms: number): number { +function fakeSetTimeout(callback, ms) { const id = ++timeoutCount; timeouts.push([id, now + ms, callback]); - timeouts.sort( - ([, strikeTime0], [, strikeTime1]) => strikeTime0 - strikeTime1, - ); + timeouts.sort(([, strikeTime0], [, strikeTime1]) => strikeTime0 - strikeTime1); return id; } -function fakeClearTimeout(idToClear: number): void { +function fakeClearTimeout(idToClear) { timeouts = timeouts.filter(([id]) => id !== idToClear); } -function fakeSetInterval(callback: () => ?any, ms: number): number { +function fakeSetInterval(callback, ms) { const id = ++intervalCount; const action = () => { callback(); @@ -54,11 +54,11 @@ function fakeSetInterval(callback: () => ?any, ms: number): number { return id; } -function fakeClearInterval(idToClear: number): void { +function fakeClearInterval(idToClear) { fakeClearTimeout(intervalTimeouts[idToClear]); } -function advanceClock(deltaMs: number): void { +function advanceClock(deltaMs) { const advanceTo = now + deltaMs; while (timeouts.length !== 0 && timeouts[0][1] <= advanceTo) { @@ -73,7 +73,7 @@ function advanceClock(deltaMs: number): void { /** * Allows tests to use the non-fake setTimeout and clearTimeout functions. */ -function useRealClock(): void { +function useRealClock() { jasmine.unspy(global, 'setTimeout'); jasmine.unspy(global, 'clearTimeout'); jasmine.unspy(Date, 'now'); @@ -83,7 +83,7 @@ function useRealClock(): void { * Atom does this half-way mock. * https://github.com/atom/atom/blob/v1.12.7/spec/spec-helper.coffee#L169-L174 */ -function useMockClock(): void { +function useMockClock() { spyOn(global, 'setInterval').andCallFake(fakeSetInterval); spyOn(global, 'clearInterval').andCallFake(fakeClearInterval); } @@ -98,7 +98,7 @@ global.advanceClock = advanceClock; jasmine.useRealClock = useRealClock; jasmine.useMockClock = useMockClock; // $FlowIssue: https://github.com/facebook/flow/issues/285 -Object.defineProperty(global, 'now', {get: () => now}); +Object.defineProperty(global, 'now', { get: () => now }); /** * This hook is a the first initialization code that happens before any jasmine test case is @@ -110,4 +110,4 @@ beforeEach(() => { spyOn(Date, 'now').andCallFake(() => now); spyOn(global, 'setTimeout').andCallFake(fakeSetTimeout); spyOn(global, 'clearTimeout').andCallFake(fakeClearTimeout); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-jasmine/lib/focused.js b/modules/nuclide-jasmine/lib/focused.js index 66fd4ce5..c12f1a70 100644 --- a/modules/nuclide-jasmine/lib/focused.js +++ b/modules/nuclide-jasmine/lib/focused.js @@ -1,3 +1,10 @@ +'use strict'; + +// eslint-disable-next-line rulesdir/no-commonjs +require('jasmine-node'); + +// These are undocumented APIs. The type of jasmine is redefined here, so that +// we don't pollute the real lib def with this nonsense. /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +13,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -15,26 +22,7 @@ * https://github.com/atom/jasmine-focused/blob/c922330/src/jasmine-focused.coffee */ -import invariant from 'assert'; - -// eslint-disable-next-line rulesdir/no-commonjs -require('jasmine-node'); - -// These are undocumented APIs. The type of jasmine is redefined here, so that -// we don't pollute the real lib def with this nonsense. -const jasmine: { - getEnv(): { - focusPriority?: number, - specFilter?: (spec: any) => boolean, - }, - Env: { - prototype: { - ddescribe?: () => void, - iit?: () => void, - }, - }, -} = - global.jasmine; +const jasmine = global.jasmine; function setGlobalFocusPriority(priority) { const env = jasmine.getEnv(); @@ -51,7 +39,11 @@ function fdescribe(description, specDefinitions, priority_) { const priority = priority_ != null ? priority_ : 1; setGlobalFocusPriority(priority); const suite = describe(description, specDefinitions); - invariant(suite != null); + + if (!(suite != null)) { + throw new Error('Invariant violation: "suite != null"'); + } + suite.focusPriority = priority; return suite; } @@ -71,7 +63,11 @@ function fit(description, definition, priority_) { const priority = priority_ != null ? priority_ : 1; setGlobalFocusPriority(priority); const spec = it(description, definition); - invariant(spec != null); + + if (!(spec != null)) { + throw new Error('Invariant violation: "spec != null"'); + } + spec.focusPriority = priority; return spec; } @@ -87,7 +83,7 @@ function fffit(description, specDefinitions) { } global.fffit = fffit; -jasmine.getEnv().specFilter = function(spec) { +jasmine.getEnv().specFilter = function (spec) { const env = jasmine.getEnv(); const globalFocusPriority = env.focusPriority; const parent = spec.parentSuite != null ? spec.parentSuite : spec.suite; @@ -99,7 +95,10 @@ jasmine.getEnv().specFilter = function(spec) { } else if (!parent) { return false; } else { - invariant(typeof env.specFilter === 'function'); + if (!(typeof env.specFilter === 'function')) { + throw new Error('Invariant violation: "typeof env.specFilter === \'function\'"'); + } + return env.specFilter(parent); } }; @@ -111,4 +110,4 @@ if (typeof jasmine.Env.prototype.ddescribe === 'function') { if (typeof jasmine.Env.prototype.iit === 'function') { delete jasmine.Env.prototype.iit; -} +} \ No newline at end of file diff --git a/modules/nuclide-jasmine/lib/unspy.js b/modules/nuclide-jasmine/lib/unspy.js index ea251801..ccd0a96d 100644 --- a/modules/nuclide-jasmine/lib/unspy.js +++ b/modules/nuclide-jasmine/lib/unspy.js @@ -1,3 +1,5 @@ +'use strict'; + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +8,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -17,9 +19,9 @@ require('jasmine-node'); * unspy is a ported utility from Atom's `spec-helper.coffee` that restores the * jasmine spied function on an object to its original value. */ -jasmine.unspy = function unspy(object: Object, methodName: string) { +jasmine.unspy = function unspy(object, methodName) { if (!object[methodName].hasOwnProperty('originalValue')) { throw new Error('Not a spy ' + methodName); } object[methodName] = object[methodName].originalValue; -}; +}; \ No newline at end of file diff --git a/modules/nuclide-jasmine/lib/waitsForPromise.js b/modules/nuclide-jasmine/lib/waitsForPromise.js index c6dd0b7d..614a50b9 100644 --- a/modules/nuclide-jasmine/lib/waitsForPromise.js +++ b/modules/nuclide-jasmine/lib/waitsForPromise.js @@ -1,25 +1,10 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ +'use strict'; -import invariant from 'assert'; - -type WaitsForPromiseOptions = { - shouldReject?: boolean, - timeout?: number, -}; - -export default function waitsForPromise( - ...args: Array Promise)> -): void { +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = waitsForPromise; +function waitsForPromise(...args) { let shouldReject; let timeout; if (args.length > 1) { @@ -34,45 +19,41 @@ export default function waitsForPromise( runs(() => { const fn = args[args.length - 1]; - invariant(typeof fn === 'function'); + + if (!(typeof fn === 'function')) { + throw new Error('Invariant violation: "typeof fn === \'function\'"'); + } + const promise = fn(); if (shouldReject) { - promise - .then( - () => { - jasmine - .getEnv() - .currentSpec.fail( - 'Expected promise to be rejected, but it was resolved', - ); - }, - () => { - // Do nothing, it's expected. - }, - ) - .then(() => { - finished = true; - }); + promise.then(() => { + jasmine.getEnv().currentSpec.fail('Expected promise to be rejected, but it was resolved'); + }, () => { + // Do nothing, it's expected. + }).then(() => { + finished = true; + }); } else { - promise - .then( - () => { - // Do nothing, it's expected. - }, - error => { - const text = error ? error.stack || error.toString() : 'undefined'; - jasmine - .getEnv() - .currentSpec.fail( - `Expected promise to be resolved, but it was rejected with ${text}`, - ); - }, - ) - .then(() => { - finished = true; - }); + promise.then(() => { + // Do nothing, it's expected. + }, error => { + const text = error ? error.stack || error.toString() : 'undefined'; + jasmine.getEnv().currentSpec.fail(`Expected promise to be resolved, but it was rejected with ${text}`); + }).then(() => { + finished = true; + }); } }); waitsFor(timeout, () => finished); -} +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ \ No newline at end of file diff --git a/modules/nuclide-jasmine/spec/faketimer-spec.js b/modules/nuclide-jasmine/spec/faketimer-spec.js index 71ba2923..1b91de1b 100644 --- a/modules/nuclide-jasmine/spec/faketimer-spec.js +++ b/modules/nuclide-jasmine/spec/faketimer-spec.js @@ -1,3 +1,5 @@ +'use strict'; + /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,7 +8,7 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ @@ -152,4 +154,4 @@ describe('Fake timer test suite', () => { expect(now2 - now1).toEqual(100); expect(now2).toEqual(global.now); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-jasmine/spec/run-jasmine-tests-spec.js b/modules/nuclide-jasmine/spec/run-jasmine-tests-spec.js index 0a783d36..140a29d3 100644 --- a/modules/nuclide-jasmine/spec/run-jasmine-tests-spec.js +++ b/modules/nuclide-jasmine/spec/run-jasmine-tests-spec.js @@ -1,21 +1,29 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - * @format - */ - -import waitsForPromise from '../lib/waitsForPromise'; - -function testFlowtypedFunction(arg: number): number { - return arg; +'use strict'; + +var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); + +var _waitsForPromise; + +function _load_waitsForPromise() { + return _waitsForPromise = _interopRequireDefault(require('../lib/waitsForPromise')); } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function testFlowtypedFunction(arg) { + return arg; +} /** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + * @format + */ + describe('Jasmine transpile test suite', () => { it('test transpiler worked as exepcted', () => { const promise = Promise.resolve('test'); @@ -34,25 +42,23 @@ describe('Jasmine waitsForPromise test suite', () => { beforeEach(() => jasmine.useRealClock()); it('test waitsForPromise worked as expected on a resolved promise', () => { - waitsForPromise(async () => { + (0, (_waitsForPromise || _load_waitsForPromise()).default)((0, _asyncToGenerator.default)(function* () { const promise = Promise.resolve('test'); - const result = await promise; + const result = yield promise; expect(result).toEqual('test'); - }); + })); }); it('test waitsForPromise worked as expected on a rejected promise', () => { - waitsForPromise({shouldReject: true}, () => - Promise.reject(new Error('test')), - ); + (0, (_waitsForPromise || _load_waitsForPromise()).default)({ shouldReject: true }, () => Promise.reject(new Error('test'))); }); it('test waitsForPromise worked as expected on a customized timeout', () => { // This is more than default timeout of 5 seconds. - waitsForPromise({shouldReject: false, timeout: 7 * 1000}, () => { + (0, (_waitsForPromise || _load_waitsForPromise()).default)({ shouldReject: false, timeout: 7 * 1000 }, () => { return new Promise((resolve, reject) => { setTimeout(resolve, 6 * 1000); }); }); }); -}); +}); \ No newline at end of file diff --git a/modules/nuclide-node-transpiler/spec/fixtures/modern-syntax.js b/modules/nuclide-node-transpiler/spec/fixtures/modern-syntax.js index 6beddeb7..4bfedb4a 100644 --- a/modules/nuclide-node-transpiler/spec/fixtures/modern-syntax.js +++ b/modules/nuclide-node-transpiler/spec/fixtures/modern-syntax.js @@ -1,3 +1,8 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. @@ -6,10 +11,10 @@ * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @flow + * * @format */ -export class Foo { - static bar = 'qux'; -} +class Foo {} +exports.Foo = Foo; +Foo.bar = 'qux'; \ No newline at end of file