From 19c3159cca6eb17f469f2de9e6b84b936dcf5faf Mon Sep 17 00:00:00 2001 From: Mohammad Amin Chitgarha Date: Mon, 18 Jul 2022 23:05:04 +0430 Subject: [PATCH 1/6] Fix max-line ESLint errors (lines exceeding 120 characters) --- lib/ProjectManager.js | 2 +- lib/Refactoring/AbstractProvider.js | 4 +- .../ConstructorGenerationProvider.js | 12 ++-- .../ConstructorGenerationProvider/View.js | 5 +- lib/Refactoring/DocblockProvider.js | 9 ++- lib/Refactoring/ExtractMethodProvider.js | 5 +- .../ExtractMethodProvider/Builder.js | 11 +++- .../ExtractMethodProvider/ParameterParser.js | 18 +++++- lib/Refactoring/ExtractMethodProvider/View.js | 63 +++++++++++++++---- lib/Refactoring/GetterSetterProvider.js | 26 +++++--- lib/Refactoring/GetterSetterProvider/View.js | 5 +- lib/Refactoring/IntroducePropertyProvider.js | 14 ++++- .../OverrideMethodProvider/View.js | 5 +- .../StubAbstractMethodProvider/View.js | 5 +- .../StubInterfaceMethodProvider.js | 5 +- .../StubInterfaceMethodProvider/View.js | 5 +- lib/Refactoring/Utility/MultiSelectionView.js | 8 ++- lib/Refactoring/Utility/TypeHelper.js | 3 +- lib/ServerManager.js | 3 +- 19 files changed, 159 insertions(+), 49 deletions(-) diff --git a/lib/ProjectManager.js b/lib/ProjectManager.js index 096ea3eb..87914f06 100644 --- a/lib/ProjectManager.js +++ b/lib/ProjectManager.js @@ -28,7 +28,7 @@ class ProjectManager // // // Great, URI's are supposed to be file:// + host (optional) + path, which on UNIX systems becomes something // // like file:///my/folder if the host is omitted. Microsoft decided to do it differently and does - // // file:///c:/my/path instead of file://C:/my/path, so add an additional slash and lower case the drive letter. + // // file:///c:/my/path instead of file://C:/my/path, so add an extra slash and lower case the drive letter. // if (process.platform === 'win32') { // mainFolder = '/' + mainFolder.substr(0, 1).toLowerCase() + mainFolder.substr(1); // } diff --git a/lib/Refactoring/AbstractProvider.js b/lib/Refactoring/AbstractProvider.js index 2017cd49..87432e76 100644 --- a/lib/Refactoring/AbstractProvider.js +++ b/lib/Refactoring/AbstractProvider.js @@ -42,8 +42,8 @@ module.exports = this.service = service; const dependentPackage = 'language-php'; - // It could be that the dependent package is already active, in that case we can continue immediately. If not, - // we'll need to wait for the listener to be invoked + // It could be that the dependent package is already active, in that case we can continue immediately. + // If not, we'll need to wait for the listener to be invoked if (atom.packages.isPackageActive(dependentPackage)) { this.doActualInitialization(); } diff --git a/lib/Refactoring/ConstructorGenerationProvider.js b/lib/Refactoring/ConstructorGenerationProvider.js index d9a3d19c..51754b61 100644 --- a/lib/Refactoring/ConstructorGenerationProvider.js +++ b/lib/Refactoring/ConstructorGenerationProvider.js @@ -118,7 +118,10 @@ module.exports = items, tabText, indentationLevel, - atom.config.get('editor.preferredLineLength', editor.getLastCursor().getScopeDescriptor()) + atom.config.get( + 'editor.preferredLineLength', + editor.getLastCursor().getScopeDescriptor() + ) ); }; @@ -126,9 +129,10 @@ module.exports = return localTypesResolvedHandler([]); } else { - // Ensure all types are localized to the use statements of this file, the original types will be - // relative to the original file (which may not be the same). The FQCN works but is long and - // there may be a local use statement that can be used to shorten it. + // Ensure all types are localized to the use statements of this file, the original + // types will be relative to the original file (which may not be the same). + // The FQCN works but is long and there may be a local use statement that can be used + // to shorten it. for (let name in classInfo.properties) { const property = classInfo.properties[name]; items.push({ diff --git a/lib/Refactoring/ConstructorGenerationProvider/View.js b/lib/Refactoring/ConstructorGenerationProvider/View.js index 998effee..c26edfa2 100644 --- a/lib/Refactoring/ConstructorGenerationProvider/View.js +++ b/lib/Refactoring/ConstructorGenerationProvider/View.js @@ -22,7 +22,10 @@ module.exports = return this.div({class: 'checkbox-bar settings-view'}, () => { return this.div({class: 'controls'}, () => { return this.div({class: 'block text-line'}, () => { - return this.label({class: 'icon icon-info'}, 'Tip: The order in which items are selected determines the order of the output.'); + return this.label( + { class: 'icon icon-info' }, + 'Tip: The order in which items are selected determines the order of the output.' + ); }); }); }); diff --git a/lib/Refactoring/DocblockProvider.js b/lib/Refactoring/DocblockProvider.js index 857e4c8c..26fc2a06 100644 --- a/lib/Refactoring/DocblockProvider.js +++ b/lib/Refactoring/DocblockProvider.js @@ -45,7 +45,11 @@ module.exports = */ getIntentionProviders() { return [{ - grammarScopes: ['entity.name.type.class.php', 'entity.name.type.interface.php', 'entity.name.type.trait.php'], + grammarScopes: [ + 'entity.name.type.class.php', + 'entity.name.type.interface.php', + 'entity.name.type.trait.php' + ], getIntentions: ({textEditor, bufferPosition}) => { const nameRange = textEditor.bufferRangeForScopeAtCursor('entity.name.type'); @@ -155,7 +159,8 @@ module.exports = return this.service.getClassInfo(resolvedType).then(nestedSuccessHandler, failureHandler); }; - return this.service.resolveType('file://' + editor.getPath(), triggerPosition, name, 'classlike').then(successHandler, failureHandler); + return this.service.resolveType('file://' + editor.getPath(), triggerPosition, name, 'classlike') + .then(successHandler, failureHandler); } /** diff --git a/lib/Refactoring/ExtractMethodProvider.js b/lib/Refactoring/ExtractMethodProvider.js index d0e78bb5..eb5ee929 100644 --- a/lib/Refactoring/ExtractMethodProvider.js +++ b/lib/Refactoring/ExtractMethodProvider.js @@ -84,7 +84,10 @@ module.exports = const selection = activeTextEditor.getSelectedBufferRange(); // Checking if a selection has been made - if ((selection.start.row === selection.end.row) && (selection.start.column === selection.end.column)) { + if ( + (selection.start.row === selection.end.row) && + (selection.start.column === selection.end.column) + ) { return []; } diff --git a/lib/Refactoring/ExtractMethodProvider/Builder.js b/lib/Refactoring/ExtractMethodProvider/Builder.js index 89dcc736..ccb8847f 100644 --- a/lib/Refactoring/ExtractMethodProvider/Builder.js +++ b/lib/Refactoring/ExtractMethodProvider/Builder.js @@ -169,7 +169,10 @@ module.exports = this.editor = editor; this.setTabText(editor.getTabText()); this.setIndentationLevel(1); - this.setMaxLineLength(atom.config.get('editor.preferredLineLength', editor.getLastCursor().getScopeDescriptor())); + this.setMaxLineLength( + atom.config.get('editor.preferredLineLength', + editor.getLastCursor().getScopeDescriptor()) + ); return this.setSelectedBufferRange(editor.getSelectedBufferRange()); } @@ -294,7 +297,8 @@ module.exports = const failureHandler = () => null; - return this.parameterParser.findParameters(this.editor, this.selectedBufferRange).then(successHandler, failureHandler); + return this.parameterParser.findParameters(this.editor, this.selectedBufferRange) + .then(successHandler, failureHandler); } /** @@ -337,7 +341,8 @@ module.exports = const failureHandler = () => null; - return this.parameterParser.findParameters(this.editor, this.selectedBufferRange).then(successHandler, failureHandler); + return this.parameterParser.findParameters(this.editor, this.selectedBufferRange) + .then(successHandler, failureHandler); } /** diff --git a/lib/Refactoring/ExtractMethodProvider/ParameterParser.js b/lib/Refactoring/ExtractMethodProvider/ParameterParser.js index 57f667bd..b692ff70 100644 --- a/lib/Refactoring/ExtractMethodProvider/ParameterParser.js +++ b/lib/Refactoring/ExtractMethodProvider/ParameterParser.js @@ -198,7 +198,11 @@ module.exports = let childScopes = 0; // First walk back until we find the start of the current scope. - for (({ row } = bufferPosition), asc = bufferPosition.row <= 0; asc ? row <= 0 : row >= 0; asc ? row++ : row--) { + for ( + ({ row } = bufferPosition), asc = bufferPosition.row <= 0; + asc ? row <= 0 : row >= 0; + asc ? row++ : row-- + ) { var asc1; line = editor.lineTextForBufferRow(row); @@ -237,7 +241,11 @@ module.exports = childScopes = 0; // Walk forward until we find the end of the current scope - for (({ row } = startScopePoint), end = editor.getLineCount(), asc2 = startScopePoint.row <= end; asc2 ? row <= end : row >= end; asc2 ? row++ : row--) { + for ( + ({ row } = startScopePoint), end = editor.getLineCount(), asc2 = startScopePoint.row <= end; + asc2 ? row <= end : row >= end; + asc2 ? row++ : row-- + ) { var asc3, end1; line = editor.lineTextForBufferRow(row); @@ -249,7 +257,11 @@ module.exports = startIndex = line.length - 1; } - for (i = startIndex, end1 = line.length - 1, asc3 = startIndex <= end1; asc3 ? i <= end1 : i >= end1; asc3 ? i++ : i--) { + for ( + i = startIndex, end1 = line.length - 1, asc3 = startIndex <= end1; + asc3 ? i <= end1 : i >= end1; + asc3 ? i++ : i-- + ) { descriptions = editor.scopeDescriptorForBufferPosition( [row, i] ); diff --git a/lib/Refactoring/ExtractMethodProvider/View.js b/lib/Refactoring/ExtractMethodProvider/View.js index 2c9f97cf..f14f184c 100644 --- a/lib/Refactoring/ExtractMethodProvider/View.js +++ b/lib/Refactoring/ExtractMethodProvider/View.js @@ -76,15 +76,23 @@ module.exports = static content() { return this.div({class: 'php-ide-serenata-refactoring-extract-method'}, () => { this.div({outlet: 'methodNameForm'}, () => { - this.subview('methodNameEditor', new TextEditorView({mini:true, placeholderText: 'Enter a method name'})); - this.div({class: 'text-error error-message hide error-message--method-name'}, 'You must enter a method name!'); + this.subview('methodNameEditor', new TextEditorView( + { mini: true, placeholderText: 'Enter a method name' } + )); + this.div( + { class: 'text-error error-message hide error-message--method-name' }, + 'You must enter a method name!' + ); return this.div({class: 'settings-view'}, () => { return this.div({class: 'section-body'}, () => { this.div({class: 'control-group'}, () => { return this.div({class: 'controls'}, () => { return this.label({class: 'control-label'}, () => { this.div({class: 'setting-title'}, 'Access Modifier'); - return this.select({outlet: 'accessMethodsInput', class: 'form-control'}, () => { + return this.select({ + outlet: 'accessMethodsInput', + class: 'form-control' + }, () => { this.option({value: 'public'}, 'Public'); this.option({value: 'protected'}, 'Protected'); return this.option({value: 'private', selected: 'selected'}, 'Private'); @@ -98,7 +106,11 @@ module.exports = this.div({class: 'controls'}, () => { return this.div({class: 'checkbox'}, () => { return this.label(() => { - this.input({outlet: 'generateDocInput', type: 'checkbox', checked: true}); + this.input({ + outlet: 'generateDocInput', + type: 'checkbox', + checked: true + }); return this.div({class: 'setting-title'}, 'Generate documentation'); }); }); @@ -106,8 +118,14 @@ module.exports = return this.div({class: 'controls generate-docs-control'}, () => { return this.div({class: 'checkbox'}, () => { return this.label(() => { - this.input({outlet: 'generateDescPlaceholdersInput', type: 'checkbox'}); - return this.div({class: 'setting-title'}, 'Generate description placeholders'); + this.input({ + outlet: 'generateDescPlaceholdersInput', + type: 'checkbox' + }); + return this.div( + { class: 'setting-title' }, + 'Generate description placeholders' + ); }); }); }); @@ -119,7 +137,11 @@ module.exports = return this.div({class: 'controls'}, () => { return this.div({class: 'checkbox'}, () => { return this.label(() => { - this.input({outlet: 'generateTypeHints', type: 'checkbox', checked: true}); + this.input({ + outlet: 'generateTypeHints', + type: 'checkbox', + checked: true + }); return this.div({class: 'setting-title'}, 'Generate type hints'); }); }); @@ -132,8 +154,15 @@ module.exports = return this.div({class: 'controls'}, () => { return this.div({class: 'checkbox'}, () => { return this.label(() => { - this.input({outlet: 'arraySyntax', type: 'checkbox', checked: true}); - return this.div({class: 'setting-title'}, 'Use PHP 5.4 array syntax (square brackets)'); + this.input({ + outlet: 'arraySyntax', + type: 'checkbox', + checked: true + }); + return this.div( + { class: 'setting-title' }, + 'Use PHP 5.4 array syntax (square brackets)' + ); }); }); }); @@ -144,7 +173,11 @@ module.exports = return this.label({class: 'control-label'}, () => { this.div({class: 'setting-title'}, 'Preview'); return this.div({class: 'preview-area'}, () => { - return this.subview('previewArea', new TextEditorView(), {class: 'preview-area'}); + return this.subview( + 'previewArea', + new TextEditorView(), + { class: 'preview-area' } + ); }); }); }); @@ -153,8 +186,14 @@ module.exports = }); }); return this.div({class: 'button-bar'}, () => { - this.button({class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel'}, 'Cancel'); - this.button({class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm'}, 'Extract'); + this.button( + { class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel' }, + 'Cancel' + ); + this.button( + { class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' }, + 'Extract' + ); return this.div({class: 'clear-float'}); }); }); diff --git a/lib/Refactoring/GetterSetterProvider.js b/lib/Refactoring/GetterSetterProvider.js index a1768ca6..862e5b1c 100644 --- a/lib/Refactoring/GetterSetterProvider.js +++ b/lib/Refactoring/GetterSetterProvider.js @@ -70,10 +70,11 @@ module.exports = } ); - return atom.commands.add('atom-workspace', { 'php-ide-serenata-refactoring:generate-getter-setter-pair': () => { - return this.executeCommand(true, true); - } - } + return atom.commands.add( + 'atom-workspace', + { 'php-ide-serenata-refactoring:generate-getter-setter-pair': () => { + return this.executeCommand(true, true); + } } ); } @@ -139,7 +140,10 @@ module.exports = if (!activeTextEditor) { return []; } if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - return this.service.determineCurrentClassName(activeTextEditor, activeTextEditor.getCursorBufferPosition()).then(successHandler, failureHandler); + return this.service.determineCurrentClassName( + activeTextEditor, + activeTextEditor.getCursorBufferPosition() + ).then(successHandler, failureHandler); } }]; } @@ -166,7 +170,9 @@ module.exports = const enabledItems = []; const disabledItems = []; - const indentationLevel = activeTextEditor.indentationForBufferRow(activeTextEditor.getCursorBufferPosition().row); + const indentationLevel = activeTextEditor.indentationForBufferRow( + activeTextEditor.getCursorBufferPosition().row + ); for (let name in classInfo.properties) { const property = classInfo.properties[name]; @@ -185,7 +191,10 @@ module.exports = setterName, tabText : activeTextEditor.getTabText(), indentationLevel, - maxLineLength : atom.config.get('editor.preferredLineLength', activeTextEditor.getLastCursor().getScopeDescriptor()) + maxLineLength : atom.config.get( + 'editor.preferredLineLength', + activeTextEditor.getLastCursor().getScopeDescriptor() + ) }; if ((enableGetterGeneration && enableSetterGeneration && getterExists && setterExists) || @@ -214,7 +223,8 @@ module.exports = return this.getSelectionView().setItems([]); }; - return this.service.determineCurrentClassName(activeTextEditor, activeTextEditor.getCursorBufferPosition()).then(successHandler, failureHandler); + return this.service.determineCurrentClassName(activeTextEditor, activeTextEditor.getCursorBufferPosition()) + .then(successHandler, failureHandler); } /** diff --git a/lib/Refactoring/GetterSetterProvider/View.js b/lib/Refactoring/GetterSetterProvider/View.js index 998effee..c26edfa2 100644 --- a/lib/Refactoring/GetterSetterProvider/View.js +++ b/lib/Refactoring/GetterSetterProvider/View.js @@ -22,7 +22,10 @@ module.exports = return this.div({class: 'checkbox-bar settings-view'}, () => { return this.div({class: 'controls'}, () => { return this.div({class: 'block text-line'}, () => { - return this.label({class: 'icon icon-info'}, 'Tip: The order in which items are selected determines the order of the output.'); + return this.label( + { class: 'icon icon-info' }, + 'Tip: The order in which items are selected determines the order of the output.' + ); }); }); }); diff --git a/lib/Refactoring/IntroducePropertyProvider.js b/lib/Refactoring/IntroducePropertyProvider.js index 170536cf..813e2b9e 100644 --- a/lib/Refactoring/IntroducePropertyProvider.js +++ b/lib/Refactoring/IntroducePropertyProvider.js @@ -137,12 +137,22 @@ module.exports = // Ensure we don't end up somewhere in the middle of the class definition if it spans multiple lines. const lineCount = editor.getLineCount(); - for (let line = (classData.range.start.line + 1), end = lineCount, asc = (classData.range.start.line + 1) <= end; asc ? line <= end : line >= end; asc ? line++ : line--) { + for ( + let line = (classData.range.start.line + 1), + end = lineCount, + asc = (classData.range.start.line + 1) <= end; + asc ? line <= end : line >= end; + asc ? line++ : line-- + ) { const lineText = editor.lineTextForBufferRow(line); if ((lineText == null)) { continue; } - for (let i = 0, end1 = lineText.length - 1, asc1 = 0 <= end1; asc1 ? i <= end1 : i >= end1; asc1 ? i++ : i--) { + for ( + let i = 0, end1 = lineText.length - 1, asc1 = 0 <= end1; + asc1 ? i <= end1 : i >= end1; + asc1 ? i++ : i-- + ) { if (lineText[i] === '{') { startLine = line + 1; break; diff --git a/lib/Refactoring/OverrideMethodProvider/View.js b/lib/Refactoring/OverrideMethodProvider/View.js index 998effee..c26edfa2 100644 --- a/lib/Refactoring/OverrideMethodProvider/View.js +++ b/lib/Refactoring/OverrideMethodProvider/View.js @@ -22,7 +22,10 @@ module.exports = return this.div({class: 'checkbox-bar settings-view'}, () => { return this.div({class: 'controls'}, () => { return this.div({class: 'block text-line'}, () => { - return this.label({class: 'icon icon-info'}, 'Tip: The order in which items are selected determines the order of the output.'); + return this.label( + { class: 'icon icon-info' }, + 'Tip: The order in which items are selected determines the order of the output.' + ); }); }); }); diff --git a/lib/Refactoring/StubAbstractMethodProvider/View.js b/lib/Refactoring/StubAbstractMethodProvider/View.js index 998effee..c26edfa2 100644 --- a/lib/Refactoring/StubAbstractMethodProvider/View.js +++ b/lib/Refactoring/StubAbstractMethodProvider/View.js @@ -22,7 +22,10 @@ module.exports = return this.div({class: 'checkbox-bar settings-view'}, () => { return this.div({class: 'controls'}, () => { return this.div({class: 'block text-line'}, () => { - return this.label({class: 'icon icon-info'}, 'Tip: The order in which items are selected determines the order of the output.'); + return this.label( + { class: 'icon icon-info' }, + 'Tip: The order in which items are selected determines the order of the output.' + ); }); }); }); diff --git a/lib/Refactoring/StubInterfaceMethodProvider.js b/lib/Refactoring/StubInterfaceMethodProvider.js index 6f6ddf93..093f8f4b 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider.js +++ b/lib/Refactoring/StubInterfaceMethodProvider.js @@ -93,7 +93,10 @@ module.exports = method }; - if ((method.declaringStructure.type === 'interface') && ((method.implementations != null ? method.implementations.length : undefined) === 0)) { + if ( + (method.declaringStructure.type === 'interface') && + ((method.implementations != null ? method.implementations.length : undefined) === 0) + ) { items.push(data); } } diff --git a/lib/Refactoring/StubInterfaceMethodProvider/View.js b/lib/Refactoring/StubInterfaceMethodProvider/View.js index 998effee..c26edfa2 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider/View.js +++ b/lib/Refactoring/StubInterfaceMethodProvider/View.js @@ -22,7 +22,10 @@ module.exports = return this.div({class: 'checkbox-bar settings-view'}, () => { return this.div({class: 'controls'}, () => { return this.div({class: 'block text-line'}, () => { - return this.label({class: 'icon icon-info'}, 'Tip: The order in which items are selected determines the order of the output.'); + return this.label( + { class: 'icon icon-info' }, + 'Tip: The order in which items are selected determines the order of the output.' + ); }); }); }); diff --git a/lib/Refactoring/Utility/MultiSelectionView.js b/lib/Refactoring/Utility/MultiSelectionView.js index dfec0674..52693532 100644 --- a/lib/Refactoring/Utility/MultiSelectionView.js +++ b/lib/Refactoring/Utility/MultiSelectionView.js @@ -90,8 +90,12 @@ module.exports = const buttonBar = $$(function() { return this.div({class: 'button-bar'}, () => { - this.button({class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel'}, cancelButtonText); - this.button({class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm'}, confirmButtonText); + this.button({ + class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel' + }, cancelButtonText); + this.button({ + class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' + }, confirmButtonText); return this.div({class: 'clear-float'}); }); }); diff --git a/lib/Refactoring/Utility/TypeHelper.js b/lib/Refactoring/Utility/TypeHelper.js index 2b40cc78..edecea17 100644 --- a/lib/Refactoring/Utility/TypeHelper.js +++ b/lib/Refactoring/Utility/TypeHelper.js @@ -151,8 +151,7 @@ module.exports = * @param {String|null} type * * @return {String|null|false} Null if the type is recognized, but there is no type hint available, false of the - * type is not recognized at all, and the type hint itself if it is recognized and there - * is a type hint. + * type is not recognized at all, and the type hint itself if it is recognized and there is a type hint. */ getScalarTypeHintForDocblockType(type) { if ((type == null)) { return null; } diff --git a/lib/ServerManager.js b/lib/ServerManager.js index 024304fd..82776693 100644 --- a/lib/ServerManager.js +++ b/lib/ServerManager.js @@ -27,7 +27,8 @@ class ServerManager // TODO: Serenata offers PHARs for each PHP version it supports, but for now we can get away with using the // lowest PHP version, as newer versions are backwards compatible enough. await download( - `https://gitlab.com/Serenata/Serenata/-/jobs/${this.distributionJobNumber}/artifacts/raw/bin/distribution.phar`, + `https://gitlab.com/Serenata/Serenata/-/jobs/${this.distributionJobNumber}` + + `/artifacts/raw/bin/distribution.phar`, this.phpInvoker.normalizePlatformAndRuntimePath(this.getServerSourcePath()), { filename: 'distribution.phar', From 2ba970a04956d3025941cc3e9ce8cb08d9299fdd Mon Sep 17 00:00:00 2001 From: Mohammad Amin Chitgarha Date: Tue, 19 Jul 2022 02:19:09 +0430 Subject: [PATCH 2/6] Use normal JS classes instead of using a variable calling a function Blah blah blah... :) Convert using static initClass() to constructor() also. --- lib/Refactoring/AbstractProvider.js | 381 +++++---- .../ConstructorGenerationProvider.js | 477 ++++++------ .../ConstructorGenerationProvider/View.js | 7 +- lib/Refactoring/DocblockProvider.js | 722 +++++++++--------- lib/Refactoring/ExtractMethodProvider.js | 605 ++++++++------- .../ExtractMethodProvider/Builder.js | 697 +++++++++-------- .../ExtractMethodProvider/ParameterParser.js | 667 ++++++++-------- lib/Refactoring/ExtractMethodProvider/View.js | 645 ++++++++-------- lib/Refactoring/GetterSetterProvider.js | 641 ++++++++-------- lib/Refactoring/GetterSetterProvider/View.js | 14 +- lib/Refactoring/IntroducePropertyProvider.js | 239 +++--- lib/Refactoring/OverrideMethodProvider.js | 428 +++++------ .../OverrideMethodProvider/View.js | 12 +- lib/Refactoring/StubAbstractMethodProvider.js | 362 +++++---- .../StubAbstractMethodProvider/View.js | 14 +- .../StubInterfaceMethodProvider.js | 378 +++++---- .../StubInterfaceMethodProvider/View.js | 14 +- lib/Refactoring/Utility/DocblockBuilder.js | 5 +- lib/Refactoring/Utility/FunctionBuilder.js | 696 +++++++++-------- lib/Refactoring/Utility/MultiSelectionView.js | 476 ++++++------ lib/Refactoring/Utility/TypeHelper.js | 383 +++++----- lib/UseStatementHelper.js | 435 ++++++----- 22 files changed, 4061 insertions(+), 4237 deletions(-) diff --git a/lib/Refactoring/AbstractProvider.js b/lib/Refactoring/AbstractProvider.js index 87432e76..14d5004d 100644 --- a/lib/Refactoring/AbstractProvider.js +++ b/lib/Refactoring/AbstractProvider.js @@ -8,114 +8,84 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let AbstractProvider; module.exports = -//#* -// Base class for providers. -//# -(AbstractProvider = (function() { - AbstractProvider = class AbstractProvider { - static initClass() { - /** - * The service (that can be used to query the source code and contains utility methods). - */ - this.prototype.service = null; - - /** - * Service to insert snippets into the editor. - */ - this.prototype.snippetManager = null; - } - +/** + * Base class for providers. + */ +class AbstractProvider { + /** + * Constructor. + */ + constructor() { /** - * Constructor. + * The service (that can be used to query the source code and contains utility methods). */ - constructor() {} + this.service = null; /** - * Initializes this provider. - * - * @param {mixed} service + * Service to insert snippets into the editor. */ - activate(service) { - this.service = service; - const dependentPackage = 'language-php'; - - // It could be that the dependent package is already active, in that case we can continue immediately. - // If not, we'll need to wait for the listener to be invoked - if (atom.packages.isPackageActive(dependentPackage)) { - this.doActualInitialization(); - } - - atom.packages.onDidActivatePackage(packageData => { - if (packageData.name !== dependentPackage) { return; } - - return this.doActualInitialization(); - }); - - return atom.packages.onDidDeactivatePackage(packageData => { - if (packageData.name !== dependentPackage) { return; } - - return this.deactivate(); - }); + this.snippetManager = null; + } + + /** + * Initializes this provider. + * + * @param {mixed} service + */ + activate(service) { + this.service = service; + const dependentPackage = 'language-php'; + + // It could be that the dependent package is already active, in that case we can continue immediately. + // If not, we'll need to wait for the listener to be invoked + if (atom.packages.isPackageActive(dependentPackage)) { + this.doActualInitialization(); } - /** - * Does the actual initialization. - */ - doActualInitialization() { - atom.workspace.observeTextEditors(editor => { - if (/text.html.php$/.test(editor.getGrammar().scopeName)) { - return this.registerEvents(editor); - } - }); + atom.packages.onDidActivatePackage(packageData => { + if (packageData.name !== dependentPackage) { return; } - // When you go back to only have one pane the events are lost, so need to re-register. - atom.workspace.onDidDestroyPane(pane => { - const panes = atom.workspace.getPanes(); + return this.doActualInitialization(); + }); - if (panes.length === 1) { - return this.registerEventsForPane(panes[0]); - } - }); + return atom.packages.onDidDeactivatePackage(packageData => { + if (packageData.name !== dependentPackage) { return; } - // Having to re-register events as when a new pane is created the old panes lose the events. - return atom.workspace.onDidAddPane(observedPane => { - const panes = atom.workspace.getPanes(); + return this.deactivate(); + }); + } - return (() => { - const result = []; + /** + * Does the actual initialization. + */ + doActualInitialization() { + atom.workspace.observeTextEditors(editor => { + if (/text.html.php$/.test(editor.getGrammar().scopeName)) { + return this.registerEvents(editor); + } + }); - for (const pane of panes) { - if (pane !== observedPane) { - result.push(this.registerEventsForPane(pane)); - } else { - result.push(undefined); - } - } + // When you go back to only have one pane the events are lost, so need to re-register. + atom.workspace.onDidDestroyPane(pane => { + const panes = atom.workspace.getPanes(); - return result; - })(); - }); - } + if (panes.length === 1) { + return this.registerEventsForPane(panes[0]); + } + }); + + // Having to re-register events as when a new pane is created the old panes lose the events. + return atom.workspace.onDidAddPane(observedPane => { + const panes = atom.workspace.getPanes(); - /** - * Registers the necessary event handlers for the editors in the specified pane. - * - * @param {Pane} pane - */ - registerEventsForPane(pane) { return (() => { const result = []; - for (const paneItem of pane.items) { - if (atom.workspace.isTextEditor(paneItem)) { - if (/text.html.php$/.test(paneItem.getGrammar().scopeName)) { - result.push(this.registerEvents(paneItem)); - } else { - result.push(undefined); - } + for (const pane of panes) { + if (pane !== observedPane) { + result.push(this.registerEventsForPane(pane)); } else { result.push(undefined); } @@ -123,114 +93,137 @@ module.exports = return result; })(); - } - - /** - * Deactives the provider. - */ - deactivate() {} - - /** - * Retrieves intention providers (by default, the intentions menu shows when the user presses alt-enter). - * - * This method should be overwritten by subclasses. - * - * @return {array} - */ - getIntentionProviders() { - return []; - } - - /** - * Registers the necessary event handlers. - * - * @param {TextEditor} editor TextEditor to register events to. - */ - registerEvents(editor) {} - - /** - * Sets the snippet manager - * - * @param {Object} @snippetManager - */ - setSnippetManager(snippetManager) { - this.snippetManager = snippetManager; - } - - /** - * @return {Number|null} - */ - getCurrentProjectPhpVersion() { - const projectSettings = this.service.getCurrentProjectSettings(); - - if (projectSettings != null) { - return projectSettings.phpVersion; - } - - return null; - } - - /** - * @param {Array} functionParameters - * @param {String} editorUri - * @param {Position} bufferPosition - * - * @return {Array} - */ - async localizeFunctionParameterTypeHints(functionParameters, editorUri, bufferPosition) { - await Promise.all(functionParameters.map(async (parameter) => { - if (!parameter.typeHint) { - return parameter.typeHint; + }); + } + + /** + * Registers the necessary event handlers for the editors in the specified pane. + * + * @param {Pane} pane + */ + registerEventsForPane(pane) { + return (() => { + const result = []; + + for (const paneItem of pane.items) { + if (atom.workspace.isTextEditor(paneItem)) { + if (/text.html.php$/.test(paneItem.getGrammar().scopeName)) { + result.push(this.registerEvents(paneItem)); + } else { + result.push(undefined); + } + } else { + result.push(undefined); } + } - parameter.typeHint = await this.service.localizeType( - editorUri, - bufferPosition, - parameter.typeHint, - 'classlike' - ); - - return parameter; - })); - } - - /** - * @param {Array} functionParameters - * @param {String} editorUri - * @param {Position} bufferPosition - * - * @return {Array} - */ - async localizeFunctionParametersTypes(functionParameters, editorUri, bufferPosition) { - await Promise.all(functionParameters.map(async (parameter) => { - await this.localizeFunctionParameterTypes(parameter, editorUri, bufferPosition); - })); + return result; + })(); + } + + /** + * Deactives the provider. + */ + deactivate() {} + + /** + * Retrieves intention providers (by default, the intentions menu shows when the user presses alt-enter). + * + * This method should be overwritten by subclasses. + * + * @return {array} + */ + getIntentionProviders() { + return []; + } + + /** + * Registers the necessary event handlers. + * + * @param {TextEditor} editor TextEditor to register events to. + */ + registerEvents(editor) {} + + /** + * Sets the snippet manager + * + * @param {Object} @snippetManager + */ + setSnippetManager(snippetManager) { + this.snippetManager = snippetManager; + } + + /** + * @return {Number|null} + */ + getCurrentProjectPhpVersion() { + const projectSettings = this.service.getCurrentProjectSettings(); + + if (projectSettings != null) { + return projectSettings.phpVersion; } - /** - * @param {Object} functionParameter - * @param {String} editorUri - * @param {Position} bufferPosition - * - * @return {Array} - */ - async localizeFunctionParameterTypes(functionParameter, editorUri, bufferPosition, property = 'types') { - await Promise.all(functionParameter[property].map(async (type) => { - if (!type.type) { - return type.type; - } + return null; + } + + /** + * @param {Array} functionParameters + * @param {String} editorUri + * @param {Position} bufferPosition + * + * @return {Array} + */ + async localizeFunctionParameterTypeHints(functionParameters, editorUri, bufferPosition) { + await Promise.all(functionParameters.map(async (parameter) => { + if (!parameter.typeHint) { + return parameter.typeHint; + } - type.type = await this.service.localizeType( - editorUri, - bufferPosition, - type.type, - 'classlike' - ); + parameter.typeHint = await this.service.localizeType( + editorUri, + bufferPosition, + parameter.typeHint, + 'classlike' + ); + + return parameter; + })); + } + + /** + * @param {Array} functionParameters + * @param {String} editorUri + * @param {Position} bufferPosition + * + * @return {Array} + */ + async localizeFunctionParametersTypes(functionParameters, editorUri, bufferPosition) { + await Promise.all(functionParameters.map(async (parameter) => { + await this.localizeFunctionParameterTypes(parameter, editorUri, bufferPosition); + })); + } + + /** + * @param {Object} functionParameter + * @param {String} editorUri + * @param {Position} bufferPosition + * + * @return {Array} + */ + async localizeFunctionParameterTypes(functionParameter, editorUri, bufferPosition, property = 'types') { + await Promise.all(functionParameter[property].map(async (type) => { + if (!type.type) { + return type.type; + } - return type; - })); - } - }; - AbstractProvider.initClass(); - return AbstractProvider; -})()); + type.type = await this.service.localizeType( + editorUri, + bufferPosition, + type.type, + 'classlike' + ); + + return type; + })); + } +}; diff --git a/lib/Refactoring/ConstructorGenerationProvider.js b/lib/Refactoring/ConstructorGenerationProvider.js index 51754b61..963b971b 100644 --- a/lib/Refactoring/ConstructorGenerationProvider.js +++ b/lib/Refactoring/ConstructorGenerationProvider.js @@ -7,279 +7,268 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let DocblockProvider; const {Point} = require('atom'); const AbstractProvider = require('./AbstractProvider'); module.exports = -//#* -// Provides docblock generation and maintenance capabilities. -//# -(DocblockProvider = (function() { - DocblockProvider = class DocblockProvider extends AbstractProvider { - static initClass() { - /** - * The view that allows the user to select the properties to add to the constructor as parameters. - */ - this.prototype.selectionView = null; - - /** - * Aids in building functions. - */ - this.prototype.functionBuilder = null; - - /** - * The docblock builder. - */ - this.prototype.docblockBuilder = null; - - /** - * The type helper. - */ - this.prototype.typeHelper = null; - } +/** + * Provides docblock generation and maintenance capabilities. + */ +class DocblockProvider extends AbstractProvider { + /** + * @param {Object} typeHelper + * @param {Object} functionBuilder + * @param {Object} docblockBuilder + */ + constructor(typeHelper, functionBuilder, docblockBuilder) { + super(); /** - * @param {Object} typeHelper - * @param {Object} functionBuilder - * @param {Object} docblockBuilder + * The view that allows the user to select the properties to add to the constructor as parameters. */ - constructor(typeHelper, functionBuilder, docblockBuilder) { - super(); - - this.typeHelper = typeHelper; - this.functionBuilder = functionBuilder; - this.docblockBuilder = docblockBuilder; - } + this.selectionView = null; /** - * @inheritdoc + * Aids in building functions. */ - deactivate() { - super.deactivate(); - - if (this.selectionView) { - this.selectionView.destroy(); - return this.selectionView = null; - } - } + this.functionBuilder = functionBuilder; /** - * @inheritdoc + * The docblock builder. */ - getIntentionProviders() { - return [{ - grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - - return this.getIntentions(textEditor, bufferPosition); - } - }]; - } + this.docblockBuilder = docblockBuilder; /** - * @param {TextEditor} editor - * @param {Point} triggerPosition + * The type helper. */ - getIntentions(editor, triggerPosition) { - const successHandler = currentClassName => { - if ((currentClassName == null)) { return []; } - - const nestedSuccessHandler = classInfo => { - if ((classInfo == null)) { return []; } - - return [{ - priority : 100, - icon : 'gear', - title : 'Generate Constructor', - - selected : () => { - const items = []; - const promises = []; - - const localTypesResolvedHandler = results => { - let resultIndex = 0; - - for (const item of items) { - for (const type of item.types) { - type.type = results[resultIndex++]; - } + this.typeHelper = typeHelper; + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.selectionView) { + this.selectionView.destroy(); + return this.selectionView = null; + } + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['source.php'], + getIntentions: ({textEditor, bufferPosition}) => { + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + + return this.getIntentions(textEditor, bufferPosition); + } + }]; + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + getIntentions(editor, triggerPosition) { + const successHandler = currentClassName => { + if ((currentClassName == null)) { return []; } + + const nestedSuccessHandler = classInfo => { + if ((classInfo == null)) { return []; } + + return [{ + priority : 100, + icon : 'gear', + title : 'Generate Constructor', + + selected : () => { + const items = []; + const promises = []; + + const localTypesResolvedHandler = results => { + let resultIndex = 0; + + for (const item of items) { + for (const type of item.types) { + type.type = results[resultIndex++]; } + } - const tabText = editor.getTabText(); - const indentationLevel = editor.indentationForBufferRow(triggerPosition.row); - - return this.generateConstructor( - editor, - triggerPosition, - items, - tabText, - indentationLevel, - atom.config.get( - 'editor.preferredLineLength', - editor.getLastCursor().getScopeDescriptor() - ) - ); - }; - - if (classInfo.properties.length === 0) { - return localTypesResolvedHandler([]); - - } else { - // Ensure all types are localized to the use statements of this file, the original - // types will be relative to the original file (which may not be the same). - // The FQCN works but is long and there may be a local use statement that can be used - // to shorten it. - for (let name in classInfo.properties) { - const property = classInfo.properties[name]; - items.push({ - name, - types : property.types - }); - - for (const type of property.types) { - if (this.typeHelper.isClassType(type.type)) { - promises.push(this.service.localizeType( - 'file://' + editor.getPath(), - triggerPosition, - type.type, - 'classlike' - ) - ); - - } else { - promises.push(Promise.resolve(type.type)); - } + const tabText = editor.getTabText(); + const indentationLevel = editor.indentationForBufferRow(triggerPosition.row); + + return this.generateConstructor( + editor, + triggerPosition, + items, + tabText, + indentationLevel, + atom.config.get( + 'editor.preferredLineLength', + editor.getLastCursor().getScopeDescriptor() + ) + ); + }; + + if (classInfo.properties.length === 0) { + return localTypesResolvedHandler([]); + + } else { + // Ensure all types are localized to the use statements of this file, the original + // types will be relative to the original file (which may not be the same). + // The FQCN works but is long and there may be a local use statement that can be used + // to shorten it. + for (let name in classInfo.properties) { + const property = classInfo.properties[name]; + items.push({ + name, + types : property.types + }); + + for (const type of property.types) { + if (this.typeHelper.isClassType(type.type)) { + promises.push(this.service.localizeType( + 'file://' + editor.getPath(), + triggerPosition, + type.type, + 'classlike' + ) + ); + + } else { + promises.push(Promise.resolve(type.type)); } } - - return Promise.all(promises).then(localTypesResolvedHandler, failureHandler); } - } - }]; - }; - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + return Promise.all(promises).then(localTypesResolvedHandler, failureHandler); + } + } + }]; }; - var failureHandler = () => []; - - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + }; + + var failureHandler = () => []; + + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + * @param {Array} items + * @param {String} tabText + * @param {Number} indentationLevel + * @param {Number} maxLineLength + */ + generateConstructor(editor, triggerPosition, items, tabText, indentationLevel, maxLineLength) { + const metadata = { + editor, + position : triggerPosition, + tabText, + indentationLevel, + maxLineLength + }; + + if (items.length > 0) { + this.getSelectionView().setItems(items); + this.getSelectionView().setMetadata(metadata); + this.getSelectionView().storeFocusedElement(); + return this.getSelectionView().present(); + + } else { + return this.onConfirm([], metadata); } - - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - * @param {Array} items - * @param {String} tabText - * @param {Number} indentationLevel - * @param {Number} maxLineLength - */ - generateConstructor(editor, triggerPosition, items, tabText, indentationLevel, maxLineLength) { - const metadata = { - editor, - position : triggerPosition, - tabText, - indentationLevel, - maxLineLength - }; - - if (items.length > 0) { - this.getSelectionView().setItems(items); - this.getSelectionView().setMetadata(metadata); - this.getSelectionView().storeFocusedElement(); - return this.getSelectionView().present(); - - } else { - return this.onConfirm([], metadata); - } + } + + /** + * Called when the selection of properties is cancelled. + * + * @param {Object|null} metadata + */ + onCancel(metadata) {} + + /** + * Called when the selection of properties is confirmed. + * + * @param {Array} selectedItems + * @param {Object|null} metadata + */ + onConfirm(selectedItems, metadata) { + const statements = []; + const parameters = []; + const docblockParameters = []; + + for (const item of selectedItems) { + const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypeArray(item.types); + const parameterTypeHint = this.typeHelper.getTypeHintForTypeSpecification(typeSpecification); + + parameters.push({ + name : `$${item.name}`, + typeHint : parameterTypeHint ? parameterTypeHint.typeHint : null, + defaultValue : parameterTypeHint ? + (parameterTypeHint.shouldSetDefaultValueToNull ? 'null' : null) : + null + }); + + docblockParameters.push({ + name : `$${item.name}`, + type : item.types.length > 0 ? typeSpecification : 'mixed' + }); + + statements.push(`$this->${item.name} = $${item.name};`); } - /** - * Called when the selection of properties is cancelled. - * - * @param {Object|null} metadata - */ - onCancel(metadata) {} - - /** - * Called when the selection of properties is confirmed. - * - * @param {Array} selectedItems - * @param {Object|null} metadata - */ - onConfirm(selectedItems, metadata) { - const statements = []; - const parameters = []; - const docblockParameters = []; - - for (const item of selectedItems) { - const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypeArray(item.types); - const parameterTypeHint = this.typeHelper.getTypeHintForTypeSpecification(typeSpecification); - - parameters.push({ - name : `$${item.name}`, - typeHint : parameterTypeHint ? parameterTypeHint.typeHint : null, - defaultValue : parameterTypeHint ? - (parameterTypeHint.shouldSetDefaultValueToNull ? 'null' : null) : - null - }); - - docblockParameters.push({ - name : `$${item.name}`, - type : item.types.length > 0 ? typeSpecification : 'mixed' - }); - - statements.push(`$this->${item.name} = $${item.name};`); - } - - if (statements.length === 0) { - statements.push(''); - } - - const functionText = this.functionBuilder - .makePublic() - .setIsStatic(false) - .setIsAbstract(false) - .setName('__construct') - .setReturnType(null) - .setParameters(parameters) - .setStatements(statements) - .setTabText(metadata.tabText) - .setIndentationLevel(metadata.indentationLevel) - .setMaxLineLength(metadata.maxLineLength) - .build(); - - const docblockText = this.docblockBuilder.buildForMethod( - docblockParameters, - null, - false, - metadata.tabText.repeat(metadata.indentationLevel) - ); - - const text = docblockText.trimLeft() + functionText; - - return metadata.editor.getBuffer().insert(metadata.position, text); + if (statements.length === 0) { + statements.push(''); } - /** - * @return {Builder} - */ - getSelectionView() { - if ((this.selectionView == null)) { - const View = require('./ConstructorGenerationProvider/View'); - - this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); - this.selectionView.setLoading('Loading class information...'); - this.selectionView.setEmptyMessage('No properties found.'); - } - - return this.selectionView; + const functionText = this.functionBuilder + .makePublic() + .setIsStatic(false) + .setIsAbstract(false) + .setName('__construct') + .setReturnType(null) + .setParameters(parameters) + .setStatements(statements) + .setTabText(metadata.tabText) + .setIndentationLevel(metadata.indentationLevel) + .setMaxLineLength(metadata.maxLineLength) + .build(); + + const docblockText = this.docblockBuilder.buildForMethod( + docblockParameters, + null, + false, + metadata.tabText.repeat(metadata.indentationLevel) + ); + + const text = docblockText.trimLeft() + functionText; + + return metadata.editor.getBuffer().insert(metadata.position, text); + } + + /** + * @return {Builder} + */ + getSelectionView() { + if ((this.selectionView == null)) { + const View = require('./ConstructorGenerationProvider/View'); + + this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); + this.selectionView.setLoading('Loading class information...'); + this.selectionView.setEmptyMessage('No properties found.'); } - }; - DocblockProvider.initClass(); - return DocblockProvider; -})()); + + return this.selectionView; + } +}; diff --git a/lib/Refactoring/ConstructorGenerationProvider/View.js b/lib/Refactoring/ConstructorGenerationProvider/View.js index c26edfa2..b0ebe367 100644 --- a/lib/Refactoring/ConstructorGenerationProvider/View.js +++ b/lib/Refactoring/ConstructorGenerationProvider/View.js @@ -3,8 +3,7 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let View; -const {$, $$, SelectListView} = require('atom-space-pen-views'); +const {$, $$} = require('atom-space-pen-views'); const MultiSelectionView = require('../Utility/MultiSelectionView'); @@ -13,7 +12,7 @@ module.exports = //#* // An extension on SelectListView from atom-space-pen-views that allows multiple selections. //# -(View = class View extends MultiSelectionView { +class View extends MultiSelectionView { /** * @inheritdoc */ @@ -50,4 +49,4 @@ module.exports = return this.onDidConfirm(this.selectedItems, this.getMetadata()); } } -}); +}; diff --git a/lib/Refactoring/DocblockProvider.js b/lib/Refactoring/DocblockProvider.js index 26fc2a06..f1a9f83b 100644 --- a/lib/Refactoring/DocblockProvider.js +++ b/lib/Refactoring/DocblockProvider.js @@ -5,7 +5,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let DocblockProvider; const {Point} = require('atom'); const AbstractProvider = require('./AbstractProvider'); @@ -15,475 +14,466 @@ module.exports = //#* // Provides docblock generation and maintenance capabilities. //# -(DocblockProvider = (function() { - DocblockProvider = class DocblockProvider extends AbstractProvider { - static initClass() { - /** - * The docblock builder. - */ - this.prototype.docblockBuilder = null; - - /** - * The type helper. - */ - this.prototype.typeHelper = null; - } +class DocblockProvider extends AbstractProvider { + /** + * @param {Object} typeHelper + * @param {Object} docblockBuilder + */ + constructor(typeHelper, docblockBuilder) { + super(); /** - * @param {Object} typeHelper - * @param {Object} docblockBuilder + * The docblock builder. */ - constructor(typeHelper, docblockBuilder) { - super(); - - this.typeHelper = typeHelper; - this.docblockBuilder = docblockBuilder; - } + this.docblockBuilder = docblockBuilder; /** - * @inheritdoc + * The type helper. */ - getIntentionProviders() { - return [{ - grammarScopes: [ - 'entity.name.type.class.php', - 'entity.name.type.interface.php', - 'entity.name.type.trait.php' - ], - getIntentions: ({textEditor, bufferPosition}) => { - const nameRange = textEditor.bufferRangeForScopeAtCursor('entity.name.type'); - - if ((nameRange == null)) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - - const name = textEditor.getTextInBufferRange(nameRange); - - return this.getClasslikeIntentions(textEditor, bufferPosition, name); - } - }, { - grammarScopes: ['entity.name.function.php', 'support.function.magic.php'], - getIntentions: ({textEditor, bufferPosition}) => { - let nameRange = textEditor.bufferRangeForScopeAtCursor('entity.name.function.php'); + this.typeHelper = typeHelper; + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: [ + 'entity.name.type.class.php', + 'entity.name.type.interface.php', + 'entity.name.type.trait.php' + ], + getIntentions: ({textEditor, bufferPosition}) => { + const nameRange = textEditor.bufferRangeForScopeAtCursor('entity.name.type'); + + if ((nameRange == null)) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + + const name = textEditor.getTextInBufferRange(nameRange); + + return this.getClasslikeIntentions(textEditor, bufferPosition, name); + } + }, { + grammarScopes: ['entity.name.function.php', 'support.function.magic.php'], + getIntentions: ({textEditor, bufferPosition}) => { + let nameRange = textEditor.bufferRangeForScopeAtCursor('entity.name.function.php'); - if ((nameRange == null)) { - nameRange = textEditor.bufferRangeForScopeAtCursor('support.function.magic.php'); - } + if ((nameRange == null)) { + nameRange = textEditor.bufferRangeForScopeAtCursor('support.function.magic.php'); + } - if ((nameRange == null)) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + if ((nameRange == null)) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - const name = textEditor.getTextInBufferRange(nameRange); + const name = textEditor.getTextInBufferRange(nameRange); - return this.getFunctionlikeIntentions(textEditor, bufferPosition, name); - } - }, { - grammarScopes: ['variable.other.php'], - getIntentions: ({textEditor, bufferPosition}) => { - const nameRange = textEditor.bufferRangeForScopeAtCursor('variable.other.php'); + return this.getFunctionlikeIntentions(textEditor, bufferPosition, name); + } + }, { + grammarScopes: ['variable.other.php'], + getIntentions: ({textEditor, bufferPosition}) => { + const nameRange = textEditor.bufferRangeForScopeAtCursor('variable.other.php'); - if ((nameRange == null)) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + if ((nameRange == null)) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - const name = textEditor.getTextInBufferRange(nameRange); + const name = textEditor.getTextInBufferRange(nameRange); - return this.getPropertyIntentions(textEditor, bufferPosition, name); - } - }, { - grammarScopes: ['constant.other.php'], - getIntentions: ({textEditor, bufferPosition}) => { - const nameRange = textEditor.bufferRangeForScopeAtCursor('constant.other.php'); + return this.getPropertyIntentions(textEditor, bufferPosition, name); + } + }, { + grammarScopes: ['constant.other.php'], + getIntentions: ({textEditor, bufferPosition}) => { + const nameRange = textEditor.bufferRangeForScopeAtCursor('constant.other.php'); - if ((nameRange == null)) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + if ((nameRange == null)) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - const name = textEditor.getTextInBufferRange(nameRange); + const name = textEditor.getTextInBufferRange(nameRange); - return this.getConstantIntentions(textEditor, bufferPosition, name); - } - }]; + return this.getConstantIntentions(textEditor, bufferPosition, name); + } + }]; + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.docblockBuilder) { + //@docblockBuilder.destroy() + return this.docblockBuilder = null; } + } - /** - * @inheritdoc - */ - deactivate() { - super.deactivate(); + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + * @param {String} name + */ + getClasslikeIntentions(editor, triggerPosition, name) { + const failureHandler = () => []; - if (this.docblockBuilder) { - //@docblockBuilder.destroy() - return this.docblockBuilder = null; - } - } + const successHandler = resolvedType => { + const nestedSuccessHandler = classInfo => { + const intentions = []; - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - * @param {String} name - */ - getClasslikeIntentions(editor, triggerPosition, name) { - const failureHandler = () => []; - - const successHandler = resolvedType => { - const nestedSuccessHandler = classInfo => { - const intentions = []; - - if ((classInfo == null)) { return intentions; } - - if (!classInfo.hasDocblock) { - if (classInfo.hasDocumentation) { - intentions.push({ - priority : 100, - icon : 'gear', - title : 'Generate Docblock (inheritDoc)', - - selected : () => { - return this.generateDocblockInheritance(editor, triggerPosition); - } - }); - } + if ((classInfo == null)) { return intentions; } + if (!classInfo.hasDocblock) { + if (classInfo.hasDocumentation) { intentions.push({ priority : 100, icon : 'gear', - title : 'Generate Docblock', + title : 'Generate Docblock (inheritDoc)', selected : () => { - return this.generateClasslikeDocblockFor(editor, classInfo); + return this.generateDocblockInheritance(editor, triggerPosition); } }); } - return intentions; - }; - - return this.service.getClassInfo(resolvedType).then(nestedSuccessHandler, failureHandler); - }; - - return this.service.resolveType('file://' + editor.getPath(), triggerPosition, name, 'classlike') - .then(successHandler, failureHandler); - } - - /** - * @param {TextEditor} editor - * @param {Object} classData - */ - generateClasslikeDocblockFor(editor, classData) { - const zeroBasedStartLine = classData.range.start.line; - - const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); - - const docblock = this.docblockBuilder.buildByLines( - [], - editor.getTabText().repeat(indentationLevel) - ); + intentions.push({ + priority : 100, + icon : 'gear', + title : 'Generate Docblock', - return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); - } + selected : () => { + return this.generateClasslikeDocblockFor(editor, classInfo); + } + }); + } - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - * @param {String} name - */ - getFunctionlikeIntentions(editor, triggerPosition, name) { - const failureHandler = () => { - return []; + return intentions; }; - const successHandler = currentClassName => { - let nestedSuccessHandler; - const helperFunction = functionlikeData => { - const intentions = []; - - if (!functionlikeData) { return intentions; } - - if (!functionlikeData.hasDocblock) { - if (functionlikeData.hasDocumentation) { - intentions.push({ - priority : 100, - icon : 'gear', - title : 'Generate Docblock (inheritDoc)', - - selected : () => { - return this.generateDocblockInheritance(editor, triggerPosition); - } - }); - } - + return this.service.getClassInfo(resolvedType).then(nestedSuccessHandler, failureHandler); + }; + + return this.service.resolveType('file://' + editor.getPath(), triggerPosition, name, 'classlike') + .then(successHandler, failureHandler); + } + + /** + * @param {TextEditor} editor + * @param {Object} classData + */ + generateClasslikeDocblockFor(editor, classData) { + const zeroBasedStartLine = classData.range.start.line; + + const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); + + const docblock = this.docblockBuilder.buildByLines( + [], + editor.getTabText().repeat(indentationLevel) + ); + + return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + * @param {String} name + */ + getFunctionlikeIntentions(editor, triggerPosition, name) { + const failureHandler = () => { + return []; + }; + + const successHandler = currentClassName => { + let nestedSuccessHandler; + const helperFunction = functionlikeData => { + const intentions = []; + + if (!functionlikeData) { return intentions; } + + if (!functionlikeData.hasDocblock) { + if (functionlikeData.hasDocumentation) { intentions.push({ priority : 100, icon : 'gear', - title : 'Generate Docblock', + title : 'Generate Docblock (inheritDoc)', - selected : async () => { - await this.generateFunctionlikeDocblockFor(editor, functionlikeData); + selected : () => { + return this.generateDocblockInheritance(editor, triggerPosition); } }); } - return intentions; - }; + intentions.push({ + priority : 100, + icon : 'gear', + title : 'Generate Docblock', - if (currentClassName) { - nestedSuccessHandler = classInfo => { - if (!(name in classInfo.methods)) { return []; } - return helperFunction(classInfo.methods[name]); - }; + selected : async () => { + await this.generateFunctionlikeDocblockFor(editor, functionlikeData); + } + }); + } - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + return intentions; + }; - } else { - nestedSuccessHandler = globalFunctions => { - if (!(name in globalFunctions)) { return []; } - return helperFunction(globalFunctions[name]); - }; + if (currentClassName) { + nestedSuccessHandler = classInfo => { + if (!(name in classInfo.methods)) { return []; } + return helperFunction(classInfo.methods[name]); + }; - return this.service.getGlobalFunctions().then(nestedSuccessHandler, failureHandler); - } - }; + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } + } else { + nestedSuccessHandler = globalFunctions => { + if (!(name in globalFunctions)) { return []; } + return helperFunction(globalFunctions[name]); + }; - /** - * @param {TextEditor} editor - * @param {Object} data - */ - async generateFunctionlikeDocblockFor(editor, data) { - const zeroBasedStartLine = data.range.start.line; + return this.service.getGlobalFunctions().then(nestedSuccessHandler, failureHandler); + } + }; - await this.localizeFunctionParametersTypes( - data.parameters, - 'file://' + editor.getPath(), - new Point(data.range.start.line, data.range.start.character), - ); + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } - const parameters = await Promise.all(data.parameters.map(async (parameter) => { - let type = 'mixed'; + /** + * @param {TextEditor} editor + * @param {Object} data + */ + async generateFunctionlikeDocblockFor(editor, data) { + const zeroBasedStartLine = data.range.start.line; - if (parameter.types.length > 0) { - type = this.typeHelper.buildTypeSpecificationFromTypeArray(parameter.types); - } + await this.localizeFunctionParametersTypes( + data.parameters, + 'file://' + editor.getPath(), + new Point(data.range.start.line, data.range.start.character), + ); - let name = ''; + const parameters = await Promise.all(data.parameters.map(async (parameter) => { + let type = 'mixed'; - if (parameter.isReference) { - name += '&'; - } + if (parameter.types.length > 0) { + type = this.typeHelper.buildTypeSpecificationFromTypeArray(parameter.types); + } - name += `$${parameter.name}`; + let name = ''; - if (parameter.isVariadic) { - name = `...${name}`; - type += '[]'; - } + if (parameter.isReference) { + name += '&'; + } - return { - name, - type - }; - })); + name += `$${parameter.name}`; - const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); + if (parameter.isVariadic) { + name = `...${name}`; + type += '[]'; + } - let returnType = null; + return { + name, + type + }; + })); - if ((data.returnTypes.length > 0) && (data.name !== '__construct')) { - await this.localizeFunctionParameterTypes( - data, - 'file://' + editor.getPath(), - new Point(data.range.start.line, data.range.start.character), - 'returnTypes' - ); + const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); - returnType = this.typeHelper.buildTypeSpecificationFromTypeArray(data.returnTypes); - } + let returnType = null; - const docblock = this.docblockBuilder.buildForMethod( - parameters, - returnType, - false, - editor.getTabText().repeat(indentationLevel) + if ((data.returnTypes.length > 0) && (data.name !== '__construct')) { + await this.localizeFunctionParameterTypes( + data, + 'file://' + editor.getPath(), + new Point(data.range.start.line, data.range.start.character), + 'returnTypes' ); - return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); + returnType = this.typeHelper.buildTypeSpecificationFromTypeArray(data.returnTypes); } - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - * @param {String} name - */ - getPropertyIntentions(editor, triggerPosition, name) { - const failureHandler = () => { - return []; - }; + const docblock = this.docblockBuilder.buildForMethod( + parameters, + returnType, + false, + editor.getTabText().repeat(indentationLevel) + ); - const successHandler = currentClassName => { - if ((currentClassName == null)) { return []; } + return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); + } - const nestedSuccessHandler = classInfo => { - name = name.substr(1); + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + * @param {String} name + */ + getPropertyIntentions(editor, triggerPosition, name) { + const failureHandler = () => { + return []; + }; - if (!(name in classInfo.properties)) { return []; } + const successHandler = currentClassName => { + if ((currentClassName == null)) { return []; } - const propertyData = classInfo.properties[name]; + const nestedSuccessHandler = classInfo => { + name = name.substr(1); - if ((propertyData == null)) { return; } + if (!(name in classInfo.properties)) { return []; } - const intentions = []; + const propertyData = classInfo.properties[name]; - if (!propertyData) { return intentions; } + if ((propertyData == null)) { return; } - if (!propertyData.hasDocblock) { - if (propertyData.hasDocumentation) { - intentions.push({ - priority : 100, - icon : 'gear', - title : 'Generate Docblock (inheritDoc)', + const intentions = []; - selected : () => { - return this.generateDocblockInheritance(editor, triggerPosition); - } - }); - } + if (!propertyData) { return intentions; } + if (!propertyData.hasDocblock) { + if (propertyData.hasDocumentation) { intentions.push({ priority : 100, icon : 'gear', - title : 'Generate Docblock', + title : 'Generate Docblock (inheritDoc)', selected : () => { - return this.generatePropertyDocblockFor(editor, propertyData); + return this.generateDocblockInheritance(editor, triggerPosition); } }); } - return intentions; - }; + intentions.push({ + priority : 100, + icon : 'gear', + title : 'Generate Docblock', - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); - }; - - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } - - /** - * @param {TextEditor} editor - * @param {Object} data - */ - generatePropertyDocblockFor(editor, data) { - const zeroBasedStartLine = data.range.start.line; - - const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); - - let type = 'mixed'; - - if (data.types.length > 0) { - type = this.typeHelper.buildTypeSpecificationFromTypeArray(data.types); - } - - const docblock = this.docblockBuilder.buildForProperty( - type, - false, - editor.getTabText().repeat(indentationLevel) - ); - - return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); - } + selected : () => { + return this.generatePropertyDocblockFor(editor, propertyData); + } + }); + } - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - * @param {String} name - */ - getConstantIntentions(editor, triggerPosition, name) { - const failureHandler = () => { - return []; + return intentions; }; - const successHandler = currentClassName => { - let nestedSuccessHandler; - const helperFunction = constantData => { - const intentions = []; + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + }; - if (!constantData) { return intentions; } + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } - if (!constantData.hasDocblock) { - intentions.push({ - priority : 100, - icon : 'gear', - title : 'Generate Docblock', + /** + * @param {TextEditor} editor + * @param {Object} data + */ + generatePropertyDocblockFor(editor, data) { + const zeroBasedStartLine = data.range.start.line; - selected : () => { - return this.generateConstantDocblockFor(editor, constantData); - } - }); - } - - return intentions; - }; + const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); - if (currentClassName) { - nestedSuccessHandler = classInfo => { - if (!(name in classInfo.constants)) { return []; } - return helperFunction(classInfo.constants[name]); - }; + let type = 'mixed'; - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); - - } else { - nestedSuccessHandler = globalConstants => { - if (!(name in globalConstants)) { return []; } - return helperFunction(globalConstants[name]); - }; + if (data.types.length > 0) { + type = this.typeHelper.buildTypeSpecificationFromTypeArray(data.types); + } - return this.service.getGlobalConstants().then(nestedSuccessHandler, failureHandler); + const docblock = this.docblockBuilder.buildForProperty( + type, + false, + editor.getTabText().repeat(indentationLevel) + ); + + return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + * @param {String} name + */ + getConstantIntentions(editor, triggerPosition, name) { + const failureHandler = () => { + return []; + }; + + const successHandler = currentClassName => { + let nestedSuccessHandler; + const helperFunction = constantData => { + const intentions = []; + + if (!constantData) { return intentions; } + + if (!constantData.hasDocblock) { + intentions.push({ + priority : 100, + icon : 'gear', + title : 'Generate Docblock', + + selected : () => { + return this.generateConstantDocblockFor(editor, constantData); + } + }); } - }; - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } + return intentions; + }; - /** - * @param {TextEditor} editor - * @param {Object} data - */ - generateConstantDocblockFor(editor, data) { - const zeroBasedStartLine = data.range.start.line; + if (currentClassName) { + nestedSuccessHandler = classInfo => { + if (!(name in classInfo.constants)) { return []; } + return helperFunction(classInfo.constants[name]); + }; - const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); - let type = 'mixed'; + } else { + nestedSuccessHandler = globalConstants => { + if (!(name in globalConstants)) { return []; } + return helperFunction(globalConstants[name]); + }; - if (data.types.length > 0) { - type = this.typeHelper.buildTypeSpecificationFromTypeArray(data.types); + return this.service.getGlobalConstants().then(nestedSuccessHandler, failureHandler); } + }; - const docblock = this.docblockBuilder.buildForProperty( - type, - false, - editor.getTabText().repeat(indentationLevel) - ); + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } - return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); - } + /** + * @param {TextEditor} editor + * @param {Object} data + */ + generateConstantDocblockFor(editor, data) { + const zeroBasedStartLine = data.range.start.line; - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - generateDocblockInheritance(editor, triggerPosition) { - const indentationLevel = editor.indentationForBufferRow(triggerPosition.row); + const indentationLevel = editor.indentationForBufferRow(zeroBasedStartLine); - const docblock = this.docblockBuilder.buildByLines( - ['@inheritDoc'], - editor.getTabText().repeat(indentationLevel) - ); + let type = 'mixed'; - return editor.getBuffer().insert(new Point(triggerPosition.row, -1), docblock); + if (data.types.length > 0) { + type = this.typeHelper.buildTypeSpecificationFromTypeArray(data.types); } - }; - DocblockProvider.initClass(); - return DocblockProvider; -})()); + + const docblock = this.docblockBuilder.buildForProperty( + type, + false, + editor.getTabText().repeat(indentationLevel) + ); + + return editor.getBuffer().insert(new Point(zeroBasedStartLine, -1), docblock); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + generateDocblockInheritance(editor, triggerPosition) { + const indentationLevel = editor.indentationForBufferRow(triggerPosition.row); + + const docblock = this.docblockBuilder.buildByLines( + ['@inheritDoc'], + editor.getTabText().repeat(indentationLevel) + ); + + return editor.getBuffer().insert(new Point(triggerPosition.row, -1), docblock); + } +}; diff --git a/lib/Refactoring/ExtractMethodProvider.js b/lib/Refactoring/ExtractMethodProvider.js index eb5ee929..61255802 100644 --- a/lib/Refactoring/ExtractMethodProvider.js +++ b/lib/Refactoring/ExtractMethodProvider.js @@ -7,7 +7,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let ExtractMethodProvider; const {Range} = require('atom'); const AbstractProvider = require('./AbstractProvider'); @@ -17,379 +16,371 @@ module.exports = //#* // Provides method extraction capabilities. //# -(ExtractMethodProvider = (function() { - ExtractMethodProvider = class ExtractMethodProvider extends AbstractProvider { - static initClass() { - /** - * View that the user interacts with when extracting code. - * - * @type {Object} - */ - this.prototype.view = null; - - /** - * Builder used to generate the new method. - * - * @type {Object} - */ - this.prototype.builder = null; - } +class ExtractMethodProvider extends AbstractProvider { + /** + * @param {Object} builder + */ + constructor(builder) { + super(); /** - * @param {Object} builder + * View that the user interacts with when extracting code. + * + * @type {Object} */ - constructor(builder) { - super(); - - this.builder = builder; - } + this.view = null; /** - * @inheritdoc + * Builder used to generate the new method. + * + * @type {Object} */ - activate(service) { - super.activate(service); + this.builder = builder; + } - return atom.commands.add('atom-text-editor', { 'php-ide-serenata:extract-method': () => { - return this.executeCommand(); - } - } - ); + /** + * @inheritdoc + */ + activate(service) { + super.activate(service); + + return atom.commands.add('atom-text-editor', { 'php-ide-serenata:extract-method': () => { + return this.executeCommand(); + } } + ); + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.view) { + this.view.destroy(); + return this.view = null; + } + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['source.php'], + getIntentions: ({textEditor, bufferPosition}) => { + const activeTextEditor = atom.workspace.getActiveTextEditor(); - /** - * @inheritdoc - */ - deactivate() { - super.deactivate(); + if (!activeTextEditor) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - if (this.view) { - this.view.destroy(); - return this.view = null; - } - } + const selection = activeTextEditor.getSelectedBufferRange(); - /** - * @inheritdoc - */ - getIntentionProviders() { - return [{ - grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { - const activeTextEditor = atom.workspace.getActiveTextEditor(); - - if (!activeTextEditor) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - - const selection = activeTextEditor.getSelectedBufferRange(); - - // Checking if a selection has been made - if ( - (selection.start.row === selection.end.row) && - (selection.start.column === selection.end.column) - ) { - return []; - } + // Checking if a selection has been made + if ( + (selection.start.row === selection.end.row) && + (selection.start.column === selection.end.column) + ) { + return []; + } - return [ - { - priority : 200, - icon : 'git-branch', - title : 'Extract Method', + return [ + { + priority : 200, + icon : 'git-branch', + title : 'Extract Method', - selected : () => { - return this.executeCommand(); - } + selected : () => { + return this.executeCommand(); } - ]; - } - }]; - } + } + ]; + } + }]; + } - /** - * Executes the extraction. - */ - executeCommand() { - const activeTextEditor = atom.workspace.getActiveTextEditor(); + /** + * Executes the extraction. + */ + executeCommand() { + const activeTextEditor = atom.workspace.getActiveTextEditor(); - if (!activeTextEditor) { return; } + if (!activeTextEditor) { return; } - const tabText = activeTextEditor.getTabText(); + const tabText = activeTextEditor.getTabText(); - const selection = activeTextEditor.getSelectedBufferRange(); + const selection = activeTextEditor.getSelectedBufferRange(); - // Checking if a selection has been made - if ((selection.start.row === selection.end.row) && (selection.start.column === selection.end.column)) { - atom.notifications.addInfo('Serenata', { - description: 'Please select the code to extract and try again.' - }); + // Checking if a selection has been made + if ((selection.start.row === selection.end.row) && (selection.start.column === selection.end.column)) { + atom.notifications.addInfo('Serenata', { + description: 'Please select the code to extract and try again.' + }); - return; - } + return; + } - const line = activeTextEditor.lineTextForBufferRow(selection.start.row); + const line = activeTextEditor.lineTextForBufferRow(selection.start.row); - const findSingleTab = new RegExp(`(${tabText})`, 'g'); + const findSingleTab = new RegExp(`(${tabText})`, 'g'); - const matches = (line.match(findSingleTab) || []).length; + const matches = (line.match(findSingleTab) || []).length; - // If the first line doesn't have any tabs then add one. - let highlightedText = activeTextEditor.getTextInBufferRange(selection); - const selectedBufferFirstLine = highlightedText.split('\n')[0]; + // If the first line doesn't have any tabs then add one. + let highlightedText = activeTextEditor.getTextInBufferRange(selection); + const selectedBufferFirstLine = highlightedText.split('\n')[0]; - if ((selectedBufferFirstLine.match(findSingleTab) || []).length === 0) { - highlightedText = `${tabText}` + highlightedText; - } + if ((selectedBufferFirstLine.match(findSingleTab) || []).length === 0) { + highlightedText = `${tabText}` + highlightedText; + } - // Replacing double indents with one, so it can be shown in the preview area of panel. - const multipleTabTexts = Array(matches).fill(`${tabText}`); - const findMultipleTab = new RegExp(`^${multipleTabTexts.join('')}`, 'mg'); - const reducedHighlightedText = highlightedText.replace(findMultipleTab, `${tabText}`); + // Replacing double indents with one, so it can be shown in the preview area of panel. + const multipleTabTexts = Array(matches).fill(`${tabText}`); + const findMultipleTab = new RegExp(`^${multipleTabTexts.join('')}`, 'mg'); + const reducedHighlightedText = highlightedText.replace(findMultipleTab, `${tabText}`); + + this.builder.setEditor(activeTextEditor); + this.builder.setMethodBody(reducedHighlightedText); + + this.getView().storeFocusedElement(); + return this.getView().present(); + } + + /** + * Called when the user has cancel the extraction in the modal. + */ + onCancel() { + return this.builder.cleanUp(); + } + + /** + * Called when the user has confirmed the extraction in the modal. + * + * @param {Object} settings + * + * @see ParameterParser.buildMethod for structure of settings + */ + onConfirm(settings) { + const successHandler = methodCall => { + const activeTextEditor = atom.workspace.getActiveTextEditor(); - this.builder.setEditor(activeTextEditor); - this.builder.setMethodBody(reducedHighlightedText); + const selectedBufferRange = activeTextEditor.getSelectedBufferRange(); - this.getView().storeFocusedElement(); - return this.getView().present(); - } + const highlightedBufferPosition = selectedBufferRange.end; - /** - * Called when the user has cancel the extraction in the modal. - */ - onCancel() { - return this.builder.cleanUp(); - } + let row = 0; - /** - * Called when the user has confirmed the extraction in the modal. - * - * @param {Object} settings - * - * @see ParameterParser.buildMethod for structure of settings - */ - onConfirm(settings) { - const successHandler = methodCall => { - const activeTextEditor = atom.workspace.getActiveTextEditor(); + while (true) { + row++; + const descriptions = activeTextEditor.scopeDescriptorForBufferPosition( + [highlightedBufferPosition.row + row, activeTextEditor.getTabLength()] + ); + const indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.end.php'); + if ((indexOfDescriptor > -1) || (row === activeTextEditor.getLineCount())) { break; } + } - const selectedBufferRange = activeTextEditor.getSelectedBufferRange(); + row = highlightedBufferPosition.row + row; - const highlightedBufferPosition = selectedBufferRange.end; + const line = activeTextEditor.lineTextForBufferRow(row); - let row = 0; + const endOfLine = line != null ? line.length : undefined; - while (true) { - row++; - const descriptions = activeTextEditor.scopeDescriptorForBufferPosition( - [highlightedBufferPosition.row + row, activeTextEditor.getTabLength()] - ); - const indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.end.php'); - if ((indexOfDescriptor > -1) || (row === activeTextEditor.getLineCount())) { break; } - } + let replaceRange = [ + [row, 0], + [row, endOfLine] + ]; - row = highlightedBufferPosition.row + row; + const previousText = activeTextEditor.getTextInBufferRange(replaceRange); - const line = activeTextEditor.lineTextForBufferRow(row); + settings.tabs = true; - const endOfLine = line != null ? line.length : undefined; + const nestedSuccessHandler = newMethodBody => { + settings.tabs = false; - let replaceRange = [ - [row, 0], - [row, endOfLine] - ]; + this.builder.cleanUp(); - const previousText = activeTextEditor.getTextInBufferRange(replaceRange); + return activeTextEditor.transact(() => { + // Matching current indentation + const selectedText = activeTextEditor.getSelectedText(); + let spacing = selectedText.match(/^\s*/); + if (spacing !== null) { + spacing = spacing[0]; + } - settings.tabs = true; + activeTextEditor.insertText(spacing + methodCall); + + // Remove any extra new lines between functions + const nextLine = activeTextEditor.lineTextForBufferRow(row + 1); + if (nextLine === '') { + activeTextEditor.setSelectedBufferRange( + [ + [row + 1, 0], + [row + 1, 1] + ] + ); + activeTextEditor.deleteLine(); + } - const nestedSuccessHandler = newMethodBody => { - settings.tabs = false; - this.builder.cleanUp(); + // Re working out range as inserting method call will delete some + // lines and thus offsetting this + row -= selectedBufferRange.end.row - selectedBufferRange.start.row; - return activeTextEditor.transact(() => { - // Matching current indentation - const selectedText = activeTextEditor.getSelectedText(); - let spacing = selectedText.match(/^\s*/); - if (spacing !== null) { - spacing = spacing[0]; - } + if (this.snippetManager != null) { + activeTextEditor.setCursorBufferPosition([row + 1, 0]); - activeTextEditor.insertText(spacing + methodCall); - - // Remove any extra new lines between functions - const nextLine = activeTextEditor.lineTextForBufferRow(row + 1); - if (nextLine === '') { - activeTextEditor.setSelectedBufferRange( - [ - [row + 1, 0], - [row + 1, 1] - ] - ); - activeTextEditor.deleteLine(); - } + const body = `\n${newMethodBody}`; + const result = this.getTabStopsForBody(body); + const snippet = { + body, + lineCount: result.lineCount, + tabStopList: result.tabStops + }; + + snippet.tabStopList.toArray = () => { + return snippet.tabStopList; + }; + + return this.snippetManager.insertSnippet( + snippet, + activeTextEditor + ); + } else { // Re working out range as inserting method call will delete some // lines and thus offsetting this row -= selectedBufferRange.end.row - selectedBufferRange.start.row; - if (this.snippetManager != null) { - activeTextEditor.setCursorBufferPosition([row + 1, 0]); - - const body = `\n${newMethodBody}`; - - const result = this.getTabStopsForBody(body); - - const snippet = { - body, - lineCount: result.lineCount, - tabStopList: result.tabStops - }; - - snippet.tabStopList.toArray = () => { - return snippet.tabStopList; - }; - - return this.snippetManager.insertSnippet( - snippet, - activeTextEditor - ); - } else { - // Re working out range as inserting method call will delete some - // lines and thus offsetting this - row -= selectedBufferRange.end.row - selectedBufferRange.start.row; - - replaceRange = [ - [row, 0], - [row, (line != null ? line.length : undefined)] - ]; - - return activeTextEditor.setTextInBufferRange( - replaceRange, - `${previousText}\n\n${newMethodBody}` - ); - } - }); - }; - - const nestedFailureHandler = () => { - return settings.tabs = false; - }; + replaceRange = [ + [row, 0], + [row, (line != null ? line.length : undefined)] + ]; - return this.builder.buildMethod(settings).then(nestedSuccessHandler, nestedFailureHandler); + return activeTextEditor.setTextInBufferRange( + replaceRange, + `${previousText}\n\n${newMethodBody}` + ); + } + }); }; - const failureHandler = () => {}; - // Do nothing. - - return this.builder.buildMethodCall(settings.methodName).then(successHandler, failureHandler); - } + const nestedFailureHandler = () => { + return settings.tabs = false; + }; - /** - * Gets all the tab stops and line count for the body given - * - * @param {String} body - * - * @return {Object} - */ - getTabStopsForBody(body) { - const lines = body.split('\n'); - let row = 0; - let lineCount = 0; - let tabStops = []; - const tabStopIndex = {}; - - for (const line of lines) { - var match; - const regex = /(\[[\w ]*?\])(\s*\$[a-zA-Z0-9_]+)?/g; - // Get tab stops by looping through all matches - while ((match = regex.exec(line)) !== null) { - let key = match[2]; // 2nd capturing group (variable name) - const replace = match[1]; // 1st capturing group ([type]) - const range = new Range( - [row, match.index], - [row, match.index + match[1].length] - ); - - if (key !== undefined) { - key = key.trim(); - if (tabStopIndex[key] !== undefined) { - tabStopIndex[key].push(range); - } else { - tabStopIndex[key] = [range]; - } + return this.builder.buildMethod(settings).then(nestedSuccessHandler, nestedFailureHandler); + }; + + const failureHandler = () => {}; + // Do nothing. + + return this.builder.buildMethodCall(settings.methodName).then(successHandler, failureHandler); + } + + /** + * Gets all the tab stops and line count for the body given + * + * @param {String} body + * + * @return {Object} + */ + getTabStopsForBody(body) { + const lines = body.split('\n'); + let row = 0; + let lineCount = 0; + let tabStops = []; + const tabStopIndex = {}; + + for (const line of lines) { + var match; + const regex = /(\[[\w ]*?\])(\s*\$[a-zA-Z0-9_]+)?/g; + // Get tab stops by looping through all matches + while ((match = regex.exec(line)) !== null) { + let key = match[2]; // 2nd capturing group (variable name) + const replace = match[1]; // 1st capturing group ([type]) + const range = new Range( + [row, match.index], + [row, match.index + match[1].length] + ); + + if (key !== undefined) { + key = key.trim(); + if (tabStopIndex[key] !== undefined) { + tabStopIndex[key].push(range); } else { - tabStops.push([range]); + tabStopIndex[key] = [range]; } + } else { + tabStops.push([range]); } - - row++; - lineCount++; - } - - for (const objectKey of Object.keys(tabStopIndex)) { - tabStops.push(tabStopIndex[objectKey]); } - tabStops = tabStops.sort(this.sortTabStops); - - return { - tabStops, - lineCount - }; + row++; + lineCount++; } - /** - * Sorts the tab stops by their row and column - * - * @param {Array} a - * @param {Array} b - * - * @return {Integer} - */ - sortTabStops(a, b) { - // Grabbing first range in the array - a = a[0]; - b = b[0]; - - // b is before a in the rows - if (a.start.row > b.start.row) { - return 1; - } + for (const objectKey of Object.keys(tabStopIndex)) { + tabStops.push(tabStopIndex[objectKey]); + } - // a is before b in the rows - if (a.start.row < b.start.row) { - return -1; - } + tabStops = tabStops.sort(this.sortTabStops); + + return { + tabStops, + lineCount + }; + } + + /** + * Sorts the tab stops by their row and column + * + * @param {Array} a + * @param {Array} b + * + * @return {Integer} + */ + sortTabStops(a, b) { + // Grabbing first range in the array + a = a[0]; + b = b[0]; + + // b is before a in the rows + if (a.start.row > b.start.row) { + return 1; + } - // On same line but b is before a - if (a.start.column > b.start.column) { - return 1; - } + // a is before b in the rows + if (a.start.row < b.start.row) { + return -1; + } - // On same line but a is before b - if (a.start.column < b.start.column) { - return -1; - } + // On same line but b is before a + if (a.start.column > b.start.column) { + return 1; + } - // Same position - return 0; + // On same line but a is before b + if (a.start.column < b.start.column) { + return -1; } - /** - * @return {View} - */ - getView() { - if ((this.view == null)) { - const View = require('./ExtractMethodProvider/View'); + // Same position + return 0; + } - this.view = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); - this.view.setBuilder(this.builder); - } + /** + * @return {View} + */ + getView() { + if ((this.view == null)) { + const View = require('./ExtractMethodProvider/View'); - return this.view; + this.view = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); + this.view.setBuilder(this.builder); } - }; - ExtractMethodProvider.initClass(); - return ExtractMethodProvider; -})()); + + return this.view; + } +}; diff --git a/lib/Refactoring/ExtractMethodProvider/Builder.js b/lib/Refactoring/ExtractMethodProvider/Builder.js index ccb8847f..0d4d7691 100644 --- a/lib/Refactoring/ExtractMethodProvider/Builder.js +++ b/lib/Refactoring/ExtractMethodProvider/Builder.js @@ -7,433 +7,422 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let Builder; const {Range} = require('atom'); module.exports = -(Builder = (function() { - Builder = class Builder { - static initClass() { - /** - * The body of the new method that will be shown in the preview area. - * - * @type {String} - */ - this.prototype.methodBody = ''; - - /** - * The tab string that is used by the current editor. - * - * @type {String} - */ - this.prototype.tabText = ''; - - /** - * @type {Number} - */ - this.prototype.indentationLevel = null; - - /** - * @type {Number} - */ - this.prototype.maxLineLength = null; - - /** - * The php-ide-serenata service. - * - * @type {Service} - */ - this.prototype.service = null; - - /** - * A range of the selected/highlighted area of code to analyse. - * - * @type {Range} - */ - this.prototype.selectedBufferRange = null; - - /** - * The text editor to be analysing. - * - * @type {TextEditor} - */ - this.prototype.editor = null; - - /** - * The parameter parser that will work out the parameters the - * selectedBufferRange will need. - * - * @type {Object} - */ - this.prototype.parameterParser = null; - - /** - * All the variables to return - * - * @type {Array} - */ - this.prototype.returnVariables = null; - - /** - * @type {Object} - */ - this.prototype.docblockBuilder = null; - - /** - * @type {Object} - */ - this.prototype.functionBuilder = null; - - /** - * @type {Object} - */ - this.prototype.typeHelper = null; - } - +class Builder { + /** + * Constructor. + * + * @param {Object} parameterParser + * @param {Object} docblockBuilder + * @param {Object} functionBuilder + * @param {Object} typeHelper + */ + constructor(parameterParser, docblockBuilder, functionBuilder, typeHelper) { /** - * Constructor. + * The body of the new method that will be shown in the preview area. * - * @param {Object} parameterParser - * @param {Object} docblockBuilder - * @param {Object} functionBuilder - * @param {Object} typeHelper + * @type {String} */ - constructor(parameterParser, docblockBuilder, functionBuilder, typeHelper) { - this.setEditor = this.setEditor.bind(this); - this.buildMethod = this.buildMethod.bind(this); - this.buildMethodCall = this.buildMethodCall.bind(this); - this.parameterParser = parameterParser; - this.docblockBuilder = docblockBuilder; - this.functionBuilder = functionBuilder; - this.typeHelper = typeHelper; - } + this.methodBody = ''; /** - * Sets the method body to use in the preview. + * The tab string that is used by the current editor. * - * @param {String} text + * @type {String} */ - setMethodBody(text) { - return this.methodBody = text; - } + this.tabText = ''; /** - * The tab string to use when generating the new method. - * - * @param {String} tab + * @type {Number} */ - setTabText(tab) { - return this.tabText = tab; - } + this.indentationLevel = null; /** - * @param {Number} indentationLevel + * @type {Number} */ - setIndentationLevel(indentationLevel) { - return this.indentationLevel = indentationLevel; - } + this.maxLineLength = null; /** - * @param {Number} maxLineLength + * The php-ide-serenata service. + * + * @type {Service} */ - setMaxLineLength(maxLineLength) { - return this.maxLineLength = maxLineLength; - } + this.service = null; /** - * Set the php-ide-serenata service to be used. + * A range of the selected/highlighted area of code to analyse. * - * @param {Service} service + * @type {Range} */ - setService(service) { - this.service = service; - return this.parameterParser.setService(service); - } + this.selectedBufferRange = null; /** - * Set the selectedBufferRange to analyse. + * The text editor to be analysing. * - * @param {Range} range [description] + * @type {TextEditor} */ - setSelectedBufferRange(range) { - return this.selectedBufferRange = range; - } + this.editor = null; /** - * Set the TextEditor to be used when analysing the selectedBufferRange + * The parameter parser that will work out the parameters the + * selectedBufferRange will need. * - * @param {TextEditor} editor [description] + * @type {Object} */ - setEditor(editor) { - this.editor = editor; - this.setTabText(editor.getTabText()); - this.setIndentationLevel(1); - this.setMaxLineLength( - atom.config.get('editor.preferredLineLength', - editor.getLastCursor().getScopeDescriptor()) - ); - return this.setSelectedBufferRange(editor.getSelectedBufferRange()); - } + this.parameterParser = parameterParser; /** - * Builds the new method from the selectedBufferRange and settings given. - * - * The settings parameter should be an object with these properties: - * - methodName (string) - * - visibility (string) ['private', 'protected', 'public'] - * - tabs (boolean) - * - generateDocs (boolean) - * - arraySyntax (string) ['word', 'brackets'] - * - generateDocPlaceholders (boolean) - * - * @param {Object} settings + * All the variables to return * - * @return {Promise} + * @type {Array} */ - buildMethod(settings) { - const successHandler = parameters => { - if (this.returnVariables === null) { - this.returnVariables = this.workOutReturnVariables(this.parameterParser.getVariableDeclarations()); - } - - const tabText = settings.tabs ? this.tabText : ''; - const totalIndentation = tabText.repeat(this.indentationLevel); - - const statements = []; + this.returnVariables = null; - for (const statement of this.methodBody.split('\n')) { - const newStatement = statement.substr(totalIndentation.length); - - statements.push(newStatement); - } - - let returnTypeHintSpecification = 'void'; - let returnStatement = this.buildReturnStatement(this.returnVariables, settings.arraySyntax); - - if (returnStatement != null) { - if (this.returnVariables.length === 1) { - returnTypeHintSpecification = this.returnVariables[0].types.join('|'); - - } else { - returnTypeHintSpecification = 'array'; - } - - returnStatement = returnStatement.substr(totalIndentation.length); - - statements.push(''); - statements.push(returnStatement); - } + /** + * @type {Object} + */ + this.docblockBuilder = docblockBuilder; - const functionParameters = parameters.map(parameter => { - const typeHintInfo = this.typeHelper.getTypeHintForDocblockTypes(parameter.types); + /** + * @type {Object} + */ + this.functionBuilder = functionBuilder; - return { - name : parameter.name, - typeHint : (typeHintInfo != null) && settings.typeHinting ? typeHintInfo.typeHint : null, - defaultValue : (typeHintInfo != null) && typeHintInfo.isNullable ? 'null' : null - }; - }); + /** + * @type {Object} + */ + this.typeHelper = typeHelper; + + this.setEditor = this.setEditor.bind(this); + this.buildMethod = this.buildMethod.bind(this); + this.buildMethodCall = this.buildMethodCall.bind(this); + } + + /** + * Sets the method body to use in the preview. + * + * @param {String} text + */ + setMethodBody(text) { + return this.methodBody = text; + } + + /** + * The tab string to use when generating the new method. + * + * @param {String} tab + */ + setTabText(tab) { + return this.tabText = tab; + } + + /** + * @param {Number} indentationLevel + */ + setIndentationLevel(indentationLevel) { + return this.indentationLevel = indentationLevel; + } + + /** + * @param {Number} maxLineLength + */ + setMaxLineLength(maxLineLength) { + return this.maxLineLength = maxLineLength; + } + + /** + * Set the php-ide-serenata service to be used. + * + * @param {Service} service + */ + setService(service) { + this.service = service; + return this.parameterParser.setService(service); + } + + /** + * Set the selectedBufferRange to analyse. + * + * @param {Range} range [description] + */ + setSelectedBufferRange(range) { + return this.selectedBufferRange = range; + } + + /** + * Set the TextEditor to be used when analysing the selectedBufferRange + * + * @param {TextEditor} editor [description] + */ + setEditor(editor) { + this.editor = editor; + this.setTabText(editor.getTabText()); + this.setIndentationLevel(1); + this.setMaxLineLength( + atom.config.get('editor.preferredLineLength', + editor.getLastCursor().getScopeDescriptor()) + ); + return this.setSelectedBufferRange(editor.getSelectedBufferRange()); + } + + /** + * Builds the new method from the selectedBufferRange and settings given. + * + * The settings parameter should be an object with these properties: + * - methodName (string) + * - visibility (string) ['private', 'protected', 'public'] + * - tabs (boolean) + * - generateDocs (boolean) + * - arraySyntax (string) ['word', 'brackets'] + * - generateDocPlaceholders (boolean) + * + * @param {Object} settings + * + * @return {Promise} + */ + buildMethod(settings) { + const successHandler = parameters => { + if (this.returnVariables === null) { + this.returnVariables = this.workOutReturnVariables(this.parameterParser.getVariableDeclarations()); + } - const docblockParameters = parameters.map(parameter => { - const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypes(parameter.types); + const tabText = settings.tabs ? this.tabText : ''; + const totalIndentation = tabText.repeat(this.indentationLevel); - return { - name : parameter.name, - type : typeSpecification.length > 0 ? typeSpecification : '[type]' - }; - }); + const statements = []; - this.functionBuilder - .setIsStatic(false) - .setIsAbstract(false) - .setName(settings.methodName) - .setReturnType(this.typeHelper.getReturnTypeHintForTypeSpecification(returnTypeHintSpecification)) - .setParameters(functionParameters) - .setStatements(statements) - .setIndentationLevel(this.indentationLevel) - .setTabText(tabText) - .setMaxLineLength(this.maxLineLength); + for (const statement of this.methodBody.split('\n')) { + const newStatement = statement.substr(totalIndentation.length); - if (settings.visibility === 'public') { - this.functionBuilder.makePublic(); + statements.push(newStatement); + } - } else if (settings.visibility === 'protected') { - this.functionBuilder.makeProtected(); + let returnTypeHintSpecification = 'void'; + let returnStatement = this.buildReturnStatement(this.returnVariables, settings.arraySyntax); - } else if (settings.visibility === 'private') { - this.functionBuilder.makePrivate(); + if (returnStatement != null) { + if (this.returnVariables.length === 1) { + returnTypeHintSpecification = this.returnVariables[0].types.join('|'); } else { - this.functionBuilder.makeGlobal(); + returnTypeHintSpecification = 'array'; } - let docblockText = ''; + returnStatement = returnStatement.substr(totalIndentation.length); - if (settings.generateDocs) { - let returnType = 'void'; + statements.push(''); + statements.push(returnStatement); + } - if ((this.returnVariables !== null) && (this.returnVariables.length > 0)) { - returnType = '[type]'; + const functionParameters = parameters.map(parameter => { + const typeHintInfo = this.typeHelper.getTypeHintForDocblockTypes(parameter.types); - if (this.returnVariables.length > 1) { - returnType = 'array'; + return { + name : parameter.name, + typeHint : (typeHintInfo != null) && settings.typeHinting ? typeHintInfo.typeHint : null, + defaultValue : (typeHintInfo != null) && typeHintInfo.isNullable ? 'null' : null + }; + }); - } else if ((this.returnVariables.length === 1) && (this.returnVariables[0].types.length > 0)) { - returnType = this.typeHelper.buildTypeSpecificationFromTypes(this.returnVariables[0].types); - } - } + const docblockParameters = parameters.map(parameter => { + const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypes(parameter.types); - docblockText = this.docblockBuilder.buildForMethod( - docblockParameters, - returnType, - settings.generateDescPlaceholders, - totalIndentation - ); - } + return { + name : parameter.name, + type : typeSpecification.length > 0 ? typeSpecification : '[type]' + }; + }); - return docblockText + this.functionBuilder.build(); - }; + this.functionBuilder + .setIsStatic(false) + .setIsAbstract(false) + .setName(settings.methodName) + .setReturnType(this.typeHelper.getReturnTypeHintForTypeSpecification(returnTypeHintSpecification)) + .setParameters(functionParameters) + .setStatements(statements) + .setIndentationLevel(this.indentationLevel) + .setTabText(tabText) + .setMaxLineLength(this.maxLineLength); - const failureHandler = () => null; + if (settings.visibility === 'public') { + this.functionBuilder.makePublic(); - return this.parameterParser.findParameters(this.editor, this.selectedBufferRange) - .then(successHandler, failureHandler); - } + } else if (settings.visibility === 'protected') { + this.functionBuilder.makeProtected(); - /** - * Build the line that calls the new method and the variable the method - * to be assigned to. - * - * @param {String} methodName - * @param {String} variable [Optional] - * - * @return {Promise} - */ - buildMethodCall(methodName, variable) { - const successHandler = parameters => { - const parameterNames = parameters.map(item => item.name); + } else if (settings.visibility === 'private') { + this.functionBuilder.makePrivate(); - let methodCall = `$this->${methodName}(${parameterNames.join(', ')});`; + } else { + this.functionBuilder.makeGlobal(); + } - if (variable !== undefined) { - methodCall = `$${variable} = ${methodCall}`; - } else { - if (this.returnVariables !== null) { - if (this.returnVariables.length === 1) { - methodCall = `${this.returnVariables[0].name} = ${methodCall}`; - } else if (this.returnVariables.length > 1) { - const variables = this.returnVariables.reduce(function(previous, current) { - if (typeof previous !== 'string') { - previous = previous.name; - } - - return previous + ', ' + current.name; - }); - - methodCall = `list(${variables}) = ${methodCall}`; - } - } - } + let docblockText = ''; - return methodCall; - }; + if (settings.generateDocs) { + let returnType = 'void'; - const failureHandler = () => null; + if ((this.returnVariables !== null) && (this.returnVariables.length > 0)) { + returnType = '[type]'; - return this.parameterParser.findParameters(this.editor, this.selectedBufferRange) - .then(successHandler, failureHandler); - } + if (this.returnVariables.length > 1) { + returnType = 'array'; - /** - * Performs any clean up needed with the builder. - */ - cleanUp() { - this.returnVariables = null; - return this.parameterParser.cleanUp(); - } + } else if ((this.returnVariables.length === 1) && (this.returnVariables[0].types.length > 0)) { + returnType = this.typeHelper.buildTypeSpecificationFromTypes(this.returnVariables[0].types); + } + } - /** - * Works out which variables need to be returned from the new method. - * - * @param {Array} variableDeclarations - * - * @return {Array} - */ - workOutReturnVariables(variableDeclarations) { - const startPoint = this.selectedBufferRange.end; - const scopeRange = this.parameterParser.getRangeForCurrentScope(this.editor, startPoint); + docblockText = this.docblockBuilder.buildForMethod( + docblockParameters, + returnType, + settings.generateDescPlaceholders, + totalIndentation + ); + } - const lookupRange = new Range(startPoint, scopeRange.end); + return docblockText + this.functionBuilder.build(); + }; + + const failureHandler = () => null; + + return this.parameterParser.findParameters(this.editor, this.selectedBufferRange) + .then(successHandler, failureHandler); + } + + /** + * Build the line that calls the new method and the variable the method + * to be assigned to. + * + * @param {String} methodName + * @param {String} variable [Optional] + * + * @return {Promise} + */ + buildMethodCall(methodName, variable) { + const successHandler = parameters => { + const parameterNames = parameters.map(item => item.name); + + let methodCall = `$this->${methodName}(${parameterNames.join(', ')});`; + + if (variable !== undefined) { + methodCall = `$${variable} = ${methodCall}`; + } else { + if (this.returnVariables !== null) { + if (this.returnVariables.length === 1) { + methodCall = `${this.returnVariables[0].name} = ${methodCall}`; + } else if (this.returnVariables.length > 1) { + const variables = this.returnVariables.reduce(function(previous, current) { + if (typeof previous !== 'string') { + previous = previous.name; + } - const textAfterExtraction = this.editor.getTextInBufferRange(lookupRange); - const allVariablesAfterExtraction = textAfterExtraction.match(/\$[a-zA-Z0-9]+/g); + return previous + ', ' + current.name; + }); - if (allVariablesAfterExtraction === null) { return null; } + methodCall = `list(${variables}) = ${methodCall}`; + } + } + } - variableDeclarations = variableDeclarations.filter(variable => { - if (allVariablesAfterExtraction.includes(variable.name)) { return true; } - return false; - }); + return methodCall; + }; + + const failureHandler = () => null; + + return this.parameterParser.findParameters(this.editor, this.selectedBufferRange) + .then(successHandler, failureHandler); + } + + /** + * Performs any clean up needed with the builder. + */ + cleanUp() { + this.returnVariables = null; + return this.parameterParser.cleanUp(); + } + + /** + * Works out which variables need to be returned from the new method. + * + * @param {Array} variableDeclarations + * + * @return {Array} + */ + workOutReturnVariables(variableDeclarations) { + const startPoint = this.selectedBufferRange.end; + const scopeRange = this.parameterParser.getRangeForCurrentScope(this.editor, startPoint); + + const lookupRange = new Range(startPoint, scopeRange.end); + + const textAfterExtraction = this.editor.getTextInBufferRange(lookupRange); + const allVariablesAfterExtraction = textAfterExtraction.match(/\$[a-zA-Z0-9]+/g); + + if (allVariablesAfterExtraction === null) { return null; } + + variableDeclarations = variableDeclarations.filter(variable => { + if (allVariablesAfterExtraction.includes(variable.name)) { return true; } + return false; + }); + + return variableDeclarations; + } + + /** + * Builds the return statement for the new method. + * + * @param {Array} variableDeclarations + * @param {String} arrayType ['word', 'brackets'] + * + * @return {String|null} + */ + buildReturnStatement(variableDeclarations, arrayType) { + if (arrayType == null) { arrayType = 'word'; } + if (variableDeclarations != null) { + if (variableDeclarations.length === 1) { + return `${this.tabText}return ${variableDeclarations[0].name};`; + + } else if (variableDeclarations.length > 1) { + let variables = variableDeclarations.reduce(function(previous, current) { + if (typeof previous !== 'string') { + previous = previous.name; + } - return variableDeclarations; - } + return previous + ', ' + current.name; + }); - /** - * Builds the return statement for the new method. - * - * @param {Array} variableDeclarations - * @param {String} arrayType ['word', 'brackets'] - * - * @return {String|null} - */ - buildReturnStatement(variableDeclarations, arrayType) { - if (arrayType == null) { arrayType = 'word'; } - if (variableDeclarations != null) { - if (variableDeclarations.length === 1) { - return `${this.tabText}return ${variableDeclarations[0].name};`; - - } else if (variableDeclarations.length > 1) { - let variables = variableDeclarations.reduce(function(previous, current) { - if (typeof previous !== 'string') { - previous = previous.name; - } - - return previous + ', ' + current.name; - }); - - if (arrayType === 'brackets') { - variables = `[${variables}]`; - - } else { - variables = `array(${variables})`; - } + if (arrayType === 'brackets') { + variables = `[${variables}]`; - return `${this.tabText}return ${variables};`; + } else { + variables = `array(${variables})`; } - } - - return null; - } - /** - * Checks if the new method will be returning any values. - * - * @return {Boolean} - */ - hasReturnValues() { - return (this.returnVariables !== null) && (this.returnVariables.length > 0); + return `${this.tabText}return ${variables};`; + } } - /** - * Returns if there are multiple return values. - * - * @return {Boolean} - */ - hasMultipleReturnValues() { - return (this.returnVariables !== null) && (this.returnVariables.length > 1); - } - }; - Builder.initClass(); - return Builder; -})()); + return null; + } + + /** + * Checks if the new method will be returning any values. + * + * @return {Boolean} + */ + hasReturnValues() { + return (this.returnVariables !== null) && (this.returnVariables.length > 0); + } + + /** + * Returns if there are multiple return values. + * + * @return {Boolean} + */ + hasMultipleReturnValues() { + return (this.returnVariables !== null) && (this.returnVariables.length > 1); + } +}; diff --git a/lib/Refactoring/ExtractMethodProvider/ParameterParser.js b/lib/Refactoring/ExtractMethodProvider/ParameterParser.js index b692ff70..7d429b46 100644 --- a/lib/Refactoring/ExtractMethodProvider/ParameterParser.js +++ b/lib/Refactoring/ExtractMethodProvider/ParameterParser.js @@ -6,401 +6,392 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let ParameterParser; const {Point, Range} = require('atom'); module.exports = -(ParameterParser = (function() { - ParameterParser = class ParameterParser { - static initClass() { - /** - * Service object from the php-ide-serenata service - * - * @type {Service} - */ - this.prototype.service = null; - - /** - * @type {Object} - */ - this.prototype.typeHelper = null; - - /** - * List of all the variable declarations that have been process - * - * @type {Array} - */ - this.prototype.variableDeclarations = []; - - /** - * The selected range that we are scanning for parameters in. - * - * @type {Range} - */ - this.prototype.selectedBufferRange = null; - } - +class ParameterParser { + /** + * Constructor + * + * @param {Object} typeHelper + */ + constructor(typeHelper) { /** - * Constructor + * Service object from the php-ide-serenata service * - * @param {Object} typeHelper + * @type {Service} */ - constructor(typeHelper) { - this.typeHelper = typeHelper; - } + this.service = null; /** - * @param {Object} service + * @type {Object} */ - setService(service) { - this.service = service; - } + this.typeHelper = typeHelper; /** - * Takes the editor and the range and loops through finding all the - * parameters that will be needed if this code was to be moved into - * its own function + * List of all the variable declarations that have been process * - * @param {TextEditor} editor - * @param {Range} selectedBufferRange - * - * @return {Promise} + * @type {Array} */ - findParameters(editor, selectedBufferRange) { - this.selectedBufferRange = selectedBufferRange; - - let parameters = []; + this.variableDeclarations = []; - editor.scanInBufferRange(/\$[a-zA-Z0-9_]+/g, selectedBufferRange, element => { - // Making sure we matched a variable and not a variable within a string - const descriptions = editor.scopeDescriptorForBufferPosition(element.range.start); - const indexOfDescriptor = descriptions.scopes.indexOf('variable.other.php'); - if (indexOfDescriptor > -1) { - return parameters.push({ - name: element.matchText, - range: element.range - }); - } - }); - - const regexFilters = [ - { - name: 'Foreach loops', - regex: /as\s(\$[a-zA-Z0-9_]+)(?:\s=>\s(\$[a-zA-Z0-9_]+))?/g - }, - { - name: 'For loops', - regex: /for\s*\(\s*(\$[a-zA-Z0-9_]+)\s*=/g - }, - { - name: 'Try catch', - regex: /catch(?:\(|\s)+.*?(\$[a-zA-Z0-9_]+)/g - }, - { - name: 'Closure', - regex: /function(?:\s)*?\((?:\$).*?\)/g - }, - { - name: 'Variable declarations', - regex: /(\$[a-zA-Z0-9]+)\s*?=(?!>|=)/g - } - ]; - - const getTypePromises = []; - const variableDeclarations = []; - - for (const filter of regexFilters) { - editor.backwardsScanInBufferRange(filter.regex, selectedBufferRange, element => { - const variables = element.matchText.match(/\$[a-zA-Z0-9]+/g); - const startPoint = new Point(element.range.end.row, 0); - const scopeRange = this.getRangeForCurrentScope(editor, startPoint); - - if (filter.name === 'Variable declarations') { - let chosenParameter = null; - for (const parameter of parameters) { - if (element.range.containsRange(parameter.range)) { - chosenParameter = parameter; - break; - } + /** + * The selected range that we are scanning for parameters in. + * + * @type {Range} + */ + this.selectedBufferRange = null; + } + + /** + * @param {Object} service + */ + setService(service) { + this.service = service; + } + + /** + * Takes the editor and the range and loops through finding all the + * parameters that will be needed if this code was to be moved into + * its own function + * + * @param {TextEditor} editor + * @param {Range} selectedBufferRange + * + * @return {Promise} + */ + findParameters(editor, selectedBufferRange) { + this.selectedBufferRange = selectedBufferRange; + + let parameters = []; + + editor.scanInBufferRange(/\$[a-zA-Z0-9_]+/g, selectedBufferRange, element => { + // Making sure we matched a variable and not a variable within a string + const descriptions = editor.scopeDescriptorForBufferPosition(element.range.start); + const indexOfDescriptor = descriptions.scopes.indexOf('variable.other.php'); + if (indexOfDescriptor > -1) { + return parameters.push({ + name: element.matchText, + range: element.range + }); + } + }); + + const regexFilters = [ + { + name: 'Foreach loops', + regex: /as\s(\$[a-zA-Z0-9_]+)(?:\s=>\s(\$[a-zA-Z0-9_]+))?/g + }, + { + name: 'For loops', + regex: /for\s*\(\s*(\$[a-zA-Z0-9_]+)\s*=/g + }, + { + name: 'Try catch', + regex: /catch(?:\(|\s)+.*?(\$[a-zA-Z0-9_]+)/g + }, + { + name: 'Closure', + regex: /function(?:\s)*?\((?:\$).*?\)/g + }, + { + name: 'Variable declarations', + regex: /(\$[a-zA-Z0-9]+)\s*?=(?!>|=)/g + } + ]; + + const getTypePromises = []; + const variableDeclarations = []; + + for (const filter of regexFilters) { + editor.backwardsScanInBufferRange(filter.regex, selectedBufferRange, element => { + const variables = element.matchText.match(/\$[a-zA-Z0-9]+/g); + const startPoint = new Point(element.range.end.row, 0); + const scopeRange = this.getRangeForCurrentScope(editor, startPoint); + + if (filter.name === 'Variable declarations') { + let chosenParameter = null; + for (const parameter of parameters) { + if (element.range.containsRange(parameter.range)) { + chosenParameter = parameter; + break; } + } - if (chosenParameter !== null) { - getTypePromises.push((this.getTypesForParameter(editor, chosenParameter))); - variableDeclarations.push(chosenParameter); - } + if (chosenParameter !== null) { + getTypePromises.push((this.getTypesForParameter(editor, chosenParameter))); + variableDeclarations.push(chosenParameter); } + } - return variables.map((variable) => { - (parameters = parameters.filter(parameter => { - if (parameter.name !== variable) { + return variables.map((variable) => { + (parameters = parameters.filter(parameter => { + if (parameter.name !== variable) { + return true; + } + if (scopeRange.containsRange(parameter.range)) { + // If variable declaration is after parameter then it's + // still needed in parameters. + if (element.range.start.row > parameter.range.start.row) { return true; } - if (scopeRange.containsRange(parameter.range)) { - // If variable declaration is after parameter then it's - // still needed in parameters. - if (element.range.start.row > parameter.range.start.row) { - return true; - } - if ((element.range.start.row === parameter.range.start.row) && - (element.range.start.column > parameter.range.start.column)) { - return true; - } - - return false; + if ((element.range.start.row === parameter.range.start.row) && + (element.range.start.column > parameter.range.start.column)) { + return true; } - return true; - })); - }); - }); - } - - this.variableDeclarations = this.makeUnique(variableDeclarations); + return false; + } - parameters = this.makeUnique(parameters); + return true; + })); + }); + }); + } - // Grab the variable types of the parameters. - const promises = []; + this.variableDeclarations = this.makeUnique(variableDeclarations); + + parameters = this.makeUnique(parameters); + + // Grab the variable types of the parameters. + const promises = []; + + parameters.forEach(parameter => { + // Removing $this from parameters as this doesn't need to be passed in. + if (parameter.name === '$this') { return; } + + return promises.push(this.getTypesForParameter(editor, parameter)); + }); + + const returnFirstResultHandler = resultArray => resultArray[0]; + + return Promise.all([Promise.all(promises), Promise.all(getTypePromises)]).then(returnFirstResultHandler); + } + + /** + * Takes the current buffer position and returns a range of the current + * scope that the buffer position is in. + * + * For example this could be the code within an if statement or closure. + * + * @param {TextEditor} editor + * @param {Point} bufferPosition + * + * @return {Range} + */ + getRangeForCurrentScope(editor, bufferPosition) { + let descriptions, i, indexOfDescriptor, line, row; + let asc; + let asc2, end; + let startScopePoint = null; + let endScopePoint = null; + + // Tracks any extra scopes that might exist inside the scope we are + // looking for. + let childScopes = 0; + + // First walk back until we find the start of the current scope. + for ( + ({ row } = bufferPosition), asc = bufferPosition.row <= 0; + asc ? row <= 0 : row >= 0; + asc ? row++ : row-- + ) { + var asc1; + line = editor.lineTextForBufferRow(row); + + if (!line) { continue; } + + const lastIndex = line.length - 1; + + for (i = lastIndex, asc1 = lastIndex <= 0; asc1 ? i <= 0 : i >= 0; asc1 ? i++ : i--) { + descriptions = editor.scopeDescriptorForBufferPosition( + [row, i] + ); - parameters.forEach(parameter => { - // Removing $this from parameters as this doesn't need to be passed in. - if (parameter.name === '$this') { return; } + indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.end.php'); + if (indexOfDescriptor > -1) { + childScopes++; + } - return promises.push(this.getTypesForParameter(editor, parameter)); - }); + indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.begin.php'); + if (indexOfDescriptor > -1) { + childScopes--; - const returnFirstResultHandler = resultArray => resultArray[0]; + if (childScopes === -1) { + startScopePoint = new Point(row, 0); + break; + } + } + } - return Promise.all([Promise.all(promises), Promise.all(getTypePromises)]).then(returnFirstResultHandler); + if (startScopePoint != null) { break; } } - /** - * Takes the current buffer position and returns a range of the current - * scope that the buffer position is in. - * - * For example this could be the code within an if statement or closure. - * - * @param {TextEditor} editor - * @param {Point} bufferPosition - * - * @return {Range} - */ - getRangeForCurrentScope(editor, bufferPosition) { - let descriptions, i, indexOfDescriptor, line, row; - let asc; - let asc2, end; - let startScopePoint = null; - let endScopePoint = null; - - // Tracks any extra scopes that might exist inside the scope we are - // looking for. - let childScopes = 0; - - // First walk back until we find the start of the current scope. - for ( - ({ row } = bufferPosition), asc = bufferPosition.row <= 0; - asc ? row <= 0 : row >= 0; - asc ? row++ : row-- - ) { - var asc1; - line = editor.lineTextForBufferRow(row); - - if (!line) { continue; } + if (startScopePoint === null) { + startScopePoint = new Point(0, 0); + } - const lastIndex = line.length - 1; + childScopes = 0; - for (i = lastIndex, asc1 = lastIndex <= 0; asc1 ? i <= 0 : i >= 0; asc1 ? i++ : i--) { - descriptions = editor.scopeDescriptorForBufferPosition( - [row, i] - ); + // Walk forward until we find the end of the current scope + for ( + ({ row } = startScopePoint), end = editor.getLineCount(), asc2 = startScopePoint.row <= end; + asc2 ? row <= end : row >= end; + asc2 ? row++ : row-- + ) { + var asc3, end1; + line = editor.lineTextForBufferRow(row); - indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.end.php'); - if (indexOfDescriptor > -1) { - childScopes++; - } + if (!line) { continue; } - indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.begin.php'); - if (indexOfDescriptor > -1) { - childScopes--; + let startIndex = 0; - if (childScopes === -1) { - startScopePoint = new Point(row, 0); - break; - } - } - } - - if (startScopePoint != null) { break; } - } - - if (startScopePoint === null) { - startScopePoint = new Point(0, 0); + if (startScopePoint.row === row) { + startIndex = line.length - 1; } - childScopes = 0; - - // Walk forward until we find the end of the current scope for ( - ({ row } = startScopePoint), end = editor.getLineCount(), asc2 = startScopePoint.row <= end; - asc2 ? row <= end : row >= end; - asc2 ? row++ : row-- + i = startIndex, end1 = line.length - 1, asc3 = startIndex <= end1; + asc3 ? i <= end1 : i >= end1; + asc3 ? i++ : i-- ) { - var asc3, end1; - line = editor.lineTextForBufferRow(row); - - if (!line) { continue; } - - let startIndex = 0; + descriptions = editor.scopeDescriptorForBufferPosition( + [row, i] + ); - if (startScopePoint.row === row) { - startIndex = line.length - 1; + indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.begin.php'); + if (indexOfDescriptor > -1) { + childScopes++; } - for ( - i = startIndex, end1 = line.length - 1, asc3 = startIndex <= end1; - asc3 ? i <= end1 : i >= end1; - asc3 ? i++ : i-- - ) { - descriptions = editor.scopeDescriptorForBufferPosition( - [row, i] - ); - - indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.begin.php'); - if (indexOfDescriptor > -1) { - childScopes++; + indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.end.php'); + if (indexOfDescriptor > -1) { + if (childScopes > 0) { + childScopes--; } - indexOfDescriptor = descriptions.scopes.indexOf('punctuation.section.scope.end.php'); - if (indexOfDescriptor > -1) { - if (childScopes > 0) { - childScopes--; - } - - if (childScopes === 0) { - endScopePoint = new Point(row, i + 1); - break; - } + if (childScopes === 0) { + endScopePoint = new Point(row, i + 1); + break; } } - - if (endScopePoint != null) { break; } } - return new Range(startScopePoint, endScopePoint); + if (endScopePoint != null) { break; } } - /** - * Takes an array of parameters and removes any parameters that appear more - * that once with the same name. - * - * @param {Array} array - * - * @return {Array} - */ - makeUnique(array) { - return array.filter(function(filterItem, pos, self) { - for (let i = 0, end = self.length - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { - if (self[i].name !== filterItem.name) { - continue; - } - - return pos === i; + return new Range(startScopePoint, endScopePoint); + } + + /** + * Takes an array of parameters and removes any parameters that appear more + * that once with the same name. + * + * @param {Array} array + * + * @return {Array} + */ + makeUnique(array) { + return array.filter(function(filterItem, pos, self) { + for (let i = 0, end = self.length - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + if (self[i].name !== filterItem.name) { + continue; } - return true; - }); - } - /** - * Generates the key used to store the parameters in the cache. - * - * @param {TextEditor} editor - * @param {Range} selectedBufferRange - * - * @return {String} - */ - buildKey(editor, selectedBufferRange) { - return editor.getPath() + JSON.stringify(selectedBufferRange); - } - /** - * Gets the type for the parameter given. - * - * @param {TextEditor} editor - * @param {Object} parameter - * - * @return {Promise} - */ - getTypesForParameter(editor, parameter) { - const successHandler = types => { - parameter.types = types; - - const typeResolutionPromises = []; - const path = 'file://' + editor.getPath(); - - const localizeTypeSuccessHandler = localizedType => { - return localizedType; - }; - - const localizeTypeFailureHandler = () => null; - - for (const fqcn of parameter.types) { - if (this.typeHelper.isClassType(fqcn)) { - const typeResolutionPromise = this.service.localizeType( - path, - this.selectedBufferRange.end, - fqcn, - 'classlike' - ); - - typeResolutionPromises.push(typeResolutionPromise.then( - localizeTypeSuccessHandler, - localizeTypeFailureHandler - ) - ); - - } else { - typeResolutionPromises.push(Promise.resolve(fqcn)); - } - } + return pos === i; + } + return true; + }); + } + /** + * Generates the key used to store the parameters in the cache. + * + * @param {TextEditor} editor + * @param {Range} selectedBufferRange + * + * @return {String} + */ + buildKey(editor, selectedBufferRange) { + return editor.getPath() + JSON.stringify(selectedBufferRange); + } + + /** + * Gets the type for the parameter given. + * + * @param {TextEditor} editor + * @param {Object} parameter + * + * @return {Promise} + */ + getTypesForParameter(editor, parameter) { + const successHandler = types => { + parameter.types = types; + + const typeResolutionPromises = []; + const path = 'file://' + editor.getPath(); + + const localizeTypeSuccessHandler = localizedType => { + return localizedType; + }; - const combineResolvedTypesHandler = function(processedTypeArray) { - parameter.types = processedTypeArray; + const localizeTypeFailureHandler = () => null; - return parameter; - }; + for (const fqcn of parameter.types) { + if (this.typeHelper.isClassType(fqcn)) { + const typeResolutionPromise = this.service.localizeType( + path, + this.selectedBufferRange.end, + fqcn, + 'classlike' + ); - return Promise.all(typeResolutionPromises).then( - combineResolvedTypesHandler, - combineResolvedTypesHandler - ); - }; + typeResolutionPromises.push(typeResolutionPromise.then( + localizeTypeSuccessHandler, + localizeTypeFailureHandler + ) + ); - const failureHandler = () => { - return null; - }; + } else { + typeResolutionPromises.push(Promise.resolve(fqcn)); + } + } - return this.service.deduceTypesAt(parameter.name, editor, this.selectedBufferRange.end).then( - successHandler, - failureHandler - ); - } + const combineResolvedTypesHandler = function(processedTypeArray) { + parameter.types = processedTypeArray; - /** - * Returns all the variable declarations that have been parsed. - * - * @return {Array} - */ - getVariableDeclarations() { - return this.variableDeclarations; - } + return parameter; + }; - /** - * Clean up any data from previous usage - */ - cleanUp() { - return this.variableDeclarations = []; - } - }; - ParameterParser.initClass(); - return ParameterParser; -})()); + return Promise.all(typeResolutionPromises).then( + combineResolvedTypesHandler, + combineResolvedTypesHandler + ); + }; + + const failureHandler = () => { + return null; + }; + + return this.service.deduceTypesAt(parameter.name, editor, this.selectedBufferRange.end).then( + successHandler, + failureHandler + ); + } + + /** + * Returns all the variable declarations that have been parsed. + * + * @return {Array} + */ + getVariableDeclarations() { + return this.variableDeclarations; + } + + /** + * Clean up any data from previous usage + */ + cleanUp() { + return this.variableDeclarations = []; + } +}; diff --git a/lib/Refactoring/ExtractMethodProvider/View.js b/lib/Refactoring/ExtractMethodProvider/View.js index f14f184c..b3c4b287 100644 --- a/lib/Refactoring/ExtractMethodProvider/View.js +++ b/lib/Refactoring/ExtractMethodProvider/View.js @@ -7,395 +7,382 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let ExtractMethodView; const {$, TextEditorView, View} = require('atom-space-pen-views'); const Parser = require('./Builder'); module.exports = -(ExtractMethodView = (function() { - ExtractMethodView = class ExtractMethodView extends View { - static initClass() { - - /** - * The callback to invoke when the user confirms his selections. - * - * @type {Callback} - */ - this.prototype.onDidConfirm = null; - - /** - * The callback to invoke when the user cancels the view. - * - * @type {Callback} - */ - this.prototype.onDidCancel = null; - - /** - * Settings of how to generate new method that will be passed to the parser - * - * @type {Object} - */ - this.prototype.settings = null; - - /** - * Builder to use when generating preview area - * - * @type {Builder} - */ - this.prototype.builder = null; - } +class ExtractMethodView extends View { + /** + * Constructor. + * + * @param {Callback} onDidConfirm + * @param {Callback} onDidCancel + */ + constructor(onDidConfirm, onDidCancel = null) { + super(); /** - * Constructor. + * The callback to invoke when the user confirms his selections. * - * @param {Callback} onDidConfirm - * @param {Callback} onDidCancel + * @type {Callback} */ - constructor(onDidConfirm, onDidCancel = null) { - super(); - - this.onDidConfirm = onDidConfirm; - this.onDidCancel = onDidCancel; - - this.settings = { - generateDocs: true, - methodName: '', - visibility: 'private', - tabs: false, - arraySyntax: 'brackets', - typeHinting: true, - generateDescPlaceholders: false - }; - } + this.onDidConfirm = onDidConfirm; /** - * Content to be displayed when this view is shown. + * The callback to invoke when the user cancels the view. + * + * @type {Callback} */ - static content() { - return this.div({class: 'php-ide-serenata-refactoring-extract-method'}, () => { - this.div({outlet: 'methodNameForm'}, () => { - this.subview('methodNameEditor', new TextEditorView( - { mini: true, placeholderText: 'Enter a method name' } - )); - this.div( - { class: 'text-error error-message hide error-message--method-name' }, - 'You must enter a method name!' - ); - return this.div({class: 'settings-view'}, () => { - return this.div({class: 'section-body'}, () => { - this.div({class: 'control-group'}, () => { - return this.div({class: 'controls'}, () => { - return this.label({class: 'control-label'}, () => { - this.div({class: 'setting-title'}, 'Access Modifier'); - return this.select({ - outlet: 'accessMethodsInput', - class: 'form-control' - }, () => { - this.option({value: 'public'}, 'Public'); - this.option({value: 'protected'}, 'Protected'); - return this.option({value: 'private', selected: 'selected'}, 'Private'); - }); + this.onDidCancel = onDidCancel; + + /** + * Settings of how to generate new method that will be passed to the parser + * + * @type {Object} + */ + this.settings = { + generateDocs: true, + methodName: '', + visibility: 'private', + tabs: false, + arraySyntax: 'brackets', + typeHinting: true, + generateDescPlaceholders: false + }; + + /** + * Builder to use when generating preview area + * + * @type {Builder} + */ + this.builder = null; + } + + /** + * Content to be displayed when this view is shown. + */ + static content() { + return this.div({class: 'php-ide-serenata-refactoring-extract-method'}, () => { + this.div({outlet: 'methodNameForm'}, () => { + this.subview('methodNameEditor', new TextEditorView( + { mini: true, placeholderText: 'Enter a method name' } + )); + this.div( + { class: 'text-error error-message hide error-message--method-name' }, + 'You must enter a method name!' + ); + return this.div({class: 'settings-view'}, () => { + return this.div({class: 'section-body'}, () => { + this.div({class: 'control-group'}, () => { + return this.div({class: 'controls'}, () => { + return this.label({class: 'control-label'}, () => { + this.div({class: 'setting-title'}, 'Access Modifier'); + return this.select({ + outlet: 'accessMethodsInput', + class: 'form-control' + }, () => { + this.option({value: 'public'}, 'Public'); + this.option({value: 'protected'}, 'Protected'); + return this.option({value: 'private', selected: 'selected'}, 'Private'); }); }); }); - this.div({class: 'control-group'}, () => { - return this.label({class: 'control-label'}, () => { - this.div({class: 'setting-title'}, 'Documentation'); - this.div({class: 'controls'}, () => { - return this.div({class: 'checkbox'}, () => { - return this.label(() => { - this.input({ - outlet: 'generateDocInput', - type: 'checkbox', - checked: true - }); - return this.div({class: 'setting-title'}, 'Generate documentation'); + }); + this.div({class: 'control-group'}, () => { + return this.label({class: 'control-label'}, () => { + this.div({class: 'setting-title'}, 'Documentation'); + this.div({class: 'controls'}, () => { + return this.div({class: 'checkbox'}, () => { + return this.label(() => { + this.input({ + outlet: 'generateDocInput', + type: 'checkbox', + checked: true }); + return this.div({class: 'setting-title'}, 'Generate documentation'); }); }); - return this.div({class: 'controls generate-docs-control'}, () => { - return this.div({class: 'checkbox'}, () => { - return this.label(() => { - this.input({ - outlet: 'generateDescPlaceholdersInput', - type: 'checkbox' - }); - return this.div( - { class: 'setting-title' }, - 'Generate description placeholders' - ); + }); + return this.div({class: 'controls generate-docs-control'}, () => { + return this.div({class: 'checkbox'}, () => { + return this.label(() => { + this.input({ + outlet: 'generateDescPlaceholdersInput', + type: 'checkbox' }); + return this.div( + { class: 'setting-title' }, + 'Generate description placeholders' + ); }); }); }); }); - this.div({class: 'control-group'}, () => { - return this.label({class: 'control-label'}, () => { - this.div({class: 'setting-title'}, 'Type hinting'); - return this.div({class: 'controls'}, () => { - return this.div({class: 'checkbox'}, () => { - return this.label(() => { - this.input({ - outlet: 'generateTypeHints', - type: 'checkbox', - checked: true - }); - return this.div({class: 'setting-title'}, 'Generate type hints'); + }); + this.div({class: 'control-group'}, () => { + return this.label({class: 'control-label'}, () => { + this.div({class: 'setting-title'}, 'Type hinting'); + return this.div({class: 'controls'}, () => { + return this.div({class: 'checkbox'}, () => { + return this.label(() => { + this.input({ + outlet: 'generateTypeHints', + type: 'checkbox', + checked: true }); + return this.div({class: 'setting-title'}, 'Generate type hints'); }); }); }); }); - this.div({class: 'return-multiple-control control-group'}, () => { - return this.label({class: 'control-label'}, () => { - this.div({class: 'setting-title'}, 'Method styling'); - return this.div({class: 'controls'}, () => { - return this.div({class: 'checkbox'}, () => { - return this.label(() => { - this.input({ - outlet: 'arraySyntax', - type: 'checkbox', - checked: true - }); - return this.div( - { class: 'setting-title' }, - 'Use PHP 5.4 array syntax (square brackets)' - ); + }); + this.div({class: 'return-multiple-control control-group'}, () => { + return this.label({class: 'control-label'}, () => { + this.div({class: 'setting-title'}, 'Method styling'); + return this.div({class: 'controls'}, () => { + return this.div({class: 'checkbox'}, () => { + return this.label(() => { + this.input({ + outlet: 'arraySyntax', + type: 'checkbox', + checked: true }); + return this.div( + { class: 'setting-title' }, + 'Use PHP 5.4 array syntax (square brackets)' + ); }); }); }); }); - return this.div({class: 'control-group'}, () => { - return this.div({class: 'controls'}, () => { - return this.label({class: 'control-label'}, () => { - this.div({class: 'setting-title'}, 'Preview'); - return this.div({class: 'preview-area'}, () => { - return this.subview( - 'previewArea', - new TextEditorView(), - { class: 'preview-area' } - ); - }); + }); + return this.div({class: 'control-group'}, () => { + return this.div({class: 'controls'}, () => { + return this.label({class: 'control-label'}, () => { + this.div({class: 'setting-title'}, 'Preview'); + return this.div({class: 'preview-area'}, () => { + return this.subview( + 'previewArea', + new TextEditorView(), + { class: 'preview-area' } + ); }); }); }); }); }); }); - return this.div({class: 'button-bar'}, () => { - this.button( - { class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel' }, - 'Cancel' - ); - this.button( - { class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' }, - 'Extract' - ); - return this.div({class: 'clear-float'}); - }); }); + return this.div({class: 'button-bar'}, () => { + this.button( + { class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel' }, + 'Cancel' + ); + this.button( + { class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' }, + 'Extract' + ); + return this.div({class: 'clear-float'}); + }); + }); + } + + /** + * @inheritdoc + */ + initialize() { + atom.commands.add(this.element, { + 'core:confirm': event => { + this.confirm(); + return event.stopPropagation(); + }, + 'core:cancel': event => { + this.cancel(); + return event.stopPropagation(); + } } - - /** - * @inheritdoc - */ - initialize() { - atom.commands.add(this.element, { - 'core:confirm': event => { - this.confirm(); - return event.stopPropagation(); - }, - 'core:cancel': event => { - this.cancel(); - return event.stopPropagation(); - } + ); + + this.on('click', 'button', event => { + if ($(event.target).hasClass('button--confirm')) { this.confirm(); } + if ($(event.target).hasClass('button--cancel')) { return this.cancel(); } + }); + + this.methodNameEditor.getModel().onDidChange(() => { + this.settings.methodName = this.methodNameEditor.getText(); + $('.php-ide-serenata-refactoring-extract-method .error-message--method-name').addClass('hide'); + + return this.refreshPreviewArea(); + }); + + $(this.accessMethodsInput[0]).change(event => { + this.settings.visibility = $(event.target).val(); + return this.refreshPreviewArea(); + }); + + $(this.generateDocInput[0]).change(event => { + this.settings.generateDocs = !this.settings.generateDocs; + if (this.settings.generateDocs === true) { + $('.php-ide-serenata-refactoring-extract-method .generate-docs-control').removeClass('hide'); + } else { + $('.php-ide-serenata-refactoring-extract-method .generate-docs-control').addClass('hide'); } - ); - - this.on('click', 'button', event => { - if ($(event.target).hasClass('button--confirm')) { this.confirm(); } - if ($(event.target).hasClass('button--cancel')) { return this.cancel(); } - }); - this.methodNameEditor.getModel().onDidChange(() => { - this.settings.methodName = this.methodNameEditor.getText(); - $('.php-ide-serenata-refactoring-extract-method .error-message--method-name').addClass('hide'); - return this.refreshPreviewArea(); - }); + return this.refreshPreviewArea(); + }); - $(this.accessMethodsInput[0]).change(event => { - this.settings.visibility = $(event.target).val(); - return this.refreshPreviewArea(); - }); - - $(this.generateDocInput[0]).change(event => { - this.settings.generateDocs = !this.settings.generateDocs; - if (this.settings.generateDocs === true) { - $('.php-ide-serenata-refactoring-extract-method .generate-docs-control').removeClass('hide'); - } else { - $('.php-ide-serenata-refactoring-extract-method .generate-docs-control').addClass('hide'); - } + $(this.generateDescPlaceholdersInput[0]).change(event => { + this.settings.generateDescPlaceholders = !this.settings.generateDescPlaceholders; + return this.refreshPreviewArea(); + }); + $(this.generateTypeHints[0]).change(event => { + this.settings.typeHinting = !this.settings.typeHinting; + return this.refreshPreviewArea(); + }); - return this.refreshPreviewArea(); - }); - - $(this.generateDescPlaceholdersInput[0]).change(event => { - this.settings.generateDescPlaceholders = !this.settings.generateDescPlaceholders; - return this.refreshPreviewArea(); - }); - - $(this.generateTypeHints[0]).change(event => { - this.settings.typeHinting = !this.settings.typeHinting; - return this.refreshPreviewArea(); - }); - - $(this.arraySyntax[0]).change(event => { - if (this.settings.arraySyntax === 'word') { - this.settings.arraySyntax = 'brackets'; - } else { - this.settings.arraySyntax = 'word'; - } - return this.refreshPreviewArea(); - }); - - if (this.panel == null) { this.panel = atom.workspace.addModalPanel({item: this, visible: false}); } - - const previewAreaTextEditor = this.previewArea.getModel(); - previewAreaTextEditor.setGrammar(atom.grammars.grammarForScopeName('text.html.php')); - - this.on('click', document, event => { - return event.stopPropagation(); - }); - - return $(document).on('click', event => { - if (this.panel != null ? this.panel.isVisible() : undefined) { return this.cancel(); } - }); - } - - /** - * Destroys the view and cleans up. - */ - destroy() { - this.panel.destroy(); - return this.panel = null; + $(this.arraySyntax[0]).change(event => { + if (this.settings.arraySyntax === 'word') { + this.settings.arraySyntax = 'brackets'; + } else { + this.settings.arraySyntax = 'word'; + } + return this.refreshPreviewArea(); + }); + + if (this.panel == null) { this.panel = atom.workspace.addModalPanel({item: this, visible: false}); } + + const previewAreaTextEditor = this.previewArea.getModel(); + previewAreaTextEditor.setGrammar(atom.grammars.grammarForScopeName('text.html.php')); + + this.on('click', document, event => { + return event.stopPropagation(); + }); + + return $(document).on('click', event => { + if (this.panel != null ? this.panel.isVisible() : undefined) { return this.cancel(); } + }); + } + + /** + * Destroys the view and cleans up. + */ + destroy() { + this.panel.destroy(); + return this.panel = null; + } + + /** + * Shows the view and refreshes the preview area with the current settings. + */ + present() { + this.panel.show(); + this.methodNameEditor.focus(); + return this.methodNameEditor.setText(''); + } + + /** + * Hides the panel. + */ + hide() { + if (this.panel != null) { + this.panel.hide(); } - - /** - * Shows the view and refreshes the preview area with the current settings. - */ - present() { - this.panel.show(); - this.methodNameEditor.focus(); - return this.methodNameEditor.setText(''); + return this.restoreFocus(); + } + + /** + * Called when the user confirms the extraction and will then call + * onDidConfirm, if set. + */ + confirm() { + if (this.settings.methodName === '') { + $('.php-ide-serenata-refactoring-extract-method .error-message--method-name').removeClass('hide'); + return false; } - /** - * Hides the panel. - */ - hide() { - if (this.panel != null) { - this.panel.hide(); - } - return this.restoreFocus(); + if (this.onDidConfirm) { + this.onDidConfirm(this.getSettings()); } - /** - * Called when the user confirms the extraction and will then call - * onDidConfirm, if set. - */ - confirm() { - if (this.settings.methodName === '') { - $('.php-ide-serenata-refactoring-extract-method .error-message--method-name').removeClass('hide'); - return false; - } + return this.hide(); + } - if (this.onDidConfirm) { - this.onDidConfirm(this.getSettings()); - } - - return this.hide(); + /** + * Called when the user cancels the extraction and will then call + * onDidCancel, if set. + */ + cancel() { + if (this.onDidCancel) { + this.onDidCancel(); } - /** - * Called when the user cancels the extraction and will then call - * onDidCancel, if set. - */ - cancel() { - if (this.onDidCancel) { - this.onDidCancel(); - } + return this.hide(); + } - return this.hide(); - } + /** + * Updates the preview area using the current setttings. + */ + refreshPreviewArea() { + if (!this.panel.isVisible()) { return; } - /** - * Updates the preview area using the current setttings. - */ - refreshPreviewArea() { - if (!this.panel.isVisible()) { return; } - - const successHandler = methodBody => { - if (this.builder.hasReturnValues()) { - if (this.builder.hasMultipleReturnValues()) { - $('.php-ide-serenata-refactoring-extract-method .return-multiple-control').removeClass('hide'); - } else { - $('.php-ide-serenata-refactoring-extract-method .return-multiple-control').addClass('hide'); - } - - $('.php-ide-serenata-refactoring-extract-method .return-control').removeClass('hide'); + const successHandler = methodBody => { + if (this.builder.hasReturnValues()) { + if (this.builder.hasMultipleReturnValues()) { + $('.php-ide-serenata-refactoring-extract-method .return-multiple-control').removeClass('hide'); } else { - $('.php-ide-serenata-refactoring-extract-method .return-control').addClass('hide'); $('.php-ide-serenata-refactoring-extract-method .return-multiple-control').addClass('hide'); } - return this.previewArea.getModel().getBuffer().setText(` { - return this.executeCommand(true, false); - } - } - ); - - atom.commands.add('atom-workspace', { 'php-ide-serenata-refactoring:generate-setter': () => { - return this.executeCommand(false, true); - } - } - ); - - return atom.commands.add( - 'atom-workspace', - { 'php-ide-serenata-refactoring:generate-getter-setter-pair': () => { - return this.executeCommand(true, true); - } } - ); - } + /** + * The docblock builder. + */ + this.docblockBuilder = docblockBuilder; /** - * @inheritdoc + * The type helper. */ - deactivate() { - super.deactivate(); + this.typeHelper = typeHelper; + } - if (this.selectionView) { - this.selectionView.destroy(); - return this.selectionView = null; - } + /** + * @inheritdoc + */ + activate(service) { + super.activate(service); + + atom.commands.add('atom-workspace', { 'php-ide-serenata-refactoring:generate-getter': () => { + return this.executeCommand(true, false); } + } + ); - /** - * @inheritdoc - */ - getIntentionProviders() { - return [{ - grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { - const successHandler = currentClassName => { - if (!currentClassName) { return []; } - - return [ - { - priority : 100, - icon : 'gear', - title : 'Generate Getter And Setter Pair(s)', - - selected : () => { - return this.executeCommand(true, true); - } - }, - - { - priority : 100, - icon : 'gear', - title : 'Generate Getter(s)', - - selected : () => { - return this.executeCommand(true, false); - } - }, - - { - priority : 100, - icon : 'gear', - title : 'Generate Setter(s)', - - selected : () => { - return this.executeCommand(false, true); - } + atom.commands.add('atom-workspace', { 'php-ide-serenata-refactoring:generate-setter': () => { + return this.executeCommand(false, true); + } + } + ); + + return atom.commands.add( + 'atom-workspace', + { 'php-ide-serenata-refactoring:generate-getter-setter-pair': () => { + return this.executeCommand(true, true); + } } + ); + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.selectionView) { + this.selectionView.destroy(); + return this.selectionView = null; + } + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['source.php'], + getIntentions: ({textEditor, bufferPosition}) => { + const successHandler = currentClassName => { + if (!currentClassName) { return []; } + + return [ + { + priority : 100, + icon : 'gear', + title : 'Generate Getter And Setter Pair(s)', + + selected : () => { + return this.executeCommand(true, true); } - ]; - }; - - const failureHandler = () => []; + }, - const activeTextEditor = atom.workspace.getActiveTextEditor(); + { + priority : 100, + icon : 'gear', + title : 'Generate Getter(s)', - if (!activeTextEditor) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + selected : () => { + return this.executeCommand(true, false); + } + }, - return this.service.determineCurrentClassName( - activeTextEditor, - activeTextEditor.getCursorBufferPosition() - ).then(successHandler, failureHandler); - } - }]; - } + { + priority : 100, + icon : 'gear', + title : 'Generate Setter(s)', - /** - * Executes the generation. - * - * @param {boolean} enableGetterGeneration - * @param {boolean} enableSetterGeneration - */ - executeCommand(enableGetterGeneration, enableSetterGeneration) { - const activeTextEditor = atom.workspace.getActiveTextEditor(); - - if (!activeTextEditor) { return; } - - this.getSelectionView().setMetadata({editor: activeTextEditor}); - this.getSelectionView().storeFocusedElement(); - this.getSelectionView().present(); - - const successHandler = currentClassName => { - if (!currentClassName) { return; } - - const nestedSuccessHandler = classInfo => { - const enabledItems = []; - const disabledItems = []; - - const indentationLevel = activeTextEditor.indentationForBufferRow( - activeTextEditor.getCursorBufferPosition().row - ); - - for (let name in classInfo.properties) { - const property = classInfo.properties[name]; - const getterName = `get${name.substr(0, 1).toUpperCase()}${name.substr(1)}`; - const setterName = `set${name.substr(0, 1).toUpperCase()}${name.substr(1)}`; - - const getterExists = getterName in classInfo.methods ? true : false; - const setterExists = setterName in classInfo.methods ? true : false; - - const data = { - name, - types : property.types, - needsGetter : enableGetterGeneration, - needsSetter : enableSetterGeneration, - getterName, - setterName, - tabText : activeTextEditor.getTabText(), - indentationLevel, - maxLineLength : atom.config.get( - 'editor.preferredLineLength', - activeTextEditor.getLastCursor().getScopeDescriptor() - ) - }; - - if ((enableGetterGeneration && enableSetterGeneration && getterExists && setterExists) || - (enableGetterGeneration && getterExists) || - (enableSetterGeneration && setterExists)) { - data.className = 'php-ide-serenata-refactoring-strikethrough'; - disabledItems.push(data); - - } else { - data.className = ''; - enabledItems.push(data); + selected : () => { + return this.executeCommand(false, true); + } } - } - - return this.getSelectionView().setItems(enabledItems.concat(disabledItems)); + ]; }; - const nestedFailureHandler = () => { - return this.getSelectionView().setItems([]); - }; + const failureHandler = () => []; - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, nestedFailureHandler); - }; + const activeTextEditor = atom.workspace.getActiveTextEditor(); - const failureHandler = () => { - return this.getSelectionView().setItems([]); - }; + if (!activeTextEditor) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - return this.service.determineCurrentClassName(activeTextEditor, activeTextEditor.getCursorBufferPosition()) - .then(successHandler, failureHandler); - } - - /** - * Indicates if the specified type is a class type or not. - * - * @return {bool} - */ - isClassType(type) { - if (type.substr(0, 1).toUpperCase() === type.substr(0, 1)) { return true; } else { return false; } - } - - /** - * Called when the selection of properties is cancelled. - * - * @param {Object|null} metadata - */ - onCancel(metadata) {} + return this.service.determineCurrentClassName( + activeTextEditor, + activeTextEditor.getCursorBufferPosition() + ).then(successHandler, failureHandler); + } + }]; + } + + /** + * Executes the generation. + * + * @param {boolean} enableGetterGeneration + * @param {boolean} enableSetterGeneration + */ + executeCommand(enableGetterGeneration, enableSetterGeneration) { + const activeTextEditor = atom.workspace.getActiveTextEditor(); + + if (!activeTextEditor) { return; } + + this.getSelectionView().setMetadata({editor: activeTextEditor}); + this.getSelectionView().storeFocusedElement(); + this.getSelectionView().present(); + + const successHandler = currentClassName => { + if (!currentClassName) { return; } + + const nestedSuccessHandler = classInfo => { + const enabledItems = []; + const disabledItems = []; + + const indentationLevel = activeTextEditor.indentationForBufferRow( + activeTextEditor.getCursorBufferPosition().row + ); + + for (let name in classInfo.properties) { + const property = classInfo.properties[name]; + const getterName = `get${name.substr(0, 1).toUpperCase()}${name.substr(1)}`; + const setterName = `set${name.substr(0, 1).toUpperCase()}${name.substr(1)}`; + + const getterExists = getterName in classInfo.methods ? true : false; + const setterExists = setterName in classInfo.methods ? true : false; + + const data = { + name, + types : property.types, + needsGetter : enableGetterGeneration, + needsSetter : enableSetterGeneration, + getterName, + setterName, + tabText : activeTextEditor.getTabText(), + indentationLevel, + maxLineLength : atom.config.get( + 'editor.preferredLineLength', + activeTextEditor.getLastCursor().getScopeDescriptor() + ) + }; - /** - * Called when the selection of properties is confirmed. - * - * @param {array} selectedItems - * @param {Object|null} metadata - */ - async onConfirm(selectedItems, metadata) { - const itemOutputs = []; - const editorUri = 'file://' + metadata.editor.getPath(); - const bufferPosition = metadata.editor.getCursorBufferPosition(); - - for (const item of selectedItems) { - if (item.needsGetter) { - itemOutputs.push(await this.generateGetterForItem(item, editorUri, bufferPosition)); - } + if ((enableGetterGeneration && enableSetterGeneration && getterExists && setterExists) || + (enableGetterGeneration && getterExists) || + (enableSetterGeneration && setterExists)) { + data.className = 'php-ide-serenata-refactoring-strikethrough'; + disabledItems.push(data); - if (item.needsSetter) { - itemOutputs.push(await this.generateSetterForItem(item, editorUri, bufferPosition)); + } else { + data.className = ''; + enabledItems.push(data); + } } - } - const output = itemOutputs.join('\n').trim(); + return this.getSelectionView().setItems(enabledItems.concat(disabledItems)); + }; - return metadata.editor.getBuffer().insert(bufferPosition, output); - } + const nestedFailureHandler = () => { + return this.getSelectionView().setItems([]); + }; - /** - * Generates a getter for the specified selected item. - * - * @param {Object} item - * @param {String} editorUri - * @param {Point} bufferPosition - * - * @return {string} - */ - async generateGetterForItem(item, editorUri, bufferPosition) { - await this.localizeFunctionParameterTypes(item, editorUri, bufferPosition); - - const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypeArray(item.types); - - const statements = [ - `return $this->${item.name};` - ]; - - const functionText = this.functionBuilder - .makePublic() - .setIsStatic(false) - .setIsAbstract(false) - .setName(item.getterName) - .setReturnType(this.typeHelper.getReturnTypeHintForTypeSpecification(typeSpecification)) - .setParameters([]) - .setStatements(statements) - .setTabText(item.tabText) - .setIndentationLevel(item.indentationLevel) - .setMaxLineLength(item.maxLineLength) - .build(); - - const docblockText = this.docblockBuilder.buildForMethod( - [], - typeSpecification, - false, - item.tabText.repeat(item.indentationLevel) - ); - - return docblockText + functionText; - } + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, nestedFailureHandler); + }; + + const failureHandler = () => { + return this.getSelectionView().setItems([]); + }; + + return this.service.determineCurrentClassName(activeTextEditor, activeTextEditor.getCursorBufferPosition()) + .then(successHandler, failureHandler); + } + + /** + * Indicates if the specified type is a class type or not. + * + * @return {bool} + */ + isClassType(type) { + if (type.substr(0, 1).toUpperCase() === type.substr(0, 1)) { return true; } else { return false; } + } + + /** + * Called when the selection of properties is cancelled. + * + * @param {Object|null} metadata + */ + onCancel(metadata) {} + + /** + * Called when the selection of properties is confirmed. + * + * @param {array} selectedItems + * @param {Object|null} metadata + */ + async onConfirm(selectedItems, metadata) { + const itemOutputs = []; + const editorUri = 'file://' + metadata.editor.getPath(); + const bufferPosition = metadata.editor.getCursorBufferPosition(); + + for (const item of selectedItems) { + if (item.needsGetter) { + itemOutputs.push(await this.generateGetterForItem(item, editorUri, bufferPosition)); + } - /** - * Generates a setter for the specified selected item. - * - * @param {Object} item - * - * @return {string} - */ - generateSetterForItem(item) { - const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypeArray(item.types); - const parameterTypeHint = this.typeHelper.getTypeHintForTypeSpecification(typeSpecification); - - const statements = [ - `$this->${item.name} = $${item.name};`, - 'return $this;' - ]; - - const parameters = [ - { - name : `$${item.name}`, - typeHint : parameterTypeHint.typeHint, - defaultValue : parameterTypeHint.shouldSetDefaultValueToNull ? 'null' : null - } - ]; - - const functionText = this.functionBuilder - .makePublic() - .setIsStatic(false) - .setIsAbstract(false) - .setName(item.setterName) - .setReturnType(null) - .setParameters(parameters) - .setStatements(statements) - .setTabText(item.tabText) - .setIndentationLevel(item.indentationLevel) - .setMaxLineLength(item.maxLineLength) - .build(); - - const docblockText = this.docblockBuilder.buildForMethod( - [{name : `$${item.name}`, type : typeSpecification}], - 'static', - false, - item.tabText.repeat(item.indentationLevel) - ); - - return docblockText + functionText; + if (item.needsSetter) { + itemOutputs.push(await this.generateSetterForItem(item, editorUri, bufferPosition)); + } } - /** - * @return {Builder} - */ - getSelectionView() { - if ((this.selectionView == null)) { - const View = require('./GetterSetterProvider/View'); - - this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); - this.selectionView.setLoading('Loading class information...'); - this.selectionView.setEmptyMessage('No properties found.'); + const output = itemOutputs.join('\n').trim(); + + return metadata.editor.getBuffer().insert(bufferPosition, output); + } + + /** + * Generates a getter for the specified selected item. + * + * @param {Object} item + * @param {String} editorUri + * @param {Point} bufferPosition + * + * @return {string} + */ + async generateGetterForItem(item, editorUri, bufferPosition) { + await this.localizeFunctionParameterTypes(item, editorUri, bufferPosition); + + const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypeArray(item.types); + + const statements = [ + `return $this->${item.name};` + ]; + + const functionText = this.functionBuilder + .makePublic() + .setIsStatic(false) + .setIsAbstract(false) + .setName(item.getterName) + .setReturnType(this.typeHelper.getReturnTypeHintForTypeSpecification(typeSpecification)) + .setParameters([]) + .setStatements(statements) + .setTabText(item.tabText) + .setIndentationLevel(item.indentationLevel) + .setMaxLineLength(item.maxLineLength) + .build(); + + const docblockText = this.docblockBuilder.buildForMethod( + [], + typeSpecification, + false, + item.tabText.repeat(item.indentationLevel) + ); + + return docblockText + functionText; + } + + /** + * Generates a setter for the specified selected item. + * + * @param {Object} item + * + * @return {string} + */ + generateSetterForItem(item) { + const typeSpecification = this.typeHelper.buildTypeSpecificationFromTypeArray(item.types); + const parameterTypeHint = this.typeHelper.getTypeHintForTypeSpecification(typeSpecification); + + const statements = [ + `$this->${item.name} = $${item.name};`, + 'return $this;' + ]; + + const parameters = [ + { + name : `$${item.name}`, + typeHint : parameterTypeHint.typeHint, + defaultValue : parameterTypeHint.shouldSetDefaultValueToNull ? 'null' : null } - - return this.selectionView; + ]; + + const functionText = this.functionBuilder + .makePublic() + .setIsStatic(false) + .setIsAbstract(false) + .setName(item.setterName) + .setReturnType(null) + .setParameters(parameters) + .setStatements(statements) + .setTabText(item.tabText) + .setIndentationLevel(item.indentationLevel) + .setMaxLineLength(item.maxLineLength) + .build(); + + const docblockText = this.docblockBuilder.buildForMethod( + [{name : `$${item.name}`, type : typeSpecification}], + 'static', + false, + item.tabText.repeat(item.indentationLevel) + ); + + return docblockText + functionText; + } + + /** + * @return {Builder} + */ + getSelectionView() { + if ((this.selectionView == null)) { + const View = require('./GetterSetterProvider/View'); + + this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); + this.selectionView.setLoading('Loading class information...'); + this.selectionView.setEmptyMessage('No properties found.'); } - }; - GetterSetterProvider.initClass(); - return GetterSetterProvider; -})()); + + return this.selectionView; + } +}; diff --git a/lib/Refactoring/GetterSetterProvider/View.js b/lib/Refactoring/GetterSetterProvider/View.js index c26edfa2..41729b47 100644 --- a/lib/Refactoring/GetterSetterProvider/View.js +++ b/lib/Refactoring/GetterSetterProvider/View.js @@ -3,20 +3,16 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let View; -const {$, $$, SelectListView} = require('atom-space-pen-views'); +const {$, $$} = require('atom-space-pen-views'); const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -//#* -// An extension on SelectListView from atom-space-pen-views that allows multiple selections. -//# -(View = class View extends MultiSelectionView { +class View extends MultiSelectionView { /** * @inheritdoc - */ + */ createWidgets() { const checkboxBar = $$(function() { return this.div({class: 'checkbox-bar settings-view'}, () => { @@ -44,10 +40,10 @@ module.exports = /** * @inheritdoc - */ + */ invokeOnDidConfirm() { if (this.onDidConfirm) { return this.onDidConfirm(this.selectedItems, this.getMetadata()); } } -}); +}; diff --git a/lib/Refactoring/IntroducePropertyProvider.js b/lib/Refactoring/IntroducePropertyProvider.js index 813e2b9e..62954262 100644 --- a/lib/Refactoring/IntroducePropertyProvider.js +++ b/lib/Refactoring/IntroducePropertyProvider.js @@ -6,7 +6,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let IntroducePropertyProvider; const {Point} = require('atom'); const AbstractProvider = require('./AbstractProvider'); @@ -16,160 +15,152 @@ module.exports = //#* // Provides property generation for non-existent properties. //# -(IntroducePropertyProvider = (function() { - IntroducePropertyProvider = class IntroducePropertyProvider extends AbstractProvider { - static initClass() { - /** - * The docblock builder. - */ - this.prototype.docblockBuilder = null; - } +class IntroducePropertyProvider extends AbstractProvider { + /** + * @param {Object} docblockBuilder + */ + constructor(docblockBuilder) { + super(); /** - * @param {Object} docblockBuilder + * The docblock builder. */ - constructor(docblockBuilder) { - super(); + this.docblockBuilder = docblockBuilder; + } - this.docblockBuilder = docblockBuilder; - } + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['variable.other.property.php'], + getIntentions: ({textEditor, bufferPosition}) => { + const nameRange = textEditor.bufferRangeForScopeAtCursor('variable.other.property'); - /** - * @inheritdoc - */ - getIntentionProviders() { - return [{ - grammarScopes: ['variable.other.property.php'], - getIntentions: ({textEditor, bufferPosition}) => { - const nameRange = textEditor.bufferRangeForScopeAtCursor('variable.other.property'); + if ((nameRange == null)) { return []; } + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - if ((nameRange == null)) { return []; } - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + const name = textEditor.getTextInBufferRange(nameRange); - const name = textEditor.getTextInBufferRange(nameRange); - - return this.getIntentions(textEditor, bufferPosition, name); + return this.getIntentions(textEditor, bufferPosition, name); + } + }]; + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + * @param {String} name + */ + getIntentions(editor, triggerPosition, name) { + const failureHandler = () => { + return []; + }; + + const successHandler = currentClassName => { + if ((currentClassName == null)) { return []; } + + const nestedSuccessHandler = classInfo => { + const intentions = []; + + if (!classInfo) { return intentions; } + + if (!(name in classInfo.properties)) { + intentions.push({ + priority : 100, + icon : 'gear', + title : 'Introduce New Property', + + selected : () => { + return this.introducePropertyFor(editor, classInfo, name); + } + }); } - }]; - } - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - * @param {String} name - */ - getIntentions(editor, triggerPosition, name) { - const failureHandler = () => { - return []; + return intentions; }; - const successHandler = currentClassName => { - if ((currentClassName == null)) { return []; } - - const nestedSuccessHandler = classInfo => { - const intentions = []; + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + }; - if (!classInfo) { return intentions; } - - if (!(name in classInfo.properties)) { - intentions.push({ - priority : 100, - icon : 'gear', - title : 'Introduce New Property', - - selected : () => { - return this.introducePropertyFor(editor, classInfo, name); - } - }); - } + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } - return intentions; - }; + /** + * @param {TextEditor} editor + * @param {Object} classData + * @param {String} name + */ + introducePropertyFor(editor, classData, name) { + const indentationLevel = editor.indentationForBufferRow(classData.range.start.line) + 1; - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); - }; + const tabText = editor.getTabText().repeat(indentationLevel); - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } + const docblock = this.docblockBuilder.buildForProperty( + 'mixed', + false, + tabText + ); - /** - * @param {TextEditor} editor - * @param {Object} classData - * @param {String} name - */ - introducePropertyFor(editor, classData, name) { - const indentationLevel = editor.indentationForBufferRow(classData.range.start.line) + 1; + const property = `${tabText}protected $${name};\n\n`; - const tabText = editor.getTabText().repeat(indentationLevel); + const point = this.findLocationToInsertProperty(editor, classData); - const docblock = this.docblockBuilder.buildForProperty( - 'mixed', - false, - tabText - ); + return editor.getBuffer().insert(point, docblock + property); + } - const property = `${tabText}protected $${name};\n\n`; - const point = this.findLocationToInsertProperty(editor, classData); + /** + * @param {TextEditor} editor + * @param {Object} classData + * + * @return {Point} + */ + findLocationToInsertProperty(editor, classData) { + let startLine = null; - return editor.getBuffer().insert(point, docblock + property); + // Try to place the new property underneath the existing properties. + for (let name in classData.properties) { + const propertyData = classData.properties[name]; + if (propertyData.declaringStructure.name === classData.name) { + startLine = propertyData.range.end.line + 2; + } } + if ((startLine == null)) { + // Ensure we don't end up somewhere in the middle of the class definition if it spans multiple lines. + const lineCount = editor.getLineCount(); - /** - * @param {TextEditor} editor - * @param {Object} classData - * - * @return {Point} - */ - findLocationToInsertProperty(editor, classData) { - let startLine = null; - - // Try to place the new property underneath the existing properties. - for (let name in classData.properties) { - const propertyData = classData.properties[name]; - if (propertyData.declaringStructure.name === classData.name) { - startLine = propertyData.range.end.line + 2; - } - } + for ( + let line = (classData.range.start.line + 1), + end = lineCount, + asc = (classData.range.start.line + 1) <= end; + asc ? line <= end : line >= end; + asc ? line++ : line-- + ) { + const lineText = editor.lineTextForBufferRow(line); - if ((startLine == null)) { - // Ensure we don't end up somewhere in the middle of the class definition if it spans multiple lines. - const lineCount = editor.getLineCount(); + if ((lineText == null)) { continue; } for ( - let line = (classData.range.start.line + 1), - end = lineCount, - asc = (classData.range.start.line + 1) <= end; - asc ? line <= end : line >= end; - asc ? line++ : line-- + let i = 0, end1 = lineText.length - 1, asc1 = 0 <= end1; + asc1 ? i <= end1 : i >= end1; + asc1 ? i++ : i-- ) { - const lineText = editor.lineTextForBufferRow(line); - - if ((lineText == null)) { continue; } - - for ( - let i = 0, end1 = lineText.length - 1, asc1 = 0 <= end1; - asc1 ? i <= end1 : i >= end1; - asc1 ? i++ : i-- - ) { - if (lineText[i] === '{') { - startLine = line + 1; - break; - } + if (lineText[i] === '{') { + startLine = line + 1; + break; } - - if (startLine != null) { break; } } - } - if ((startLine == null)) { - startLine = classData.range.start.line + 2; + if (startLine != null) { break; } } + } - return new Point(startLine, -1); + if ((startLine == null)) { + startLine = classData.range.start.line + 2; } - }; - IntroducePropertyProvider.initClass(); - return IntroducePropertyProvider; -})()); + + return new Point(startLine, -1); + } +}; diff --git a/lib/Refactoring/OverrideMethodProvider.js b/lib/Refactoring/OverrideMethodProvider.js index afa5445e..ad382260 100644 --- a/lib/Refactoring/OverrideMethodProvider.js +++ b/lib/Refactoring/OverrideMethodProvider.js @@ -7,7 +7,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let OverrideMethodProvider; const AbstractProvider = require('./AbstractProvider'); module.exports = @@ -15,258 +14,249 @@ module.exports = //#* // Provides the ability to implement interface methods. //# -(OverrideMethodProvider = (function() { - OverrideMethodProvider = class OverrideMethodProvider extends AbstractProvider { - static initClass() { - /** - * The view that allows the user to select the properties to generate for. - */ - this.prototype.selectionView = null; - - /** - * @type {Object} - */ - this.prototype.docblockBuilder = null; - - /** - * @type {Object} - */ - this.prototype.functionBuilder = null; - } +class OverrideMethodProvider extends AbstractProvider { + /** + * @param {Object} docblockBuilder + * @param {Object} functionBuilder + */ + constructor(docblockBuilder, functionBuilder) { + super(); /** - * @param {Object} docblockBuilder - * @param {Object} functionBuilder + * The view that allows the user to select the properties to generate for. */ - constructor(docblockBuilder, functionBuilder) { - super(); - - this.docblockBuilder = docblockBuilder; - this.functionBuilder = functionBuilder; - } + this.selectionView = null; /** - * @inheritdoc + * @type {Object} */ - deactivate() { - super.deactivate(); - - if (this.selectionView) { - this.selectionView.destroy(); - return this.selectionView = null; - } - } + this.docblockBuilder = docblockBuilder; /** - * @inheritdoc + * @type {Object} */ - getIntentionProviders() { - return [{ - grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - - return this.getStubInterfaceMethodIntentions(textEditor, bufferPosition); - } - }]; + this.functionBuilder = functionBuilder; + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.selectionView) { + this.selectionView.destroy(); + return this.selectionView = null; } + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['source.php'], + getIntentions: ({textEditor, bufferPosition}) => { + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + + return this.getStubInterfaceMethodIntentions(textEditor, bufferPosition); + } + }]; + } - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - getStubInterfaceMethodIntentions(editor, triggerPosition) { - const failureHandler = () => []; + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + getStubInterfaceMethodIntentions(editor, triggerPosition) { + const failureHandler = () => []; - const successHandler = currentClassName => { - if (!currentClassName) { return []; } + const successHandler = currentClassName => { + if (!currentClassName) { return []; } - const nestedSuccessHandler = classInfo => { - if (!classInfo) { return []; } + const nestedSuccessHandler = classInfo => { + if (!classInfo) { return []; } - const items = []; + const items = []; - for (let name in classInfo.methods) { - const method = classInfo.methods[name]; - const data = { - name, - method - }; + for (let name in classInfo.methods) { + const method = classInfo.methods[name]; + const data = { + name, + method + }; - // Interface methods can already be stubbed via StubInterfaceMethodProvider. - if (method.declaringStructure.type === 'interface') { continue; } + // Interface methods can already be stubbed via StubInterfaceMethodProvider. + if (method.declaringStructure.type === 'interface') { continue; } - // Abstract methods can already be stubbed via StubAbstractMethodProvider. - if (method.isAbstract) { continue; } + // Abstract methods can already be stubbed via StubAbstractMethodProvider. + if (method.isAbstract) { continue; } - if (method.declaringStructure.name !== classInfo.name) { - items.push(data); - } + if (method.declaringStructure.name !== classInfo.name) { + items.push(data); } + } - if (items.length === 0) { return []; } + if (items.length === 0) { return []; } - this.getSelectionView().setItems(items); + this.getSelectionView().setItems(items); - return [ - { - priority : 100, - icon : 'link', - title : 'Override Method(s)', + return [ + { + priority : 100, + icon : 'link', + title : 'Override Method(s)', - selected : () => { - return this.executeStubInterfaceMethods(editor); - } + selected : () => { + return this.executeStubInterfaceMethods(editor); } - ]; - }; - - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + } + ]; }; - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } - - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - executeStubInterfaceMethods(editor) { - this.getSelectionView().setMetadata({editor}); - this.getSelectionView().storeFocusedElement(); - return this.getSelectionView().present(); - } - - /** - * Called when the selection of properties is cancelled. - */ - onCancel(metadata) {} - - /** - * Called when the selection of properties is confirmed. - * - * @param {array} selectedItems - * @param {Object|null} metadata - */ - async onConfirm(selectedItems, metadata) { - const itemOutputs = []; - - const tabText = metadata.editor.getTabText(); - const editorUri = 'file://' + metadata.editor.getPath(); - const bufferPosition = metadata.editor.getCursorBufferPosition(); - const indentationLevel = metadata.editor.indentationForBufferRow(bufferPosition.row); - const maxLineLength = atom.config.get( - 'editor.preferredLineLength', - metadata.editor.getLastCursor().getScopeDescriptor() + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + }; + + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + executeStubInterfaceMethods(editor) { + this.getSelectionView().setMetadata({editor}); + this.getSelectionView().storeFocusedElement(); + return this.getSelectionView().present(); + } + + /** + * Called when the selection of properties is cancelled. + */ + onCancel(metadata) {} + + /** + * Called when the selection of properties is confirmed. + * + * @param {array} selectedItems + * @param {Object|null} metadata + */ + async onConfirm(selectedItems, metadata) { + const itemOutputs = []; + + const tabText = metadata.editor.getTabText(); + const editorUri = 'file://' + metadata.editor.getPath(); + const bufferPosition = metadata.editor.getCursorBufferPosition(); + const indentationLevel = metadata.editor.indentationForBufferRow(bufferPosition.row); + const maxLineLength = atom.config.get( + 'editor.preferredLineLength', + metadata.editor.getLastCursor().getScopeDescriptor() + ); + + for (const item of selectedItems) { + const stub = await this.generateStubForInterfaceMethod( + item.method, + tabText, + indentationLevel, + maxLineLength, + editorUri, + bufferPosition ); - for (const item of selectedItems) { - const stub = await this.generateStubForInterfaceMethod( - item.method, - tabText, - indentationLevel, - maxLineLength, - editorUri, - bufferPosition - ); - - itemOutputs.push(stub); - } - - const output = itemOutputs.join('\n').trim(); - - return metadata.editor.insertText(output); + itemOutputs.push(stub); } - /** - * Generates an override for the specified selected data. - * - * @param {Object} data - * @param {String} tabText - * @param {Number} indentationLevel - * @param {Number} maxLineLength - * @param {String} editorUri - * @param {Position} bufferPosition - * - * @return {Promise} - */ - async generateStubForInterfaceMethod( - data, - tabText, - indentationLevel, - maxLineLength, - editorUri, - bufferPosition - ) { - const parameterNames = data.parameters.map(item => `$${item.name}`); - - const hasReturnValue = this.hasReturnValue(data); - - let parentCallStatement = ''; - - if (hasReturnValue) { - parentCallStatement += '$value = '; - } - - parentCallStatement += `parent::${data.name}(`; - parentCallStatement += parameterNames.join(', '); - parentCallStatement += ');'; - - const statements = [ - parentCallStatement, - '', - '// TODO' - ]; - - if (hasReturnValue) { - statements.push(''); - statements.push('return $value;'); - } - - await this.localizeFunctionParameterTypeHints(data.parameters, editorUri, bufferPosition); + const output = itemOutputs.join('\n').trim(); + + return metadata.editor.insertText(output); + } + + /** + * Generates an override for the specified selected data. + * + * @param {Object} data + * @param {String} tabText + * @param {Number} indentationLevel + * @param {Number} maxLineLength + * @param {String} editorUri + * @param {Position} bufferPosition + * + * @return {Promise} + */ + async generateStubForInterfaceMethod( + data, + tabText, + indentationLevel, + maxLineLength, + editorUri, + bufferPosition + ) { + const parameterNames = data.parameters.map(item => `$${item.name}`); + + const hasReturnValue = this.hasReturnValue(data); + + let parentCallStatement = ''; + + if (hasReturnValue) { + parentCallStatement += '$value = '; + } - const functionText = this.functionBuilder - .setFromRawMethodData(data) - .setIsAbstract(false) - .setStatements(statements) - .setTabText(tabText) - .setIndentationLevel(indentationLevel) - .setMaxLineLength(maxLineLength) - .build(); + parentCallStatement += `parent::${data.name}(`; + parentCallStatement += parameterNames.join(', '); + parentCallStatement += ');'; - const docblockText = this.docblockBuilder.buildByLines(['@inheritDoc'], tabText.repeat(indentationLevel)); + const statements = [ + parentCallStatement, + '', + '// TODO' + ]; - return docblockText + functionText; + if (hasReturnValue) { + statements.push(''); + statements.push('return $value;'); } - /** - * @param {Object} data - * - * @return {Boolean} - */ - hasReturnValue(data) { - if (data.name === '__construct') { return false; } - if (data.returnTypes.length === 0) { return false; } - if ((data.returnTypes.length === 1) && (data.returnTypes[0].type === 'void')) { return false; } - - return true; + await this.localizeFunctionParameterTypeHints(data.parameters, editorUri, bufferPosition); + + const functionText = this.functionBuilder + .setFromRawMethodData(data) + .setIsAbstract(false) + .setStatements(statements) + .setTabText(tabText) + .setIndentationLevel(indentationLevel) + .setMaxLineLength(maxLineLength) + .build(); + + const docblockText = this.docblockBuilder.buildByLines(['@inheritDoc'], tabText.repeat(indentationLevel)); + + return docblockText + functionText; + } + + /** + * @param {Object} data + * + * @return {Boolean} + */ + hasReturnValue(data) { + if (data.name === '__construct') { return false; } + if (data.returnTypes.length === 0) { return false; } + if ((data.returnTypes.length === 1) && (data.returnTypes[0].type === 'void')) { return false; } + + return true; + } + + /** + * @return {Builder} + */ + getSelectionView() { + if ((this.selectionView == null)) { + const View = require('./OverrideMethodProvider/View'); + + this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); + this.selectionView.setLoading('Loading class information...'); + this.selectionView.setEmptyMessage('No overridable methods found.'); } - /** - * @return {Builder} - */ - getSelectionView() { - if ((this.selectionView == null)) { - const View = require('./OverrideMethodProvider/View'); - - this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); - this.selectionView.setLoading('Loading class information...'); - this.selectionView.setEmptyMessage('No overridable methods found.'); - } - - return this.selectionView; - } - }; - OverrideMethodProvider.initClass(); - return OverrideMethodProvider; -})()); + return this.selectionView; + } +}; diff --git a/lib/Refactoring/OverrideMethodProvider/View.js b/lib/Refactoring/OverrideMethodProvider/View.js index c26edfa2..3c7c1bee 100644 --- a/lib/Refactoring/OverrideMethodProvider/View.js +++ b/lib/Refactoring/OverrideMethodProvider/View.js @@ -3,20 +3,16 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let View; -const {$, $$, SelectListView} = require('atom-space-pen-views'); +const {$, $$} = require('atom-space-pen-views'); const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -//#* -// An extension on SelectListView from atom-space-pen-views that allows multiple selections. -//# -(View = class View extends MultiSelectionView { +class View extends MultiSelectionView { /** * @inheritdoc - */ + */ createWidgets() { const checkboxBar = $$(function() { return this.div({class: 'checkbox-bar settings-view'}, () => { @@ -50,4 +46,4 @@ module.exports = return this.onDidConfirm(this.selectedItems, this.getMetadata()); } } -}); +}; diff --git a/lib/Refactoring/StubAbstractMethodProvider.js b/lib/Refactoring/StubAbstractMethodProvider.js index eb3221e8..41c7618b 100644 --- a/lib/Refactoring/StubAbstractMethodProvider.js +++ b/lib/Refactoring/StubAbstractMethodProvider.js @@ -7,7 +7,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let StubAbstractMethodProvider; const AbstractProvider = require('./AbstractProvider'); module.exports = @@ -15,218 +14,209 @@ module.exports = //#* // Provides the ability to stub abstract methods. //# -(StubAbstractMethodProvider = (function() { - StubAbstractMethodProvider = class StubAbstractMethodProvider extends AbstractProvider { - static initClass() { - /** - * The view that allows the user to select the properties to generate for. - */ - this.prototype.selectionView = null; - - /** - * @type {Object} - */ - this.prototype.docblockBuilder = null; - - /** - * @type {Object} - */ - this.prototype.functionBuilder = null; - } +class StubAbstractMethodProvider extends AbstractProvider { + /** + * @param {Object} docblockBuilder + * @param {Object} functionBuilder + */ + constructor(docblockBuilder, functionBuilder) { + super(); /** - * @param {Object} docblockBuilder - * @param {Object} functionBuilder + * The view that allows the user to select the properties to generate for. */ - constructor(docblockBuilder, functionBuilder) { - super(); - - this.docblockBuilder = docblockBuilder; - this.functionBuilder = functionBuilder; - } + this.prototype.selectionView = null; /** - * @inheritdoc + * @type {Object} */ - deactivate() { - super.deactivate(); - - if (this.selectionView) { - this.selectionView.destroy(); - return this.selectionView = null; - } - } + this.prototype.docblockBuilder = docblockBuilder; /** - * @inheritdoc + * @type {Object} */ - getIntentionProviders() { - return [{ - grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - - return this.getStubInterfaceMethodIntentions(textEditor, bufferPosition); - } - }]; + this.prototype.functionBuilder = functionBuilder; + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.selectionView) { + this.selectionView.destroy(); + return this.selectionView = null; } + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['source.php'], + getIntentions: ({textEditor, bufferPosition}) => { + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + + return this.getStubInterfaceMethodIntentions(textEditor, bufferPosition); + } + }]; + } - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - getStubInterfaceMethodIntentions(editor, triggerPosition) { - const failureHandler = () => []; + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + getStubInterfaceMethodIntentions(editor, triggerPosition) { + const failureHandler = () => []; - const successHandler = currentClassName => { - if (!currentClassName) { return []; } + const successHandler = currentClassName => { + if (!currentClassName) { return []; } - const nestedSuccessHandler = classInfo => { - if (!classInfo) { return []; } + const nestedSuccessHandler = classInfo => { + if (!classInfo) { return []; } - const items = []; + const items = []; - for (let name in classInfo.methods) { - const method = classInfo.methods[name]; - const data = { - name, - method - }; + for (let name in classInfo.methods) { + const method = classInfo.methods[name]; + const data = { + name, + method + }; - if (method.isAbstract) { - items.push(data); - } + if (method.isAbstract) { + items.push(data); } + } - if (items.length === 0) { return []; } + if (items.length === 0) { return []; } - this.getSelectionView().setItems(items); + this.getSelectionView().setItems(items); - return [ - { - priority : 100, - icon : 'link', - title : 'Stub Unimplemented Abstract Method(s)', + return [ + { + priority : 100, + icon : 'link', + title : 'Stub Unimplemented Abstract Method(s)', - selected : () => { - return this.executeStubInterfaceMethods(editor); - } + selected : () => { + return this.executeStubInterfaceMethods(editor); } - ]; - }; - - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + } + ]; }; - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } - - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - executeStubInterfaceMethods(editor) { - this.getSelectionView().setMetadata({editor}); - this.getSelectionView().storeFocusedElement(); - return this.getSelectionView().present(); - } - - /** - * Called when the selection of properties is cancelled. - */ - onCancel(metadata) {} - - /** - * Called when the selection of properties is confirmed. - * - * @param {array} selectedItems - * @param {Object|null} metadata - */ - async onConfirm(selectedItems, metadata) { - const itemOutputs = []; - - const tabText = metadata.editor.getTabText(); - const editorUri = 'file://' + metadata.editor.getPath(); - const bufferPosition = metadata.editor.getCursorBufferPosition(); - const indentationLevel = metadata.editor.indentationForBufferRow(bufferPosition.row); - const maxLineLength = atom.config.get( - 'editor.preferredLineLength', - metadata.editor.getLastCursor().getScopeDescriptor() + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + }; + + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + executeStubInterfaceMethods(editor) { + this.getSelectionView().setMetadata({editor}); + this.getSelectionView().storeFocusedElement(); + return this.getSelectionView().present(); + } + + /** + * Called when the selection of properties is cancelled. + */ + onCancel(metadata) {} + + /** + * Called when the selection of properties is confirmed. + * + * @param {array} selectedItems + * @param {Object|null} metadata + */ + async onConfirm(selectedItems, metadata) { + const itemOutputs = []; + + const tabText = metadata.editor.getTabText(); + const editorUri = 'file://' + metadata.editor.getPath(); + const bufferPosition = metadata.editor.getCursorBufferPosition(); + const indentationLevel = metadata.editor.indentationForBufferRow(bufferPosition.row); + const maxLineLength = atom.config.get( + 'editor.preferredLineLength', + metadata.editor.getLastCursor().getScopeDescriptor() + ); + + for (const item of selectedItems) { + const stub = await this.generateStubForInterfaceMethod( + item.method, + tabText, + indentationLevel, + maxLineLength, + editorUri, + bufferPosition ); - for (const item of selectedItems) { - const stub = await this.generateStubForInterfaceMethod( - item.method, - tabText, - indentationLevel, - maxLineLength, - editorUri, - bufferPosition - ); - - itemOutputs.push(stub); - } - - const output = itemOutputs.join('\n').trim(); - - return metadata.editor.insertText(output); + itemOutputs.push(stub); } - /** - * Generates a stub for the specified selected data. - * - * @param {Object} data - * @param {String} tabText - * @param {Number} indentationLevel - * @param {Number} maxLineLength - * @param {String} editorUri - * @param {Position} bufferPosition - * - * @return {string} - */ - async generateStubForInterfaceMethod( - data, - tabText, - indentationLevel, - maxLineLength, - editorUri, - bufferPosition - ) { - const statements = [ - 'throw new \\LogicException(\'Not implemented\'); // TODO' - ]; - - await this.localizeFunctionParameterTypeHints(data.parameters, editorUri, bufferPosition); - - const functionText = this.functionBuilder - .setFromRawMethodData(data) - .setIsAbstract(false) - .setStatements(statements) - .setTabText(tabText) - .setIndentationLevel(indentationLevel) - .setMaxLineLength(maxLineLength) - .build(); - - const docblockText = this.docblockBuilder.buildByLines(['@inheritDoc'], tabText.repeat(indentationLevel)); - - return docblockText + functionText; + const output = itemOutputs.join('\n').trim(); + + return metadata.editor.insertText(output); + } + + /** + * Generates a stub for the specified selected data. + * + * @param {Object} data + * @param {String} tabText + * @param {Number} indentationLevel + * @param {Number} maxLineLength + * @param {String} editorUri + * @param {Position} bufferPosition + * + * @return {string} + */ + async generateStubForInterfaceMethod( + data, + tabText, + indentationLevel, + maxLineLength, + editorUri, + bufferPosition + ) { + const statements = [ + 'throw new \\LogicException(\'Not implemented\'); // TODO' + ]; + + await this.localizeFunctionParameterTypeHints(data.parameters, editorUri, bufferPosition); + + const functionText = this.functionBuilder + .setFromRawMethodData(data) + .setIsAbstract(false) + .setStatements(statements) + .setTabText(tabText) + .setIndentationLevel(indentationLevel) + .setMaxLineLength(maxLineLength) + .build(); + + const docblockText = this.docblockBuilder.buildByLines(['@inheritDoc'], tabText.repeat(indentationLevel)); + + return docblockText + functionText; + } + + /** + * @return {Builder} + */ + getSelectionView() { + if ((this.selectionView == null)) { + const View = require('./StubAbstractMethodProvider/View'); + + this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); + this.selectionView.setLoading('Loading class information...'); + this.selectionView.setEmptyMessage('No unimplemented abstract methods found.'); } - /** - * @return {Builder} - */ - getSelectionView() { - if ((this.selectionView == null)) { - const View = require('./StubAbstractMethodProvider/View'); - - this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); - this.selectionView.setLoading('Loading class information...'); - this.selectionView.setEmptyMessage('No unimplemented abstract methods found.'); - } - - return this.selectionView; - } - }; - StubAbstractMethodProvider.initClass(); - return StubAbstractMethodProvider; -})()); + return this.selectionView; + } +}; diff --git a/lib/Refactoring/StubAbstractMethodProvider/View.js b/lib/Refactoring/StubAbstractMethodProvider/View.js index c26edfa2..41729b47 100644 --- a/lib/Refactoring/StubAbstractMethodProvider/View.js +++ b/lib/Refactoring/StubAbstractMethodProvider/View.js @@ -3,20 +3,16 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let View; -const {$, $$, SelectListView} = require('atom-space-pen-views'); +const {$, $$} = require('atom-space-pen-views'); const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -//#* -// An extension on SelectListView from atom-space-pen-views that allows multiple selections. -//# -(View = class View extends MultiSelectionView { +class View extends MultiSelectionView { /** * @inheritdoc - */ + */ createWidgets() { const checkboxBar = $$(function() { return this.div({class: 'checkbox-bar settings-view'}, () => { @@ -44,10 +40,10 @@ module.exports = /** * @inheritdoc - */ + */ invokeOnDidConfirm() { if (this.onDidConfirm) { return this.onDidConfirm(this.selectedItems, this.getMetadata()); } } -}); +}; diff --git a/lib/Refactoring/StubInterfaceMethodProvider.js b/lib/Refactoring/StubInterfaceMethodProvider.js index 093f8f4b..343cf0cd 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider.js +++ b/lib/Refactoring/StubInterfaceMethodProvider.js @@ -7,7 +7,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let StubInterfaceMethodProvider; const AbstractProvider = require('./AbstractProvider'); module.exports = @@ -15,220 +14,211 @@ module.exports = //#* // Provides the ability to stub interface methods. //# -(StubInterfaceMethodProvider = (function() { - StubInterfaceMethodProvider = class StubInterfaceMethodProvider extends AbstractProvider { - static initClass() { - /** - * The view that allows the user to select the properties to generate for. - */ - this.prototype.selectionView = null; - - /** - * @type {Object} - */ - this.prototype.docblockBuilder = null; - - /** - * @type {Object} - */ - this.prototype.functionBuilder = null; - } +class StubInterfaceMethodProvider extends AbstractProvider { + /** + * @param {Object} docblockBuilder + * @param {Object} functionBuilder + */ + constructor(docblockBuilder, functionBuilder) { + super(); /** - * @param {Object} docblockBuilder - * @param {Object} functionBuilder + * The view that allows the user to select the properties to generate for. */ - constructor(docblockBuilder, functionBuilder) { - super(); - - this.docblockBuilder = docblockBuilder; - this.functionBuilder = functionBuilder; - } + this.prototype.selectionView = null; /** - * @inheritdoc + * @type {Object} */ - deactivate() { - super.deactivate(); - - if (this.selectionView) { - this.selectionView.destroy(); - return this.selectionView = null; - } - } + this.prototype.docblockBuilder = docblockBuilder; /** - * @inheritdoc + * @type {Object} */ - getIntentionProviders() { - return [{ - grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { - if ((this.getCurrentProjectPhpVersion() == null)) { return []; } - - return this.getStubInterfaceMethodIntentions(textEditor, bufferPosition); - } - }]; + this.prototype.functionBuilder = functionBuilder; + } + + /** + * @inheritdoc + */ + deactivate() { + super.deactivate(); + + if (this.selectionView) { + this.selectionView.destroy(); + return this.selectionView = null; } - - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - getStubInterfaceMethodIntentions(editor, triggerPosition) { - const failureHandler = () => []; - - const successHandler = currentClassName => { - if (!currentClassName) { return []; } - - const nestedSuccessHandler = classInfo => { - if (!classInfo) { return []; } - - const items = []; - - for (let name in classInfo.methods) { - const method = classInfo.methods[name]; - const data = { - name, - method - }; - - if ( - (method.declaringStructure.type === 'interface') && - ((method.implementations != null ? method.implementations.length : undefined) === 0) - ) { - items.push(data); - } + } + + /** + * @inheritdoc + */ + getIntentionProviders() { + return [{ + grammarScopes: ['source.php'], + getIntentions: ({textEditor, bufferPosition}) => { + if ((this.getCurrentProjectPhpVersion() == null)) { return []; } + + return this.getStubInterfaceMethodIntentions(textEditor, bufferPosition); + } + }]; + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + getStubInterfaceMethodIntentions(editor, triggerPosition) { + const failureHandler = () => []; + + const successHandler = currentClassName => { + if (!currentClassName) { return []; } + + const nestedSuccessHandler = classInfo => { + if (!classInfo) { return []; } + + const items = []; + + for (let name in classInfo.methods) { + const method = classInfo.methods[name]; + const data = { + name, + method + }; + + if ( + (method.declaringStructure.type === 'interface') && + ((method.implementations != null ? method.implementations.length : undefined) === 0) + ) { + items.push(data); } + } - if (items.length === 0) { return []; } + if (items.length === 0) { return []; } - this.getSelectionView().setItems(items); + this.getSelectionView().setItems(items); - return [ - { - priority : 100, - icon : 'link', - title : 'Stub Unimplemented Interface Method(s)', + return [ + { + priority : 100, + icon : 'link', + title : 'Stub Unimplemented Interface Method(s)', - selected : () => { - return this.executeStubInterfaceMethods(editor); - } + selected : () => { + return this.executeStubInterfaceMethods(editor); } - ]; - }; - - return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + } + ]; }; - return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); - } - - /** - * @param {TextEditor} editor - * @param {Point} triggerPosition - */ - executeStubInterfaceMethods(editor) { - this.getSelectionView().setMetadata({editor}); - this.getSelectionView().storeFocusedElement(); - return this.getSelectionView().present(); - } - - /** - * Called when the selection of properties is cancelled. - */ - onCancel(metadata) {} - - /** - * Called when the selection of properties is confirmed. - * - * @param {array} selectedItems - * @param {Object|null} metadata - */ - async onConfirm(selectedItems, metadata) { - const itemOutputs = []; - - const tabText = metadata.editor.getTabText(); - const editorUri = 'file://' + metadata.editor.getPath(); - const bufferPosition = metadata.editor.getCursorBufferPosition(); - const indentationLevel = metadata.editor.indentationForBufferRow(bufferPosition.row); - const maxLineLength = atom.config.get( - 'editor.preferredLineLength', - metadata.editor.getLastCursor().getScopeDescriptor() + return this.service.getClassInfo(currentClassName).then(nestedSuccessHandler, failureHandler); + }; + + return this.service.determineCurrentClassName(editor, triggerPosition).then(successHandler, failureHandler); + } + + /** + * @param {TextEditor} editor + * @param {Point} triggerPosition + */ + executeStubInterfaceMethods(editor) { + this.getSelectionView().setMetadata({editor}); + this.getSelectionView().storeFocusedElement(); + return this.getSelectionView().present(); + } + + /** + * Called when the selection of properties is cancelled. + */ + onCancel(metadata) {} + + /** + * Called when the selection of properties is confirmed. + * + * @param {array} selectedItems + * @param {Object|null} metadata + */ + async onConfirm(selectedItems, metadata) { + const itemOutputs = []; + + const tabText = metadata.editor.getTabText(); + const editorUri = 'file://' + metadata.editor.getPath(); + const bufferPosition = metadata.editor.getCursorBufferPosition(); + const indentationLevel = metadata.editor.indentationForBufferRow(bufferPosition.row); + const maxLineLength = atom.config.get( + 'editor.preferredLineLength', + metadata.editor.getLastCursor().getScopeDescriptor() + ); + + for (const item of selectedItems) { + const stub = await this.generateStubForInterfaceMethod( + item.method, + tabText, + indentationLevel, + maxLineLength, + editorUri, + bufferPosition ); - for (const item of selectedItems) { - const stub = await this.generateStubForInterfaceMethod( - item.method, - tabText, - indentationLevel, - maxLineLength, - editorUri, - bufferPosition - ); - - itemOutputs.push(stub); - } - - const output = itemOutputs.join('\n').trim(); - - return metadata.editor.insertText(output); + itemOutputs.push(stub); } - /** - * Generates a stub for the specified selected data. - * - * @param {Object} data - * @param {String} tabText - * @param {Number} indentationLevel - * @param {Number} maxLineLength - * @param {String} editorUri - * @param {Position} bufferPosition - * - * @return {string} - */ - async generateStubForInterfaceMethod( - data, - tabText, - indentationLevel, - maxLineLength, - editorUri, - bufferPosition - ) { - const statements = [ - 'throw new \\LogicException(\'Not implemented\'); // TODO' - ]; - - await this.localizeFunctionParameterTypeHints(data.parameters, editorUri, bufferPosition); - - const functionText = this.functionBuilder - .setFromRawMethodData(data) - .setStatements(statements) - .setTabText(tabText) - .setIndentationLevel(indentationLevel) - .setMaxLineLength(maxLineLength) - .build(); - - const docblockText = this.docblockBuilder.buildByLines(['@inheritDoc'], tabText.repeat(indentationLevel)); - - return docblockText + functionText; + const output = itemOutputs.join('\n').trim(); + + return metadata.editor.insertText(output); + } + + /** + * Generates a stub for the specified selected data. + * + * @param {Object} data + * @param {String} tabText + * @param {Number} indentationLevel + * @param {Number} maxLineLength + * @param {String} editorUri + * @param {Position} bufferPosition + * + * @return {string} + */ + async generateStubForInterfaceMethod( + data, + tabText, + indentationLevel, + maxLineLength, + editorUri, + bufferPosition + ) { + const statements = [ + 'throw new \\LogicException(\'Not implemented\'); // TODO' + ]; + + await this.localizeFunctionParameterTypeHints(data.parameters, editorUri, bufferPosition); + + const functionText = this.functionBuilder + .setFromRawMethodData(data) + .setStatements(statements) + .setTabText(tabText) + .setIndentationLevel(indentationLevel) + .setMaxLineLength(maxLineLength) + .build(); + + const docblockText = this.docblockBuilder.buildByLines(['@inheritDoc'], tabText.repeat(indentationLevel)); + + return docblockText + functionText; + } + + /** + * @return {Builder} + */ + getSelectionView() { + if ((this.selectionView == null)) { + const View = require('./StubInterfaceMethodProvider/View'); + + this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); + this.selectionView.setLoading('Loading class information...'); + this.selectionView.setEmptyMessage('No unimplemented interface methods found.'); } - /** - * @return {Builder} - */ - getSelectionView() { - if ((this.selectionView == null)) { - const View = require('./StubInterfaceMethodProvider/View'); - - this.selectionView = new View(this.onConfirm.bind(this), this.onCancel.bind(this)); - this.selectionView.setLoading('Loading class information...'); - this.selectionView.setEmptyMessage('No unimplemented interface methods found.'); - } - - return this.selectionView; - } - }; - StubInterfaceMethodProvider.initClass(); - return StubInterfaceMethodProvider; -})()); + return this.selectionView; + } +}; diff --git a/lib/Refactoring/StubInterfaceMethodProvider/View.js b/lib/Refactoring/StubInterfaceMethodProvider/View.js index c26edfa2..41729b47 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider/View.js +++ b/lib/Refactoring/StubInterfaceMethodProvider/View.js @@ -3,20 +3,16 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let View; -const {$, $$, SelectListView} = require('atom-space-pen-views'); +const {$, $$} = require('atom-space-pen-views'); const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -//#* -// An extension on SelectListView from atom-space-pen-views that allows multiple selections. -//# -(View = class View extends MultiSelectionView { +class View extends MultiSelectionView { /** * @inheritdoc - */ + */ createWidgets() { const checkboxBar = $$(function() { return this.div({class: 'checkbox-bar settings-view'}, () => { @@ -44,10 +40,10 @@ module.exports = /** * @inheritdoc - */ + */ invokeOnDidConfirm() { if (this.onDidConfirm) { return this.onDidConfirm(this.selectedItems, this.getMetadata()); } } -}); +}; diff --git a/lib/Refactoring/Utility/DocblockBuilder.js b/lib/Refactoring/Utility/DocblockBuilder.js index 8bab28c7..a50c91b2 100644 --- a/lib/Refactoring/Utility/DocblockBuilder.js +++ b/lib/Refactoring/Utility/DocblockBuilder.js @@ -4,10 +4,9 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let DocblockBuilder; module.exports = -(DocblockBuilder = class DocblockBuilder { +class DocblockBuilder { /** * @param {Array} parameters * @param {String|null} returnType @@ -144,4 +143,4 @@ module.exports = if (tabText == null) { tabText = ''; } return `${tabText}${content}\n`; } -}); +}; diff --git a/lib/Refactoring/Utility/FunctionBuilder.js b/lib/Refactoring/Utility/FunctionBuilder.js index 7a6809ba..3d2590ee 100644 --- a/lib/Refactoring/Utility/FunctionBuilder.js +++ b/lib/Refactoring/Utility/FunctionBuilder.js @@ -4,423 +4,411 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let FunctionBuilder; module.exports = -(FunctionBuilder = (function() { - FunctionBuilder = class FunctionBuilder { - static initClass() { - /** - * The access modifier (null if none). - */ - this.prototype.accessModifier = null; - - /** - * Whether the method is static or not. - */ - this.prototype.isStatic = false; - - /** - * Whether the method is abstract or not. - */ - this.prototype.isAbstract = null; - - /** - * The name of the function. - */ - this.prototype.name = null; - - /** - * The return type of the function. This could be set when generating PHP >= 7 methods. - */ - this.prototype.returnType = null; - - /** - * The parameters of the function (a list of objects). - */ - this.prototype.parameters = null; - - /** - * A list of statements to place in the body of the function. - */ - this.prototype.statements = null; - - /** - * The tab text to insert on each line. - */ - this.prototype.tabText = ''; - - /** - * The indentation level. - */ - this.prototype.indentationLevel = null; - - /** - * The indentation level. - * - * @var {Number|null} - */ - this.prototype.maxLineLength = null; - } - +class FunctionBuilder { + constructor() { /** - * Constructor. - */ - constructor() { - this.build = this.build.bind(this); - this.parameters = []; - this.statements = []; - } + * The access modifier (null if none). + */ + this.accessModifier = null; /** - * Makes the method public. - * - * @return {FunctionBuilder} - */ - makePublic() { - this.accessModifier = 'public'; - return this; - } + * Whether the method is static or not. + */ + this.isStatic = false; /** - * Makes the method private. - * - * @return {FunctionBuilder} - */ - makePrivate() { - this.accessModifier = 'private'; - return this; - } + * Whether the method is abstract or not. + */ + this.isAbstract = null; /** - * Makes the method protected. - * - * @return {FunctionBuilder} - */ - makeProtected() { - this.accessModifier = 'protected'; - return this; - } + * The name of the function. + */ + this.name = null; /** - * Makes the method global (i.e. no access modifier is added). - * - * @return {FunctionBuilder} - */ - makeGlobal() { - this.accessModifier = null; - return this; - } + * The return type of the function. This could be set when generating PHP >= 7 methods. + */ + this.returnType = null; /** - * Sets whether the method is static or not. - * - * @param {bool} isStatic - * - * @return {FunctionBuilder} - */ - setIsStatic(isStatic) { - this.isStatic = isStatic; - return this; - } + * The parameters of the function (a list of objects). + */ + this.parameters = []; /** - * Sets whether the method is abstract or not. - * - * @param {bool} isAbstract - * - * @return {FunctionBuilder} - */ - setIsAbstract(isAbstract) { - this.isAbstract = isAbstract; - return this; - } + * A list of statements to place in the body of the function. + */ + this.statements = []; /** - * Sets the name of the function. - * - * @param {String} name - * - * @return {FunctionBuilder} - */ - setName(name) { - this.name = name; - return this; - } + * The tab text to insert on each line. + */ + this.tabText = ''; /** - * Sets the return type. - * - * @param {String|null} returnType - * - * @return {FunctionBuilder} - */ - setReturnType(returnType) { - this.returnType = returnType; - return this; - } + * The indentation level. + */ + this.indentationLevel = null; /** - * Sets the parameters to add. - * - * @param {Array} parameters - * - * @return {FunctionBuilder} - */ - setParameters(parameters) { - this.parameters = parameters; - return this; + * The indentation level. + * + * @var {Number|null} + */ + this.maxLineLength = null; + + this.build = this.build.bind(this); + } + + /** + * Makes the method public. + * + * @return {FunctionBuilder} + */ + makePublic() { + this.accessModifier = 'public'; + return this; + } + + /** + * Makes the method private. + * + * @return {FunctionBuilder} + */ + makePrivate() { + this.accessModifier = 'private'; + return this; + } + + /** + * Makes the method protected. + * + * @return {FunctionBuilder} + */ + makeProtected() { + this.accessModifier = 'protected'; + return this; + } + + /** + * Makes the method global (i.e. no access modifier is added). + * + * @return {FunctionBuilder} + */ + makeGlobal() { + this.accessModifier = null; + return this; + } + + /** + * Sets whether the method is static or not. + * + * @param {bool} isStatic + * + * @return {FunctionBuilder} + */ + setIsStatic(isStatic) { + this.isStatic = isStatic; + return this; + } + + /** + * Sets whether the method is abstract or not. + * + * @param {bool} isAbstract + * + * @return {FunctionBuilder} + */ + setIsAbstract(isAbstract) { + this.isAbstract = isAbstract; + return this; + } + + /** + * Sets the name of the function. + * + * @param {String} name + * + * @return {FunctionBuilder} + */ + setName(name) { + this.name = name; + return this; + } + + /** + * Sets the return type. + * + * @param {String|null} returnType + * + * @return {FunctionBuilder} + */ + setReturnType(returnType) { + this.returnType = returnType; + return this; + } + + /** + * Sets the parameters to add. + * + * @param {Array} parameters + * + * @return {FunctionBuilder} + */ + setParameters(parameters) { + this.parameters = parameters; + return this; + } + + /** + * Adds a parameter to the parameter list. + * + * @param {Object} parameter + * + * @return {FunctionBuilder} + */ + addParameter(parameter) { + this.parameters.push(parameter); + return this; + } + + /** + * Sets the statements to add. + * + * @param {Array} statements + * + * @return {FunctionBuilder} + */ + setStatements(statements) { + this.statements = statements; + return this; + } + + /** + * Adds a statement to the body of the function. + * + * @param {String} statement + * + * @return {FunctionBuilder} + */ + addStatement(statement) { + this.statements.push(statement); + return this; + } + + /** + * Sets the tab text to prepend to each line. + * + * @param {String} tabText + * + * @return {FunctionBuilder} + */ + setTabText(tabText) { + this.tabText = tabText; + return this; + } + + /** + * Sets the indentation level to use. The tab text is repeated this many times for each line. + * + * @param {Number} indentationLevel + * + * @return {FunctionBuilder} + */ + setIndentationLevel(indentationLevel) { + this.indentationLevel = indentationLevel; + return this; + } + + /** + * Sets the maximum length a single line may occupy. After this, text will wrap. + * + * This primarily influences parameter lists, which will automatically be split over multiple lines if the + * parameter list would otherwise exceed the maximum length. + * + * @param {Number|null} maxLineLength The length or null to disable the maximum. + * + * @return {FunctionBuilder} + */ + setMaxLineLength(maxLineLength) { + this.maxLineLength = maxLineLength; + return this; + } + + /** + * Sets the parameters of the builder based on raw method data from the base service. + * + * @param {Object} data + * + * @return {FunctionBuilder} + */ + setFromRawMethodData(data) { + if (data.isPublic) { + this.makePublic(); + + } else if (data.isProtected) { + this.makeProtected(); + + } else if (data.isPrivate) { + this.makePrivate(); + + } else { + this.makeGlobal(); } - /** - * Adds a parameter to the parameter list. - * - * @param {Object} parameter - * - * @return {FunctionBuilder} - */ - addParameter(parameter) { - this.parameters.push(parameter); - return this; + this.setName(data.name); + this.setIsStatic(data.isStatic); + this.setIsAbstract(data.isAbstract); + this.setReturnType(data.returnTypeHint); + + const parameters = []; + + for (const parameter of data.parameters) { + parameters.push({ + name : `$${parameter.name}`, + typeHint : parameter.typeHint, + isVariadic : parameter.isVariadic, + isReference : parameter.isReference, + defaultValue : parameter.defaultValue + }); } - /** - * Sets the statements to add. - * - * @param {Array} statements - * - * @return {FunctionBuilder} - */ - setStatements(statements) { - this.statements = statements; - return this; - } - - /** - * Adds a statement to the body of the function. - * - * @param {String} statement - * - * @return {FunctionBuilder} - */ - addStatement(statement) { - this.statements.push(statement); - return this; - } + this.setParameters(parameters); - /** - * Sets the tab text to prepend to each line. - * - * @param {String} tabText - * - * @return {FunctionBuilder} - */ - setTabText(tabText) { - this.tabText = tabText; - return this; - } + return this; + } - /** - * Sets the indentation level to use. The tab text is repeated this many times for each line. - * - * @param {Number} indentationLevel - * - * @return {FunctionBuilder} - */ - setIndentationLevel(indentationLevel) { - this.indentationLevel = indentationLevel; - return this; - } + /** + * Builds the method using the preconfigured settings. + * + * @return {String} + */ + build() { + let output = ''; - /** - * Sets the maximum length a single line may occupy. After this, text will wrap. - * - * This primarily influences parameter lists, which will automatically be split over multiple lines if the - * parameter list would otherwise exceed the maximum length. - * - * @param {Number|null} maxLineLength The length or null to disable the maximum. - * - * @return {FunctionBuilder} - */ - setMaxLineLength(maxLineLength) { - this.maxLineLength = maxLineLength; - return this; - } + const signature = this.buildSignature(false); - /** - * Sets the parameters of the builder based on raw method data from the base service. - * - * @param {Object} data - * - * @return {FunctionBuilder} - */ - setFromRawMethodData(data) { - if (data.isPublic) { - this.makePublic(); + if ((this.maxLineLength != null) && (signature.length > this.maxLineLength)) { + output += this.buildSignature(true); + output += ' {\n'; - } else if (data.isProtected) { - this.makeProtected(); + } else { + output += signature + '\n'; + output += this.buildLine('{'); + } - } else if (data.isPrivate) { - this.makePrivate(); + for (const statement of this.statements) { + output += this.tabText + this.buildLine(statement); + } - } else { - this.makeGlobal(); - } + output += this.buildLine('}'); - this.setName(data.name); - this.setIsStatic(data.isStatic); - this.setIsAbstract(data.isAbstract); - this.setReturnType(data.returnTypeHint); - - const parameters = []; - - for (const parameter of data.parameters) { - parameters.push({ - name : `$${parameter.name}`, - typeHint : parameter.typeHint, - isVariadic : parameter.isVariadic, - isReference : parameter.isReference, - defaultValue : parameter.defaultValue - }); - } + return output; + } - this.setParameters(parameters); + /** + * @param {Boolean} isMultiLine + * + * @return {String} + */ + buildSignature(isMultiLine) { + let signatureLine = ''; - return this; + if (this.isAbstract) { + signatureLine += 'abstract '; } - /** - * Builds the method using the preconfigured settings. - * - * @return {String} - */ - build() { - let output = ''; - - const signature = this.buildSignature(false); - - if ((this.maxLineLength != null) && (signature.length > this.maxLineLength)) { - output += this.buildSignature(true); - output += ' {\n'; + if (this.accessModifier != null) { + signatureLine += `${this.accessModifier} `; + } - } else { - output += signature + '\n'; - output += this.buildLine('{'); - } + if (this.isStatic) { + signatureLine += 'static '; + } - for (const statement of this.statements) { - output += this.tabText + this.buildLine(statement); - } + signatureLine += `function ${this.name}(`; - output += this.buildLine('}'); + const parameters = []; - return output; - } + for (const parameter of this.parameters) { + let parameterText = ''; - /** - * @param {Boolean} isMultiLine - * - * @return {String} - */ - buildSignature(isMultiLine) { - let signatureLine = ''; - - if (this.isAbstract) { - signatureLine += 'abstract '; + if (parameter.typeHint != null) { + parameterText += `${parameter.typeHint} `; } - if (this.accessModifier != null) { - signatureLine += `${this.accessModifier} `; + if (parameter.isVariadic) { + parameterText += '...'; } - if (this.isStatic) { - signatureLine += 'static '; + if (parameter.isReference) { + parameterText += '&'; } - signatureLine += `function ${this.name}(`; - - const parameters = []; - - for (const parameter of this.parameters) { - let parameterText = ''; - - if (parameter.typeHint != null) { - parameterText += `${parameter.typeHint} `; - } - - if (parameter.isVariadic) { - parameterText += '...'; - } - - if (parameter.isReference) { - parameterText += '&'; - } - - parameterText += `${parameter.name}`; - - if (parameter.defaultValue != null) { - parameterText += ` = ${parameter.defaultValue}`; - } + parameterText += `${parameter.name}`; - parameters.push(parameterText); + if (parameter.defaultValue != null) { + parameterText += ` = ${parameter.defaultValue}`; } - if (!isMultiLine) { - signatureLine += parameters.join(', '); - signatureLine += ')'; + parameters.push(parameterText); + } - signatureLine = this.addTabText(signatureLine); + if (!isMultiLine) { + signatureLine += parameters.join(', '); + signatureLine += ')'; - } else { - signatureLine = this.buildLine(signatureLine); + signatureLine = this.addTabText(signatureLine); - for (let i in parameters) { - let parameter = parameters[i]; + } else { + signatureLine = this.buildLine(signatureLine); - if (i < (parameters.length - 1)) { - parameter += ','; - } + for (let i in parameters) { + let parameter = parameters[i]; - signatureLine += this.buildLine(parameter, this.indentationLevel + 1); + if (i < (parameters.length - 1)) { + parameter += ','; } - signatureLine += this.addTabText(')'); - } - - if (this.returnType != null) { - signatureLine += `: ${this.returnType}`; + signatureLine += this.buildLine(parameter, this.indentationLevel + 1); } - return signatureLine; + signatureLine += this.addTabText(')'); } - /** - * @param {String} content - * @param {Number|null} indentationLevel - * - * @return {String} - */ - buildLine(content, indentationLevel = null) { - return this.addTabText(content, indentationLevel) + '\n'; + if (this.returnType != null) { + signatureLine += `: ${this.returnType}`; } - /** - * @param {String} content - * @param {Number|null} indentationLevel - * - * @return {String} - */ - addTabText(content, indentationLevel = null) { - if ((indentationLevel == null)) { - ({ indentationLevel } = this); - } + return signatureLine; + } + + /** + * @param {String} content + * @param {Number|null} indentationLevel + * + * @return {String} + */ + buildLine(content, indentationLevel = null) { + return this.addTabText(content, indentationLevel) + '\n'; + } + + /** + * @param {String} content + * @param {Number|null} indentationLevel + * + * @return {String} + */ + addTabText(content, indentationLevel = null) { + if ((indentationLevel == null)) { + ({ indentationLevel } = this); + } - const tabText = this.tabText.repeat(indentationLevel); + const tabText = this.tabText.repeat(indentationLevel); - return `${tabText}${content}`; - } - }; - FunctionBuilder.initClass(); - return FunctionBuilder; -})()); + return `${tabText}${content}`; + } +}; diff --git a/lib/Refactoring/Utility/MultiSelectionView.js b/lib/Refactoring/Utility/MultiSelectionView.js index 52693532..ce6c5019 100644 --- a/lib/Refactoring/Utility/MultiSelectionView.js +++ b/lib/Refactoring/Utility/MultiSelectionView.js @@ -7,285 +7,273 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let MultiSelectionView; const {$, $$, SelectListView} = require('atom-space-pen-views'); module.exports = -//#* -// An extension on SelectListView from atom-space-pen-views that allows multiple selections. -//# -(MultiSelectionView = (function() { - MultiSelectionView = class MultiSelectionView extends SelectListView { - static initClass() { - /** - * The callback to invoke when the user confirms his selections. - */ - this.prototype.onDidConfirm = null; - - /** - * The callback to invoke when the user cancels the view. - */ - this.prototype.onDidCancel = null; - - /** - * Metadata to pass to the callbacks. - */ - this.prototype.metadata = null; - - /** - * The message to display when there are no results. - */ - this.prototype.emptyMessage = null; - - /** - * Items that are currently selected. - */ - this.prototype.selectedItems = null; - } +/** + * An extension on SelectListView from atom-space-pen-views that allows multiple selections. + */ +class MultiSelectionView extends SelectListView { + /** + * Constructor. + * + * @param {Callback} onDidConfirm + * @param {Callback} onDidCancel + */ + constructor(onDidConfirm, onDidCancel = null) { + super(); /** - * Constructor. - * - * @param {Callback} onDidConfirm - * @param {Callback} onDidCancel - */ - constructor(onDidConfirm, onDidCancel = null) { - super(); - - this.onDidConfirm = onDidConfirm; - this.onDidCancel = onDidCancel; - - this.selectedItems = []; - } + * The callback to invoke when the user confirms his selections. + */ + this.onDidConfirm = onDidConfirm; /** - * @inheritdoc - */ - initialize() { - super.initialize(); - - this.addClass('php-ide-serenata-refactoring-multi-selection-view'); - this.list.addClass('mark-active'); - - if (this.panel == null) { this.panel = atom.workspace.addModalPanel({item: this, visible: false}); } - - return this.createWidgets(); - } + * The callback to invoke when the user cancels the view. + */ + this.onDidCancel = onDidCancel; /** - * Destroys the view and cleans up. - */ - destroy() { - this.panel.destroy(); - return this.panel = null; - } + * Metadata to pass to the callbacks. + */ + this.metadata = null; /** - * Creates additional for the view. - */ - createWidgets() { - const cancelButtonText = this.getCancelButtonText(); - const confirmButtonText = this.getConfirmButtonText(); - - const buttonBar = $$(function() { - return this.div({class: 'button-bar'}, () => { - this.button({ - class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel' - }, cancelButtonText); - this.button({ - class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' - }, confirmButtonText); - return this.div({class: 'clear-float'}); - }); - }); - - buttonBar.appendTo(this); - - this.on('click', 'button', event => { - if ($(event.target).hasClass('button--confirm')) { this.confirmedByButton(); } - if ($(event.target).hasClass('button--cancel')) { return this.cancel(); } - }); + * The message to display when there are no results. + */ + this.emptyMessage = null; - this.on('keydown', event => { - // Shift + Return - if ((event.keyCode === 13) && (event.shiftKey === true)) { - return this.confirmedByButton(); - } - }); - - // Ensure that button clicks are actually handled. - return this.on('mousedown', ({target}) => { - if ($(target).hasClass('btn')) { return false; } + /** + * Items that are currently selected. + */ + this.selectedItems = []; + } + + /** + * @inheritdoc + */ + initialize() { + super.initialize(); + + this.addClass('php-ide-serenata-refactoring-multi-selection-view'); + this.list.addClass('mark-active'); + + if (this.panel == null) { this.panel = atom.workspace.addModalPanel({item: this, visible: false}); } + + return this.createWidgets(); + } + + /** + * Destroys the view and cleans up. + */ + destroy() { + this.panel.destroy(); + return this.panel = null; + } + + /** + * Creates additional for the view. + */ + createWidgets() { + const cancelButtonText = this.getCancelButtonText(); + const confirmButtonText = this.getConfirmButtonText(); + + const buttonBar = $$(function() { + return this.div({class: 'button-bar'}, () => { + this.button({ + class: 'btn btn-error inline-block-tight pull-left icon icon-circle-slash button--cancel' + }, cancelButtonText); + this.button({ + class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' + }, confirmButtonText); + return this.div({class: 'clear-float'}); }); - } + }); - /** - * @inheritdoc - */ - viewForItem(item) { - const classes = ['list-item']; + buttonBar.appendTo(this); - if (item.className) { - classes.push(item.className); - } + this.on('click', 'button', event => { + if ($(event.target).hasClass('button--confirm')) { this.confirmedByButton(); } + if ($(event.target).hasClass('button--cancel')) { return this.cancel(); } + }); - if (item.isSelected) { - classes.push('active'); + this.on('keydown', event => { + // Shift + Return + if ((event.keyCode === 13) && (event.shiftKey === true)) { + return this.confirmedByButton(); } - - const className = classes.join(' '); - const displayText = item.name; - - return `\ -
  • ${displayText}
  • \ -`; - } - - /** - * @inheritdoc - */ - getFilterKey() { - return 'name'; - } - - /** - * Retrieves the text to display on the cancel button. - * - * @return {string} - */ - getCancelButtonText() { - return 'Cancel'; - } - - /** - * Retrieves the text to display on the confirmation button. - * - * @return {string} - */ - getConfirmButtonText() { - return 'Generate'; + }); + + // Ensure that button clicks are actually handled. + return this.on('mousedown', ({target}) => { + if ($(target).hasClass('btn')) { return false; } + }); + } + + /** + * @inheritdoc + */ + viewForItem(item) { + const classes = ['list-item']; + + if (item.className) { + classes.push(item.className); } - /** - * Retrieves the message that is displayed when there are no results. - * - * @return {string} - */ - getEmptyMessage() { - if (this.emptyMessage != null) { - return this.emptyMessage; - } - - return super.getEmptyMessage(); + if (item.isSelected) { + classes.push('active'); } - /** - * Sets the message that is displayed when there are no results. - * - * @param {string} emptyMessage - */ - setEmptyMessage(emptyMessage) { - return this.emptyMessage = emptyMessage; - } + const className = classes.join(' '); + const displayText = item.name; - /** - * Retrieves the metadata to pass to the callbacks. - * - * @return {Object|null} - */ - getMetadata() { - return this.metadata; + return `\ +
  • ${displayText}
  • \ +`; + } + + /** + * @inheritdoc + */ + getFilterKey() { + return 'name'; + } + + /** + * Retrieves the text to display on the cancel button. + * + * @return {string} + */ + getCancelButtonText() { + return 'Cancel'; + } + + /** + * Retrieves the text to display on the confirmation button. + * + * @return {string} + */ + getConfirmButtonText() { + return 'Generate'; + } + + /** + * Retrieves the message that is displayed when there are no results. + * + * @return {string} + */ + getEmptyMessage() { + if (this.emptyMessage != null) { + return this.emptyMessage; } - /** - * Sets the metadata to pass to the callbacks. - * - * @param {Object|null} metadata - */ - setMetadata(metadata) { - return this.metadata = metadata; + return super.getEmptyMessage(); + } + + /** + * Sets the message that is displayed when there are no results. + * + * @param {string} emptyMessage + */ + setEmptyMessage(emptyMessage) { + return this.emptyMessage = emptyMessage; + } + + /** + * Retrieves the metadata to pass to the callbacks. + * + * @return {Object|null} + */ + getMetadata() { + return this.metadata; + } + + /** + * Sets the metadata to pass to the callbacks. + * + * @param {Object|null} metadata + */ + setMetadata(metadata) { + return this.metadata = metadata; + } + + /** + * @inheritdoc + */ + setItems(items) { + let i = 0; + + for (const item of items) { + item.index = i++; } - /** - * @inheritdoc - */ - setItems(items) { - let i = 0; + super.setItems(items); - for (const item of items) { - item.index = i++; - } - - super.setItems(items); - - return this.selectedItems = []; - } + return this.selectedItems = []; + } - /** - * @inheritdoc - */ - confirmed(item) { - let index; - item.isSelected = !item.isSelected; + /** + * @inheritdoc + */ + confirmed(item) { + let index; + item.isSelected = !item.isSelected; - if (item.isSelected) { - this.selectedItems.push(item); + if (item.isSelected) { + this.selectedItems.push(item); - } else { - index = this.selectedItems.indexOf(item); + } else { + index = this.selectedItems.indexOf(item); - if (index >= 0) { - this.selectedItems.splice(index, 1); - } + if (index >= 0) { + this.selectedItems.splice(index, 1); } - - const selectedItem = this.getSelectedItem(); - index = selectedItem ? selectedItem.index : 0; - - this.populateList(); - - return this.selectItemView(this.list.find(`li:nth(${index})`)); } - /** - * Invoked when the user confirms his selections by pressing the confirmation button. - */ - confirmedByButton() { - this.invokeOnDidConfirm(); - this.restoreFocus(); - return this.panel.hide(); + const selectedItem = this.getSelectedItem(); + index = selectedItem ? selectedItem.index : 0; + + this.populateList(); + + return this.selectItemView(this.list.find(`li:nth(${index})`)); + } + + /** + * Invoked when the user confirms his selections by pressing the confirmation button. + */ + confirmedByButton() { + this.invokeOnDidConfirm(); + this.restoreFocus(); + return this.panel.hide(); + } + + /** + * Invokes the on did confirm handler with the correct arguments (if it is set). + */ + invokeOnDidConfirm() { + if (this.onDidConfirm) { + return this.onDidConfirm(this.selectedItems, this.getMetadata()); } - - /** - * Invokes the on did confirm handler with the correct arguments (if it is set). - */ - invokeOnDidConfirm() { - if (this.onDidConfirm) { - return this.onDidConfirm(this.selectedItems, this.getMetadata()); - } + } + + /** + * @inheritdoc + */ + cancelled() { + if (this.onDidCancel) { + this.onDidCancel(this.getMetadata()); } - /** - * @inheritdoc - */ - cancelled() { - if (this.onDidCancel) { - this.onDidCancel(this.getMetadata()); - } - - this.restoreFocus(); - return this.panel.hide(); - } - - /** - * Presents the view to the user. - */ - present() { - this.panel.show(); - return this.focusFilterEditor(); - } - }; - MultiSelectionView.initClass(); - return MultiSelectionView; -})()); + this.restoreFocus(); + return this.panel.hide(); + } + + /** + * Presents the view to the user. + */ + present() { + this.panel.show(); + return this.focusFilterEditor(); + } +}; diff --git a/lib/Refactoring/Utility/TypeHelper.js b/lib/Refactoring/Utility/TypeHelper.js index edecea17..5dd99282 100644 --- a/lib/Refactoring/Utility/TypeHelper.js +++ b/lib/Refactoring/Utility/TypeHelper.js @@ -5,224 +5,219 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let TypeHelper; module.exports = -(TypeHelper = (function() { - TypeHelper = class TypeHelper { - static initClass() { - /** - * @var {Object|null} service - */ - this.prototype.service = null; - } - +class TypeHelper { + constructor() { /** - * @param {Object} service - */ - setService(service) { - this.service = service; + * @var {Object|null} service + */ + this.service = null; + } + + /** + * @param {Object} service + */ + setService(service) { + this.service = service; + } + + /** + * @return {Number} + */ + getCurrentProjectPhpVersion() { + const projectSettings = this.service.getCurrentProjectSettings(); + + if (projectSettings != null) { + return projectSettings.phpVersion; } - /** - * @return {Number} - */ - getCurrentProjectPhpVersion() { - const projectSettings = this.service.getCurrentProjectSettings(); - - if (projectSettings != null) { - return projectSettings.phpVersion; - } - - return 5.2; // Assume lowest supported version - } + return 5.2; // Assume lowest supported version + } - /** - * @param {String|null} typeSpecification - * - * @return {Object|null} - */ - getReturnTypeHintForTypeSpecification(typeSpecification) { - if (this.getCurrentProjectPhpVersion() < 7.0) { return null; } + /** + * @param {String|null} typeSpecification + * + * @return {Object|null} + */ + getReturnTypeHintForTypeSpecification(typeSpecification) { + if (this.getCurrentProjectPhpVersion() < 7.0) { return null; } - const returnTypeHint = this.getTypeHintForTypeSpecification(typeSpecification); - - if ((returnTypeHint == null) || returnTypeHint.shouldSetDefaultValueToNull) { - return null; - } - - return returnTypeHint.typeHint; - } - - /** - * @param {String|null} typeSpecification - * - * @return {Object|null} - */ - getTypeHintForTypeSpecification(typeSpecification) { - const types = this.getDocblockTypesFromDocblockTypeSpecification(typeSpecification); - - return this.getTypeHintForDocblockTypes(types); - } + const returnTypeHint = this.getTypeHintForTypeSpecification(typeSpecification); - /** - * @param {String|null} typeSpecification - * - * @return {Array} - */ - getDocblockTypesFromDocblockTypeSpecification(typeSpecification) { - if ((typeSpecification == null)) { return []; } - return typeSpecification.split('|'); + if ((returnTypeHint == null) || returnTypeHint.shouldSetDefaultValueToNull) { + return null; } - /** - * @param {Array} types - * @param {boolean} allowPhp7 - * - * @return {Object|null} - */ - getTypeHintForDocblockTypes(types) { - let isNullable = false; - - types = types.filter(type => { - if (type === 'null') { - isNullable = true; - } - - return type !== 'null'; - }); - - let typeHint = null; - let previousTypeHint = null; - - for (const type of types) { - typeHint = this.getTypeHintForDocblockType(type); - - if ((previousTypeHint != null) && (typeHint !== previousTypeHint)) { - // Several different type hints are necessary, we can't provide a common denominator. - return null; - } - - previousTypeHint = typeHint; + return returnTypeHint.typeHint; + } + + /** + * @param {String|null} typeSpecification + * + * @return {Object|null} + */ + getTypeHintForTypeSpecification(typeSpecification) { + const types = this.getDocblockTypesFromDocblockTypeSpecification(typeSpecification); + + return this.getTypeHintForDocblockTypes(types); + } + + /** + * @param {String|null} typeSpecification + * + * @return {Array} + */ + getDocblockTypesFromDocblockTypeSpecification(typeSpecification) { + if ((typeSpecification == null)) { return []; } + return typeSpecification.split('|'); + } + + /** + * @param {Array} types + * @param {boolean} allowPhp7 + * + * @return {Object|null} + */ + getTypeHintForDocblockTypes(types) { + let isNullable = false; + + types = types.filter(type => { + if (type === 'null') { + isNullable = true; } - const data = { - typeHint, - shouldSetDefaultValueToNull : false - }; - - if ((typeHint == null)) { return data; } - if (!isNullable) { return data; } + return type !== 'null'; + }); - const currentPhpVersion = this.getCurrentProjectPhpVersion(); + let typeHint = null; + let previousTypeHint = null; - if (currentPhpVersion >= 7.1) { - data.typeHint = `?${typeHint}`; - data.shouldSetDefaultValueToNull = false; + for (const type of types) { + typeHint = this.getTypeHintForDocblockType(type); - } else { - data.shouldSetDefaultValueToNull = true; + if ((previousTypeHint != null) && (typeHint !== previousTypeHint)) { + // Several different type hints are necessary, we can't provide a common denominator. + return null; } - return data; + previousTypeHint = typeHint; } - /** - * @param {String|null} type - * - * @return {String|null} - */ - getTypeHintForDocblockType(type) { - if ((type == null)) { return null; } - if (this.isClassType(type)) { return type; } - return this.getScalarTypeHintForDocblockType(type); - } + const data = { + typeHint, + shouldSetDefaultValueToNull : false + }; - /** - * @param {String|null} type - * - * @return {boolean} - */ - isClassType(type) { - if (this.getScalarTypeHintForDocblockType(type) === false) { return true; } else { return false; } - } - - /** - * @param {String|null} type - * - * @return {String|null|false} Null if the type is recognized, but there is no type hint available, false of the - * type is not recognized at all, and the type hint itself if it is recognized and there is a type hint. - */ - getScalarTypeHintForDocblockType(type) { - if ((type == null)) { return null; } - - const phpVersion = this.getCurrentProjectPhpVersion(); - - if (phpVersion >= 7.1) { - if (type === 'iterable') { return 'iterable'; } - if (type === 'void') { return 'void'; } - - } else if (phpVersion >= 7.0) { - if (type === 'string') { return 'string'; } - if (type === 'int') { return 'int'; } - if (type === 'bool') { return 'bool'; } - if (type === 'float') { return 'float'; } - if (type === 'resource') { return 'resource'; } - if (type === 'false') { return 'bool'; } - if (type === 'true') { return 'bool'; } - - } else { - if (type === 'string') { return null; } - if (type === 'int') { return null; } - if (type === 'bool') { return null; } - if (type === 'float') { return null; } - if (type === 'resource') { return null; } - if (type === 'false') { return null; } - if (type === 'true') { return null; } - } + if ((typeHint == null)) { return data; } + if (!isNullable) { return data; } - if (type === 'array') { return 'array'; } - if (type === 'callable') { return 'callable'; } - if (type === 'self') { return 'self'; } - if (type === 'static') { return 'self'; } - if (/^.+\[\]$/.test(type)) { return 'array'; } + const currentPhpVersion = this.getCurrentProjectPhpVersion(); - if (type === 'object') { return null; } - if (type === 'mixed') { return null; } - if (type === 'void') { return null; } - if (type === 'null') { return null; } - if (type === 'parent') { return null; } - if (type === '$this') { return null; } + if (currentPhpVersion >= 7.1) { + data.typeHint = `?${typeHint}`; + data.shouldSetDefaultValueToNull = false; - return false; + } else { + data.shouldSetDefaultValueToNull = true; } - /** - * Takes a type list (list of type objects) and turns them into a single docblock type specification. - * - * @param {Array} typeList - * - * @return {String} - */ - buildTypeSpecificationFromTypeArray(typeList) { - const typeNames = typeList.map(type => type.type); - - return this.buildTypeSpecificationFromTypes(typeNames); + return data; + } + + /** + * @param {String|null} type + * + * @return {String|null} + */ + getTypeHintForDocblockType(type) { + if ((type == null)) { return null; } + if (this.isClassType(type)) { return type; } + return this.getScalarTypeHintForDocblockType(type); + } + + /** + * @param {String|null} type + * + * @return {boolean} + */ + isClassType(type) { + if (this.getScalarTypeHintForDocblockType(type) === false) { return true; } else { return false; } + } + + /** + * @param {String|null} type + * + * @return {String|null|false} Null if the type is recognized, but there is no type hint available, false of the + * type is not recognized at all, and the type hint itself if it is recognized and there is a type hint. + */ + getScalarTypeHintForDocblockType(type) { + if ((type == null)) { return null; } + + const phpVersion = this.getCurrentProjectPhpVersion(); + + if (phpVersion >= 7.1) { + if (type === 'iterable') { return 'iterable'; } + if (type === 'void') { return 'void'; } + + } else if (phpVersion >= 7.0) { + if (type === 'string') { return 'string'; } + if (type === 'int') { return 'int'; } + if (type === 'bool') { return 'bool'; } + if (type === 'float') { return 'float'; } + if (type === 'resource') { return 'resource'; } + if (type === 'false') { return 'bool'; } + if (type === 'true') { return 'bool'; } + + } else { + if (type === 'string') { return null; } + if (type === 'int') { return null; } + if (type === 'bool') { return null; } + if (type === 'float') { return null; } + if (type === 'resource') { return null; } + if (type === 'false') { return null; } + if (type === 'true') { return null; } } - /** - * Takes a list of type names and turns them into a single docblock type specification. - * - * @param {Array} typeNames - * - * @return {String} - */ - buildTypeSpecificationFromTypes(typeNames) { - if (typeNames.length === 0) { return 'mixed'; } - - return typeNames.join('|'); - } - }; - TypeHelper.initClass(); - return TypeHelper; -})()); + if (type === 'array') { return 'array'; } + if (type === 'callable') { return 'callable'; } + if (type === 'self') { return 'self'; } + if (type === 'static') { return 'self'; } + if (/^.+\[\]$/.test(type)) { return 'array'; } + + if (type === 'object') { return null; } + if (type === 'mixed') { return null; } + if (type === 'void') { return null; } + if (type === 'null') { return null; } + if (type === 'parent') { return null; } + if (type === '$this') { return null; } + + return false; + } + + /** + * Takes a type list (list of type objects) and turns them into a single docblock type specification. + * + * @param {Array} typeList + * + * @return {String} + */ + buildTypeSpecificationFromTypeArray(typeList) { + const typeNames = typeList.map(type => type.type); + + return this.buildTypeSpecificationFromTypes(typeNames); + } + + /** + * Takes a list of type names and turns them into a single docblock type specification. + * + * @param {Array} typeNames + * + * @return {String} + */ + buildTypeSpecificationFromTypes(typeNames) { + if (typeNames.length === 0) { return 'mixed'; } + + return typeNames.join('|'); + } +}; diff --git a/lib/UseStatementHelper.js b/lib/UseStatementHelper.js index c472c8a7..fde0b5a6 100644 --- a/lib/UseStatementHelper.js +++ b/lib/UseStatementHelper.js @@ -8,290 +8,281 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let UseStatementHelper; module.exports = //#* // Contains convenience methods for dealing with use statements. //# -(UseStatementHelper = (function() { - UseStatementHelper = class UseStatementHelper { - static initClass() { - /** - * Regular expression that will search for a structure (class, interface, trait, ...). - * - * @var {RegExp} - */ - this.prototype.structureStartRegex = /(?:abstract class|class|trait|interface)\s+(\w+)/; - - /** - * Regular expression that will search for a use statement. - * - * @var {RegExp} - */ - this.prototype.useStatementRegex = /(?:use)(?:[^\w\\])([\w\\]+)(?![\w\\])(?:(?:[ ]+as[ ]+)(\w+))?(?:;)/; - - /** - * Whether to allow adding additional newlines to attempt to group use statements. - * - * @var {Boolean} - */ - this.prototype.allowAdditionalNewlines = true; - } - +class UseStatementHelper { + /** + * @param {Boolean} allowAdditionalNewlines + */ + constructor(allowAdditionalNewlines) { /** - * @param {Boolean} allowAdditionalNewlines + * Regular expression that will search for a structure (class, interface, trait, ...). + * + * @var {RegExp} */ - constructor(allowAdditionalNewlines) { - this.allowAdditionalNewlines = allowAdditionalNewlines; - } + this.structureStartRegex = /(?:abstract class|class|trait|interface)\s+(\w+)/; /** - * @param {Boolean} allowAdditionalNewlines + * Regular expression that will search for a use statement. + * + * @var {RegExp} */ - setAllowAdditionalNewlines(allowAdditionalNewlines) { - this.allowAdditionalNewlines = allowAdditionalNewlines; - } + this.useStatementRegex = /(?:use)(?:[^\w\\])([\w\\]+)(?![\w\\])(?:(?:[ ]+as[ ]+)(\w+))?(?:;)/; /** - * Add the use for the given class if not already added. + * Whether to allow adding additional newlines to attempt to group use statements. * - * @param {TextEditor} editor Atom text editor. - * @param {String} className Name of the class to add. - * - * @return {Number} The amount of lines added (including newlines), so you can reliably and easily offset your - * rows. This could be zero if a use statement was already present. + * @var {Boolean} */ - addUseClass(editor, className) { - let i, line, matches, scopeDescriptor; - let asc, end; - let asc1, end1; - let bestUseRow = 0; - let placeBelow = true; - let doNewLine = true; - const lineCount = editor.getLineCount(); - let previousMatchThatSharedNamespacePrefixRow = null; - - // First see if the use statement is already present. The next loop stops early (and can't do this). - for (i = 0, end = lineCount - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { - line = editor.lineTextForBufferRow(i).trim(); - - if (line.length === 0) { continue; } - - scopeDescriptor = editor.scopeDescriptorForBufferPosition([i, line.length]).getScopeChain(); - - if (scopeDescriptor.indexOf('.comment') >= 0) { - continue; - } + this.allowAdditionalNewlines = allowAdditionalNewlines; + } + + /** + * @param {Boolean} allowAdditionalNewlines + */ + setAllowAdditionalNewlines(allowAdditionalNewlines) { + this.allowAdditionalNewlines = allowAdditionalNewlines; + } + + /** + * Add the use for the given class if not already added. + * + * @param {TextEditor} editor Atom text editor. + * @param {String} className Name of the class to add. + * + * @return {Number} The amount of lines added (including newlines), so you can reliably and easily offset your + * rows. This could be zero if a use statement was already present. + */ + addUseClass(editor, className) { + let i, line, matches, scopeDescriptor; + let asc, end; + let asc1, end1; + let bestUseRow = 0; + let placeBelow = true; + let doNewLine = true; + const lineCount = editor.getLineCount(); + let previousMatchThatSharedNamespacePrefixRow = null; + + // First see if the use statement is already present. The next loop stops early (and can't do this). + for (i = 0, end = lineCount - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + line = editor.lineTextForBufferRow(i).trim(); + + if (line.length === 0) { continue; } + + scopeDescriptor = editor.scopeDescriptorForBufferPosition([i, line.length]).getScopeChain(); + + if (scopeDescriptor.indexOf('.comment') >= 0) { + continue; + } - if (line.match(this.structureStartRegex)) { break; } + if (line.match(this.structureStartRegex)) { break; } - if (matches = this.useStatementRegex.exec(line)) { - if ((matches[1] === className) || ((matches[1][0] === '\\') && - (matches[1].substr(1) === className))) { - return 0; - } + if (matches = this.useStatementRegex.exec(line)) { + if ((matches[1] === className) || ((matches[1][0] === '\\') && + (matches[1].substr(1) === className))) { + return 0; } } + } - // Determine an appropriate location to place the use statement. - for (i = 0, end1 = lineCount - 1, asc1 = 0 <= end1; asc1 ? i <= end1 : i >= end1; asc1 ? i++ : i--) { - line = editor.lineTextForBufferRow(i).trim(); + // Determine an appropriate location to place the use statement. + for (i = 0, end1 = lineCount - 1, asc1 = 0 <= end1; asc1 ? i <= end1 : i >= end1; asc1 ? i++ : i--) { + line = editor.lineTextForBufferRow(i).trim(); - if (line.length === 0) { continue; } + if (line.length === 0) { continue; } - scopeDescriptor = editor.scopeDescriptorForBufferPosition([i, line.length]).getScopeChain(); + scopeDescriptor = editor.scopeDescriptorForBufferPosition([i, line.length]).getScopeChain(); - if (scopeDescriptor.indexOf('.comment') >= 0) { - continue; - } - - if (line.match(this.structureStartRegex)) { break; } + if (scopeDescriptor.indexOf('.comment') >= 0) { + continue; + } - if (line.indexOf('namespace ') >= 0) { - bestUseRow = i; - } + if (line.match(this.structureStartRegex)) { break; } - if (matches = this.useStatementRegex.exec(line)) { - bestUseRow = i; + if (line.indexOf('namespace ') >= 0) { + bestUseRow = i; + } - placeBelow = true; - const shareCommonNamespacePrefix = this.doShareCommonNamespacePrefix(className, matches[1]); + if (matches = this.useStatementRegex.exec(line)) { + bestUseRow = i; - doNewLine = !shareCommonNamespacePrefix; + placeBelow = true; + const shareCommonNamespacePrefix = this.doShareCommonNamespacePrefix(className, matches[1]); - if (this.scoreClassName(className, matches[1]) <= 0) { - placeBelow = false; + doNewLine = !shareCommonNamespacePrefix; - // Normally we keep going until the sorting indicates we should stop, and then place the use - // statement above the 'incorrect' match, but if the previous use statement was a use statement - // that has the same namespace, we want to ensure we stick close to it instead of creating - // additional newlines (which the item from the same namespace already placed). - if (previousMatchThatSharedNamespacePrefixRow != null) { - placeBelow = true; - doNewLine = false; - bestUseRow = previousMatchThatSharedNamespacePrefixRow; - } + if (this.scoreClassName(className, matches[1]) <= 0) { + placeBelow = false; - break; + // Normally we keep going until the sorting indicates we should stop, and then place the use + // statement above the 'incorrect' match, but if the previous use statement was a use statement + // that has the same namespace, we want to ensure we stick close to it instead of creating + // additional newlines (which the item from the same namespace already placed). + if (previousMatchThatSharedNamespacePrefixRow != null) { + placeBelow = true; + doNewLine = false; + bestUseRow = previousMatchThatSharedNamespacePrefixRow; } - previousMatchThatSharedNamespacePrefixRow = shareCommonNamespacePrefix ? i : null; + break; } - } - - // Insert the use statement itself. - let lineEnding = editor.getBuffer().lineEndingForRow(0); - if (!this.allowAdditionalNewlines) { - doNewLine = false; + previousMatchThatSharedNamespacePrefixRow = shareCommonNamespacePrefix ? i : null; } + } - if (!lineEnding) { - lineEnding = '\n'; - } + // Insert the use statement itself. + let lineEnding = editor.getBuffer().lineEndingForRow(0); - let textToInsert = ''; + if (!this.allowAdditionalNewlines) { + doNewLine = false; + } - if (doNewLine && placeBelow) { - textToInsert += lineEnding; - } + if (!lineEnding) { + lineEnding = '\n'; + } - textToInsert += `use ${className};` + lineEnding; + let textToInsert = ''; - if (doNewLine && !placeBelow) { - textToInsert += lineEnding; - } + if (doNewLine && placeBelow) { + textToInsert += lineEnding; + } - const lineToInsertAt = bestUseRow + (placeBelow ? 1 : 0); - editor.setTextInBufferRange([[lineToInsertAt, 0], [lineToInsertAt, 0]], textToInsert); + textToInsert += `use ${className};` + lineEnding; - return (1 + (doNewLine ? 1 : 0)); + if (doNewLine && !placeBelow) { + textToInsert += lineEnding; } - /** - * Returns a boolean indicating if the specified class names share a common namespace prefix. - * - * @param {String} firstClassName - * @param {String} secondClassName - * - * @return {Boolean} - */ - doShareCommonNamespacePrefix(firstClassName, secondClassName) { - const firstClassNameParts = firstClassName.split('\\'); - const secondClassNameParts = secondClassName.split('\\'); - - firstClassNameParts.pop(); - secondClassNameParts.pop(); + const lineToInsertAt = bestUseRow + (placeBelow ? 1 : 0); + editor.setTextInBufferRange([[lineToInsertAt, 0], [lineToInsertAt, 0]], textToInsert); + + return (1 + (doNewLine ? 1 : 0)); + } + + /** + * Returns a boolean indicating if the specified class names share a common namespace prefix. + * + * @param {String} firstClassName + * @param {String} secondClassName + * + * @return {Boolean} + */ + doShareCommonNamespacePrefix(firstClassName, secondClassName) { + const firstClassNameParts = firstClassName.split('\\'); + const secondClassNameParts = secondClassName.split('\\'); + + firstClassNameParts.pop(); + secondClassNameParts.pop(); + + if (firstClassNameParts.join('\\') === secondClassNameParts.join('\\')) { + return true; + } - if (firstClassNameParts.join('\\') === secondClassNameParts.join('\\')) { - return true; + return false; + } + + /** + * Scores the first class name against the second, indicating how much they 'match' each other. This can be used + * to e.g. find an appropriate location to place a class in an existing list of classes. + * + * @param {String} firstClassName + * @param {String} secondClassName + * + * @return {Number} A floating point number that represents the score. + */ + scoreClassName(firstClassName, secondClassName) { + const firstClassNameParts = firstClassName.split('\\'); + const secondClassNameParts = secondClassName.split('\\'); + + const collator = new Intl.Collator; + const maxLength = Math.min(firstClassNameParts.length, secondClassNameParts.length); + + // Always sort unqualified imports before everything else. + if (firstClassNameParts.length !== secondClassNameParts.length) { + if (firstClassNameParts.length <= 1) { + return -1; + } else if (secondClassNameParts.length <= 1) { + return 1; } - - return false; } - /** - * Scores the first class name against the second, indicating how much they 'match' each other. This can be used - * to e.g. find an appropriate location to place a class in an existing list of classes. - * - * @param {String} firstClassName - * @param {String} secondClassName - * - * @return {Number} A floating point number that represents the score. - */ - scoreClassName(firstClassName, secondClassName) { - const firstClassNameParts = firstClassName.split('\\'); - const secondClassNameParts = secondClassName.split('\\'); - - const collator = new Intl.Collator; - const maxLength = Math.min(firstClassNameParts.length, secondClassNameParts.length); - - // Always sort unqualified imports before everything else. - if (firstClassNameParts.length !== secondClassNameParts.length) { - if (firstClassNameParts.length <= 1) { - return -1; - } else if (secondClassNameParts.length <= 1) { - return 1; + for (let i = 0, end = maxLength - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + if (firstClassNameParts[i] !== secondClassNameParts[i]) { + // For use statements that only differ in the last segment (with a common namespace segment), + // sort the last part by length so we get a neat gradually expanding half of a christmas tree. + if (firstClassNameParts[i].length !== secondClassNameParts[i].length && + firstClassNameParts.length === secondClassNameParts.length && + i === (maxLength - 1) + ) { + return firstClassNameParts[i].length > secondClassNameParts[i].length ? 1 : -1; } - } - - for (let i = 0, end = maxLength - 1, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { - if (firstClassNameParts[i] !== secondClassNameParts[i]) { - // For use statements that only differ in the last segment (with a common namespace segment), - // sort the last part by length so we get a neat gradually expanding half of a christmas tree. - if (firstClassNameParts[i].length !== secondClassNameParts[i].length && - firstClassNameParts.length === secondClassNameParts.length && - i === (maxLength - 1) - ) { - return firstClassNameParts[i].length > secondClassNameParts[i].length ? 1 : -1; - } - return collator.compare(firstClassNameParts[i], secondClassNameParts[i]); - } + return collator.compare(firstClassNameParts[i], secondClassNameParts[i]); } - - return firstClassNameParts.length > secondClassNameParts.length ? 1 : -1; } - /** - * Sorts the use statements in the specified file according to the same algorithm used by 'addUseClass'. - * - * @param {TextEditor} editor - */ - sortUseStatements(editor) { - let endLine = null; - let startLine = null; - const useStatements = []; - - for (let i = 0, end = editor.getLineCount(), asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { - var matches; - const lineText = editor.lineTextForBufferRow(i); + return firstClassNameParts.length > secondClassNameParts.length ? 1 : -1; + } - endLine = i; + /** + * Sorts the use statements in the specified file according to the same algorithm used by 'addUseClass'. + * + * @param {TextEditor} editor + */ + sortUseStatements(editor) { + let endLine = null; + let startLine = null; + const useStatements = []; - if (!lineText || (lineText.trim() === '')) { - continue; + for (let i = 0, end = editor.getLineCount(), asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + var matches; + const lineText = editor.lineTextForBufferRow(i); - } else if (matches = this.useStatementRegex.exec(lineText)) { - if (!startLine) { - startLine = i; - } + endLine = i; - let text = matches[1]; + if (!lineText || (lineText.trim() === '')) { + continue; - if (matches[2] != null) { - text += ` as ${matches[2]}`; - } + } else if (matches = this.useStatementRegex.exec(lineText)) { + if (!startLine) { + startLine = i; + } - useStatements.push(text); + let text = matches[1]; - // We still do the regex check here to prevent continuing when there are no use statements at all. - } else if (startLine || this.structureStartRegex.test(lineText)) { - break; + if (matches[2] != null) { + text += ` as ${matches[2]}`; } - } - if (useStatements.length === 0) { return; } + useStatements.push(text); + + // We still do the regex check here to prevent continuing when there are no use statements at all. + } else if (startLine || this.structureStartRegex.test(lineText)) { + break; + } + } - return editor.transact(() => { - editor.setTextInBufferRange([[startLine, 0], [endLine, 0]], ''); + if (useStatements.length === 0) { return; } - return (() => { - const result = []; - for (let useStatement of useStatements) { - // The leading slash is unnecessary, not recommended, and messes up sorting, take it out. - if (useStatement[0] === '\\') { - useStatement = useStatement.substr(1); - } + return editor.transact(() => { + editor.setTextInBufferRange([[startLine, 0], [endLine, 0]], ''); - result.push(this.addUseClass(editor, useStatement, this.allowAdditionalNewlines)); + return (() => { + const result = []; + for (let useStatement of useStatements) { + // The leading slash is unnecessary, not recommended, and messes up sorting, take it out. + if (useStatement[0] === '\\') { + useStatement = useStatement.substr(1); } - return result; - })(); - }); - } - }; - UseStatementHelper.initClass(); - return UseStatementHelper; -})()); + + result.push(this.addUseClass(editor, useStatement, this.allowAdditionalNewlines)); + } + return result; + })(); + }); + } +}; From 7bb9c91f2ed4ebc6355b7b9e01f0ed7e7919259c Mon Sep 17 00:00:00 2001 From: Mohammad Amin Chitgarha Date: Tue, 19 Jul 2022 02:34:11 +0430 Subject: [PATCH 3/6] Remove or suppress unused variable errors of ESLint --- lib/CodeLensManager.js | 2 -- lib/Proxy.js | 2 -- lib/Refactoring/AbstractProvider.js | 3 ++- lib/Refactoring/ConstructorGenerationProvider.js | 6 +----- lib/Refactoring/ExtractMethodProvider.js | 4 ++-- lib/Refactoring/ExtractMethodProvider/View.js | 16 ++++++++-------- lib/Refactoring/GetterSetterProvider.js | 4 ++-- lib/Refactoring/OverrideMethodProvider.js | 2 +- lib/Refactoring/StubAbstractMethodProvider.js | 2 +- lib/Refactoring/StubInterfaceMethodProvider.js | 2 +- 10 files changed, 18 insertions(+), 25 deletions(-) diff --git a/lib/CodeLensManager.js b/lib/CodeLensManager.js index b5f07514..0be87e62 100644 --- a/lib/CodeLensManager.js +++ b/lib/CodeLensManager.js @@ -1,5 +1,3 @@ -/* global atom */ - 'use strict'; module.exports = diff --git a/lib/Proxy.js b/lib/Proxy.js index ff02fe1b..d4511046 100644 --- a/lib/Proxy.js +++ b/lib/Proxy.js @@ -1,5 +1,3 @@ -/* global atom */ - 'use strict'; const net = require('net'); diff --git a/lib/Refactoring/AbstractProvider.js b/lib/Refactoring/AbstractProvider.js index 14d5004d..2ac02916 100644 --- a/lib/Refactoring/AbstractProvider.js +++ b/lib/Refactoring/AbstractProvider.js @@ -68,7 +68,7 @@ class AbstractProvider { }); // When you go back to only have one pane the events are lost, so need to re-register. - atom.workspace.onDidDestroyPane(pane => { + atom.workspace.onDidDestroyPane(() => { const panes = atom.workspace.getPanes(); if (panes.length === 1) { @@ -142,6 +142,7 @@ class AbstractProvider { * * @param {TextEditor} editor TextEditor to register events to. */ + // eslint-disable-next-line no-unused-vars registerEvents(editor) {} /** diff --git a/lib/Refactoring/ConstructorGenerationProvider.js b/lib/Refactoring/ConstructorGenerationProvider.js index 963b971b..234a336e 100644 --- a/lib/Refactoring/ConstructorGenerationProvider.js +++ b/lib/Refactoring/ConstructorGenerationProvider.js @@ -7,8 +7,6 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const {Point} = require('atom'); - const AbstractProvider = require('./AbstractProvider'); module.exports = @@ -192,10 +190,8 @@ class DocblockProvider extends AbstractProvider { /** * Called when the selection of properties is cancelled. - * - * @param {Object|null} metadata */ - onCancel(metadata) {} + onCancel() {} /** * Called when the selection of properties is confirmed. diff --git a/lib/Refactoring/ExtractMethodProvider.js b/lib/Refactoring/ExtractMethodProvider.js index 61255802..14317c43 100644 --- a/lib/Refactoring/ExtractMethodProvider.js +++ b/lib/Refactoring/ExtractMethodProvider.js @@ -69,7 +69,7 @@ class ExtractMethodProvider extends AbstractProvider { getIntentionProviders() { return [{ grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { + getIntentions: () => { const activeTextEditor = atom.workspace.getActiveTextEditor(); if (!activeTextEditor) { return []; } @@ -171,6 +171,7 @@ class ExtractMethodProvider extends AbstractProvider { let row = 0; + // eslint-disable-next-line no-constant-condition while (true) { row++; const descriptions = activeTextEditor.scopeDescriptorForBufferPosition( @@ -299,7 +300,6 @@ class ExtractMethodProvider extends AbstractProvider { // Get tab stops by looping through all matches while ((match = regex.exec(line)) !== null) { let key = match[2]; // 2nd capturing group (variable name) - const replace = match[1]; // 1st capturing group ([type]) const range = new Range( [row, match.index], [row, match.index + match[1].length] diff --git a/lib/Refactoring/ExtractMethodProvider/View.js b/lib/Refactoring/ExtractMethodProvider/View.js index b3c4b287..d29c78c4 100644 --- a/lib/Refactoring/ExtractMethodProvider/View.js +++ b/lib/Refactoring/ExtractMethodProvider/View.js @@ -9,8 +9,6 @@ */ const {$, TextEditorView, View} = require('atom-space-pen-views'); -const Parser = require('./Builder'); - module.exports = class ExtractMethodView extends View { @@ -222,7 +220,7 @@ class ExtractMethodView extends View { return this.refreshPreviewArea(); }); - $(this.generateDocInput[0]).change(event => { + $(this.generateDocInput[0]).change(() => { this.settings.generateDocs = !this.settings.generateDocs; if (this.settings.generateDocs === true) { $('.php-ide-serenata-refactoring-extract-method .generate-docs-control').removeClass('hide'); @@ -234,17 +232,17 @@ class ExtractMethodView extends View { return this.refreshPreviewArea(); }); - $(this.generateDescPlaceholdersInput[0]).change(event => { + $(this.generateDescPlaceholdersInput[0]).change(() => { this.settings.generateDescPlaceholders = !this.settings.generateDescPlaceholders; return this.refreshPreviewArea(); }); - $(this.generateTypeHints[0]).change(event => { + $(this.generateTypeHints[0]).change(() => { this.settings.typeHinting = !this.settings.typeHinting; return this.refreshPreviewArea(); }); - $(this.arraySyntax[0]).change(event => { + $(this.arraySyntax[0]).change(() => { if (this.settings.arraySyntax === 'word') { this.settings.arraySyntax = 'brackets'; } else { @@ -262,8 +260,10 @@ class ExtractMethodView extends View { return event.stopPropagation(); }); - return $(document).on('click', event => { - if (this.panel != null ? this.panel.isVisible() : undefined) { return this.cancel(); } + return $(document).on('click', () => { + if (this.panel != null ? this.panel.isVisible() : undefined) { + return this.cancel(); + } }); } diff --git a/lib/Refactoring/GetterSetterProvider.js b/lib/Refactoring/GetterSetterProvider.js index 69604b64..fd1f5c12 100644 --- a/lib/Refactoring/GetterSetterProvider.js +++ b/lib/Refactoring/GetterSetterProvider.js @@ -88,7 +88,7 @@ class GetterSetterProvider extends AbstractProvider { getIntentionProviders() { return [{ grammarScopes: ['source.php'], - getIntentions: ({textEditor, bufferPosition}) => { + getIntentions: () => { const successHandler = currentClassName => { if (!currentClassName) { return []; } @@ -233,7 +233,7 @@ class GetterSetterProvider extends AbstractProvider { * * @param {Object|null} metadata */ - onCancel(metadata) {} + onCancel() {} /** * Called when the selection of properties is confirmed. diff --git a/lib/Refactoring/OverrideMethodProvider.js b/lib/Refactoring/OverrideMethodProvider.js index ad382260..bb223a9a 100644 --- a/lib/Refactoring/OverrideMethodProvider.js +++ b/lib/Refactoring/OverrideMethodProvider.js @@ -133,7 +133,7 @@ class OverrideMethodProvider extends AbstractProvider { /** * Called when the selection of properties is cancelled. */ - onCancel(metadata) {} + onCancel() {} /** * Called when the selection of properties is confirmed. diff --git a/lib/Refactoring/StubAbstractMethodProvider.js b/lib/Refactoring/StubAbstractMethodProvider.js index 41c7618b..852fa0ad 100644 --- a/lib/Refactoring/StubAbstractMethodProvider.js +++ b/lib/Refactoring/StubAbstractMethodProvider.js @@ -127,7 +127,7 @@ class StubAbstractMethodProvider extends AbstractProvider { /** * Called when the selection of properties is cancelled. */ - onCancel(metadata) {} + onCancel() {} /** * Called when the selection of properties is confirmed. diff --git a/lib/Refactoring/StubInterfaceMethodProvider.js b/lib/Refactoring/StubInterfaceMethodProvider.js index 343cf0cd..05bcfee9 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider.js +++ b/lib/Refactoring/StubInterfaceMethodProvider.js @@ -130,7 +130,7 @@ class StubInterfaceMethodProvider extends AbstractProvider { /** * Called when the selection of properties is cancelled. */ - onCancel(metadata) {} + onCancel() {} /** * Called when the selection of properties is confirmed. From a8144c93a012377bc5c139b403d83829b30e3173 Mon Sep 17 00:00:00 2001 From: Mohammad Amin Chitgarha Date: Tue, 19 Jul 2022 02:54:03 +0430 Subject: [PATCH 4/6] Move common functionality from Refactoring View classes to their base Their base is MultiSelectionView. --- .../ConstructorGenerationProvider/View.js | 49 +------------------ lib/Refactoring/GetterSetterProvider/View.js | 46 +---------------- .../OverrideMethodProvider/View.js | 46 +---------------- .../StubAbstractMethodProvider/View.js | 46 +---------------- .../StubInterfaceMethodProvider/View.js | 46 +---------------- lib/Refactoring/Utility/MultiSelectionView.js | 25 +++++++++- 6 files changed, 28 insertions(+), 230 deletions(-) diff --git a/lib/Refactoring/ConstructorGenerationProvider/View.js b/lib/Refactoring/ConstructorGenerationProvider/View.js index b0ebe367..787a8513 100644 --- a/lib/Refactoring/ConstructorGenerationProvider/View.js +++ b/lib/Refactoring/ConstructorGenerationProvider/View.js @@ -1,52 +1,5 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const {$, $$} = require('atom-space-pen-views'); - const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -//#* -// An extension on SelectListView from atom-space-pen-views that allows multiple selections. -//# -class View extends MultiSelectionView { - /** - * @inheritdoc - */ - createWidgets() { - const checkboxBar = $$(function() { - return this.div({class: 'checkbox-bar settings-view'}, () => { - return this.div({class: 'controls'}, () => { - return this.div({class: 'block text-line'}, () => { - return this.label( - { class: 'icon icon-info' }, - 'Tip: The order in which items are selected determines the order of the output.' - ); - }); - }); - }); - }); - - checkboxBar.appendTo(this); - - // Ensure that button clicks are actually handled. - this.on('mousedown', ({target}) => { - if ($(target).hasClass('checkbox-input')) { return false; } - if ($(target).hasClass('checkbox-label-text')) { return false; } - }); - - return super.createWidgets(); - } - - /** - * @inheritdoc - */ - invokeOnDidConfirm() { - if (this.onDidConfirm) { - return this.onDidConfirm(this.selectedItems, this.getMetadata()); - } - } -}; +class View extends MultiSelectionView {} diff --git a/lib/Refactoring/GetterSetterProvider/View.js b/lib/Refactoring/GetterSetterProvider/View.js index 41729b47..787a8513 100644 --- a/lib/Refactoring/GetterSetterProvider/View.js +++ b/lib/Refactoring/GetterSetterProvider/View.js @@ -1,49 +1,5 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const {$, $$} = require('atom-space-pen-views'); - const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView { - /** - * @inheritdoc - */ - createWidgets() { - const checkboxBar = $$(function() { - return this.div({class: 'checkbox-bar settings-view'}, () => { - return this.div({class: 'controls'}, () => { - return this.div({class: 'block text-line'}, () => { - return this.label( - { class: 'icon icon-info' }, - 'Tip: The order in which items are selected determines the order of the output.' - ); - }); - }); - }); - }); - - checkboxBar.appendTo(this); - - // Ensure that button clicks are actually handled. - this.on('mousedown', ({target}) => { - if ($(target).hasClass('checkbox-input')) { return false; } - if ($(target).hasClass('checkbox-label-text')) { return false; } - }); - - return super.createWidgets(); - } - - /** - * @inheritdoc - */ - invokeOnDidConfirm() { - if (this.onDidConfirm) { - return this.onDidConfirm(this.selectedItems, this.getMetadata()); - } - } -}; +class View extends MultiSelectionView {} diff --git a/lib/Refactoring/OverrideMethodProvider/View.js b/lib/Refactoring/OverrideMethodProvider/View.js index 3c7c1bee..787a8513 100644 --- a/lib/Refactoring/OverrideMethodProvider/View.js +++ b/lib/Refactoring/OverrideMethodProvider/View.js @@ -1,49 +1,5 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const {$, $$} = require('atom-space-pen-views'); - const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView { - /** - * @inheritdoc - */ - createWidgets() { - const checkboxBar = $$(function() { - return this.div({class: 'checkbox-bar settings-view'}, () => { - return this.div({class: 'controls'}, () => { - return this.div({class: 'block text-line'}, () => { - return this.label( - { class: 'icon icon-info' }, - 'Tip: The order in which items are selected determines the order of the output.' - ); - }); - }); - }); - }); - - checkboxBar.appendTo(this); - - // Ensure that button clicks are actually handled. - this.on('mousedown', ({target}) => { - if ($(target).hasClass('checkbox-input')) { return false; } - if ($(target).hasClass('checkbox-label-text')) { return false; } - }); - - return super.createWidgets(); - } - - /** - * @inheritdoc - */ - invokeOnDidConfirm() { - if (this.onDidConfirm) { - return this.onDidConfirm(this.selectedItems, this.getMetadata()); - } - } -}; +class View extends MultiSelectionView {} diff --git a/lib/Refactoring/StubAbstractMethodProvider/View.js b/lib/Refactoring/StubAbstractMethodProvider/View.js index 41729b47..787a8513 100644 --- a/lib/Refactoring/StubAbstractMethodProvider/View.js +++ b/lib/Refactoring/StubAbstractMethodProvider/View.js @@ -1,49 +1,5 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const {$, $$} = require('atom-space-pen-views'); - const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView { - /** - * @inheritdoc - */ - createWidgets() { - const checkboxBar = $$(function() { - return this.div({class: 'checkbox-bar settings-view'}, () => { - return this.div({class: 'controls'}, () => { - return this.div({class: 'block text-line'}, () => { - return this.label( - { class: 'icon icon-info' }, - 'Tip: The order in which items are selected determines the order of the output.' - ); - }); - }); - }); - }); - - checkboxBar.appendTo(this); - - // Ensure that button clicks are actually handled. - this.on('mousedown', ({target}) => { - if ($(target).hasClass('checkbox-input')) { return false; } - if ($(target).hasClass('checkbox-label-text')) { return false; } - }); - - return super.createWidgets(); - } - - /** - * @inheritdoc - */ - invokeOnDidConfirm() { - if (this.onDidConfirm) { - return this.onDidConfirm(this.selectedItems, this.getMetadata()); - } - } -}; +class View extends MultiSelectionView {} diff --git a/lib/Refactoring/StubInterfaceMethodProvider/View.js b/lib/Refactoring/StubInterfaceMethodProvider/View.js index 41729b47..787a8513 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider/View.js +++ b/lib/Refactoring/StubInterfaceMethodProvider/View.js @@ -1,49 +1,5 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -const {$, $$} = require('atom-space-pen-views'); - const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView { - /** - * @inheritdoc - */ - createWidgets() { - const checkboxBar = $$(function() { - return this.div({class: 'checkbox-bar settings-view'}, () => { - return this.div({class: 'controls'}, () => { - return this.div({class: 'block text-line'}, () => { - return this.label( - { class: 'icon icon-info' }, - 'Tip: The order in which items are selected determines the order of the output.' - ); - }); - }); - }); - }); - - checkboxBar.appendTo(this); - - // Ensure that button clicks are actually handled. - this.on('mousedown', ({target}) => { - if ($(target).hasClass('checkbox-input')) { return false; } - if ($(target).hasClass('checkbox-label-text')) { return false; } - }); - - return super.createWidgets(); - } - - /** - * @inheritdoc - */ - invokeOnDidConfirm() { - if (this.onDidConfirm) { - return this.onDidConfirm(this.selectedItems, this.getMetadata()); - } - } -}; +class View extends MultiSelectionView {} diff --git a/lib/Refactoring/Utility/MultiSelectionView.js b/lib/Refactoring/Utility/MultiSelectionView.js index ce6c5019..68ab9fab 100644 --- a/lib/Refactoring/Utility/MultiSelectionView.js +++ b/lib/Refactoring/Utility/MultiSelectionView.js @@ -76,6 +76,27 @@ class MultiSelectionView extends SelectListView { * Creates additional for the view. */ createWidgets() { + const checkboxBar = $$(function() { + return this.div({class: 'checkbox-bar settings-view'}, () => { + return this.div({class: 'controls'}, () => { + return this.div({class: 'block text-line'}, () => { + return this.label( + { class: 'icon icon-info' }, + 'Tip: The order in which items are selected determines the order of the output.' + ); + }); + }); + }); + }); + + checkboxBar.appendTo(this); + + // Ensure that button clicks are actually handled. + this.on('mousedown', ({target}) => { + if ($(target).hasClass('checkbox-input')) { return false; } + if ($(target).hasClass('checkbox-label-text')) { return false; } + }); + const cancelButtonText = this.getCancelButtonText(); const confirmButtonText = this.getConfirmButtonText(); @@ -86,8 +107,8 @@ class MultiSelectionView extends SelectListView { }, cancelButtonText); this.button({ class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' - }, confirmButtonText); - return this.div({class: 'clear-float'}); + }, confirmButtonText) + return this.div({ class: 'clear-float' }); }); }); From 7afc0239b1529e2bb4eb785a3d51ec15661c8c29 Mon Sep 17 00:00:00 2001 From: Mohammad Amin Chitgarha Date: Tue, 19 Jul 2022 03:10:37 +0430 Subject: [PATCH 5/6] Remove unused comments, other code improvements --- lib/Refactoring/AbstractProvider.js | 3 +-- lib/Refactoring/ConstructorGenerationProvider.js | 1 - lib/Refactoring/DocblockProvider.js | 2 +- lib/Refactoring/ExtractMethodProvider.js | 2 +- lib/Refactoring/ExtractMethodProvider/Builder.js | 1 - lib/Refactoring/ExtractMethodProvider/ParameterParser.js | 1 - lib/Refactoring/ExtractMethodProvider/View.js | 1 - lib/Refactoring/GetterSetterProvider.js | 2 +- lib/Refactoring/IntroducePropertyProvider.js | 1 - lib/Refactoring/OverrideMethodProvider.js | 1 - lib/Refactoring/StubAbstractMethodProvider.js | 1 - lib/Refactoring/StubInterfaceMethodProvider.js | 1 - lib/Refactoring/Utility/DocblockBuilder.js | 6 ------ lib/Refactoring/Utility/FunctionBuilder.js | 3 --- lib/Refactoring/Utility/MultiSelectionView.js | 5 +++-- lib/Refactoring/Utility/TypeHelper.js | 1 - lib/UseStatementHelper.js | 1 - 17 files changed, 7 insertions(+), 26 deletions(-) diff --git a/lib/Refactoring/AbstractProvider.js b/lib/Refactoring/AbstractProvider.js index 2ac02916..61c8f869 100644 --- a/lib/Refactoring/AbstractProvider.js +++ b/lib/Refactoring/AbstractProvider.js @@ -4,7 +4,6 @@ * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * DS205: Consider reworking code to avoid use of IIFEs - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ @@ -143,7 +142,7 @@ class AbstractProvider { * @param {TextEditor} editor TextEditor to register events to. */ // eslint-disable-next-line no-unused-vars - registerEvents(editor) {} + registerEvents(_) {} /** * Sets the snippet manager diff --git a/lib/Refactoring/ConstructorGenerationProvider.js b/lib/Refactoring/ConstructorGenerationProvider.js index 234a336e..20ea2817 100644 --- a/lib/Refactoring/ConstructorGenerationProvider.js +++ b/lib/Refactoring/ConstructorGenerationProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/DocblockProvider.js b/lib/Refactoring/DocblockProvider.js index f1a9f83b..02612d44 100644 --- a/lib/Refactoring/DocblockProvider.js +++ b/lib/Refactoring/DocblockProvider.js @@ -1,7 +1,7 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/ExtractMethodProvider.js b/lib/Refactoring/ExtractMethodProvider.js index 14317c43..baa64b5e 100644 --- a/lib/Refactoring/ExtractMethodProvider.js +++ b/lib/Refactoring/ExtractMethodProvider.js @@ -3,7 +3,7 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/ExtractMethodProvider/Builder.js b/lib/Refactoring/ExtractMethodProvider/Builder.js index 0d4d7691..ec391dd3 100644 --- a/lib/Refactoring/ExtractMethodProvider/Builder.js +++ b/lib/Refactoring/ExtractMethodProvider/Builder.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/ExtractMethodProvider/ParameterParser.js b/lib/Refactoring/ExtractMethodProvider/ParameterParser.js index 7d429b46..19d8e2d5 100644 --- a/lib/Refactoring/ExtractMethodProvider/ParameterParser.js +++ b/lib/Refactoring/ExtractMethodProvider/ParameterParser.js @@ -2,7 +2,6 @@ * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * DS202: Simplify dynamic range loops - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/ExtractMethodProvider/View.js b/lib/Refactoring/ExtractMethodProvider/View.js index d29c78c4..40306a09 100644 --- a/lib/Refactoring/ExtractMethodProvider/View.js +++ b/lib/Refactoring/ExtractMethodProvider/View.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/GetterSetterProvider.js b/lib/Refactoring/GetterSetterProvider.js index fd1f5c12..331bbcdb 100644 --- a/lib/Refactoring/GetterSetterProvider.js +++ b/lib/Refactoring/GetterSetterProvider.js @@ -3,7 +3,7 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass + * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/IntroducePropertyProvider.js b/lib/Refactoring/IntroducePropertyProvider.js index 62954262..869285b9 100644 --- a/lib/Refactoring/IntroducePropertyProvider.js +++ b/lib/Refactoring/IntroducePropertyProvider.js @@ -2,7 +2,6 @@ * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * DS202: Simplify dynamic range loops - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/OverrideMethodProvider.js b/lib/Refactoring/OverrideMethodProvider.js index bb223a9a..276f3342 100644 --- a/lib/Refactoring/OverrideMethodProvider.js +++ b/lib/Refactoring/OverrideMethodProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/StubAbstractMethodProvider.js b/lib/Refactoring/StubAbstractMethodProvider.js index 852fa0ad..1f7e8073 100644 --- a/lib/Refactoring/StubAbstractMethodProvider.js +++ b/lib/Refactoring/StubAbstractMethodProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/StubInterfaceMethodProvider.js b/lib/Refactoring/StubInterfaceMethodProvider.js index 05bcfee9..e73a4b72 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider.js +++ b/lib/Refactoring/StubInterfaceMethodProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/Utility/DocblockBuilder.js b/lib/Refactoring/Utility/DocblockBuilder.js index a50c91b2..3e596ad7 100644 --- a/lib/Refactoring/Utility/DocblockBuilder.js +++ b/lib/Refactoring/Utility/DocblockBuilder.js @@ -15,12 +15,6 @@ class DocblockBuilder { * * @return {String} */ - constructor() { - this.buildForMethod = this.buildForMethod.bind(this); - this.buildForProperty = this.buildForProperty.bind(this); - this.buildByLines = this.buildByLines.bind(this); - } - buildForMethod(parameters, returnType, generateDescriptionPlaceholders, tabText) { if (generateDescriptionPlaceholders == null) { generateDescriptionPlaceholders = true; } if (tabText == null) { tabText = ''; } diff --git a/lib/Refactoring/Utility/FunctionBuilder.js b/lib/Refactoring/Utility/FunctionBuilder.js index 3d2590ee..eab881b3 100644 --- a/lib/Refactoring/Utility/FunctionBuilder.js +++ b/lib/Refactoring/Utility/FunctionBuilder.js @@ -1,6 +1,5 @@ /* * decaffeinate suggestions: - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ @@ -59,8 +58,6 @@ class FunctionBuilder { * @var {Number|null} */ this.maxLineLength = null; - - this.build = this.build.bind(this); } /** diff --git a/lib/Refactoring/Utility/MultiSelectionView.js b/lib/Refactoring/Utility/MultiSelectionView.js index 68ab9fab..1a6b5932 100644 --- a/lib/Refactoring/Utility/MultiSelectionView.js +++ b/lib/Refactoring/Utility/MultiSelectionView.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ @@ -59,7 +58,9 @@ class MultiSelectionView extends SelectListView { this.addClass('php-ide-serenata-refactoring-multi-selection-view'); this.list.addClass('mark-active'); - if (this.panel == null) { this.panel = atom.workspace.addModalPanel({item: this, visible: false}); } + if (this.panel == null) { + this.panel = atom.workspace.addModalPanel({ item: this, visible: false }); + } return this.createWidgets(); } diff --git a/lib/Refactoring/Utility/TypeHelper.js b/lib/Refactoring/Utility/TypeHelper.js index 5dd99282..40d29e5d 100644 --- a/lib/Refactoring/Utility/TypeHelper.js +++ b/lib/Refactoring/Utility/TypeHelper.js @@ -1,7 +1,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/UseStatementHelper.js b/lib/UseStatementHelper.js index fde0b5a6..3ee18cd3 100644 --- a/lib/UseStatementHelper.js +++ b/lib/UseStatementHelper.js @@ -4,7 +4,6 @@ * DS104: Avoid inline assignments * DS202: Simplify dynamic range loops * DS205: Consider reworking code to avoid use of IIFEs - * DS206: Consider reworking classes to avoid initClass * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ From d16aecf43235d9186eeabd7fe84de3385c3d0ffb Mon Sep 17 00:00:00 2001 From: Mohammad Amin Chitgarha Date: Tue, 19 Jul 2022 03:47:27 +0430 Subject: [PATCH 6/6] Add some missing semicolons and remove unnecessary code --- lib/Refactoring/AbstractProvider.js | 41 ++++++++----------- .../ConstructorGenerationProvider.js | 4 +- .../ConstructorGenerationProvider/View.js | 2 +- lib/Refactoring/DocblockProvider.js | 1 - lib/Refactoring/ExtractMethodProvider.js | 1 - lib/Refactoring/GetterSetterProvider.js | 1 - lib/Refactoring/GetterSetterProvider/View.js | 2 +- lib/Refactoring/IntroducePropertyProvider.js | 1 - .../OverrideMethodProvider/View.js | 2 +- .../StubAbstractMethodProvider/View.js | 2 +- .../StubInterfaceMethodProvider/View.js | 2 +- lib/Refactoring/Utility/MultiSelectionView.js | 2 +- 12 files changed, 26 insertions(+), 35 deletions(-) diff --git a/lib/Refactoring/AbstractProvider.js b/lib/Refactoring/AbstractProvider.js index 61c8f869..ef8ba62c 100644 --- a/lib/Refactoring/AbstractProvider.js +++ b/lib/Refactoring/AbstractProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS205: Consider reworking code to avoid use of IIFEs * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ @@ -79,19 +78,17 @@ class AbstractProvider { return atom.workspace.onDidAddPane(observedPane => { const panes = atom.workspace.getPanes(); - return (() => { - const result = []; + const result = []; - for (const pane of panes) { - if (pane !== observedPane) { - result.push(this.registerEventsForPane(pane)); - } else { - result.push(undefined); - } + for (const pane of panes) { + if (pane !== observedPane) { + result.push(this.registerEventsForPane(pane)); + } else { + result.push(undefined); } + } - return result; - })(); + return result; }); } @@ -101,23 +98,21 @@ class AbstractProvider { * @param {Pane} pane */ registerEventsForPane(pane) { - return (() => { - const result = []; + const result = []; - for (const paneItem of pane.items) { - if (atom.workspace.isTextEditor(paneItem)) { - if (/text.html.php$/.test(paneItem.getGrammar().scopeName)) { - result.push(this.registerEvents(paneItem)); - } else { - result.push(undefined); - } + for (const paneItem of pane.items) { + if (atom.workspace.isTextEditor(paneItem)) { + if (/text.html.php$/.test(paneItem.getGrammar().scopeName)) { + result.push(this.registerEvents(paneItem)); } else { result.push(undefined); } + } else { + result.push(undefined); } + } - return result; - })(); + return result; } /** @@ -139,7 +134,7 @@ class AbstractProvider { /** * Registers the necessary event handlers. * - * @param {TextEditor} editor TextEditor to register events to. + * @param {TextEditor} _ TextEditor to register events to. */ // eslint-disable-next-line no-unused-vars registerEvents(_) {} diff --git a/lib/Refactoring/ConstructorGenerationProvider.js b/lib/Refactoring/ConstructorGenerationProvider.js index 20ea2817..a11a5983 100644 --- a/lib/Refactoring/ConstructorGenerationProvider.js +++ b/lib/Refactoring/ConstructorGenerationProvider.js @@ -13,7 +13,7 @@ module.exports = /** * Provides docblock generation and maintenance capabilities. */ -class DocblockProvider extends AbstractProvider { +class ConstructorGenerationProvider extends AbstractProvider { /** * @param {Object} typeHelper * @param {Object} functionBuilder @@ -170,7 +170,7 @@ class DocblockProvider extends AbstractProvider { generateConstructor(editor, triggerPosition, items, tabText, indentationLevel, maxLineLength) { const metadata = { editor, - position : triggerPosition, + position: triggerPosition, tabText, indentationLevel, maxLineLength diff --git a/lib/Refactoring/ConstructorGenerationProvider/View.js b/lib/Refactoring/ConstructorGenerationProvider/View.js index 787a8513..b386767d 100644 --- a/lib/Refactoring/ConstructorGenerationProvider/View.js +++ b/lib/Refactoring/ConstructorGenerationProvider/View.js @@ -2,4 +2,4 @@ const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView {} +class View extends MultiSelectionView {}; diff --git a/lib/Refactoring/DocblockProvider.js b/lib/Refactoring/DocblockProvider.js index 02612d44..eaa73fad 100644 --- a/lib/Refactoring/DocblockProvider.js +++ b/lib/Refactoring/DocblockProvider.js @@ -1,7 +1,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/ExtractMethodProvider.js b/lib/Refactoring/ExtractMethodProvider.js index baa64b5e..19578dd6 100644 --- a/lib/Refactoring/ExtractMethodProvider.js +++ b/lib/Refactoring/ExtractMethodProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/GetterSetterProvider.js b/lib/Refactoring/GetterSetterProvider.js index 331bbcdb..8643f99a 100644 --- a/lib/Refactoring/GetterSetterProvider.js +++ b/lib/Refactoring/GetterSetterProvider.js @@ -3,7 +3,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/GetterSetterProvider/View.js b/lib/Refactoring/GetterSetterProvider/View.js index 787a8513..b386767d 100644 --- a/lib/Refactoring/GetterSetterProvider/View.js +++ b/lib/Refactoring/GetterSetterProvider/View.js @@ -2,4 +2,4 @@ const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView {} +class View extends MultiSelectionView {}; diff --git a/lib/Refactoring/IntroducePropertyProvider.js b/lib/Refactoring/IntroducePropertyProvider.js index 869285b9..096e4a8e 100644 --- a/lib/Refactoring/IntroducePropertyProvider.js +++ b/lib/Refactoring/IntroducePropertyProvider.js @@ -1,7 +1,6 @@ /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns - * DS202: Simplify dynamic range loops * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ diff --git a/lib/Refactoring/OverrideMethodProvider/View.js b/lib/Refactoring/OverrideMethodProvider/View.js index 787a8513..b386767d 100644 --- a/lib/Refactoring/OverrideMethodProvider/View.js +++ b/lib/Refactoring/OverrideMethodProvider/View.js @@ -2,4 +2,4 @@ const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView {} +class View extends MultiSelectionView {}; diff --git a/lib/Refactoring/StubAbstractMethodProvider/View.js b/lib/Refactoring/StubAbstractMethodProvider/View.js index 787a8513..b386767d 100644 --- a/lib/Refactoring/StubAbstractMethodProvider/View.js +++ b/lib/Refactoring/StubAbstractMethodProvider/View.js @@ -2,4 +2,4 @@ const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView {} +class View extends MultiSelectionView {}; diff --git a/lib/Refactoring/StubInterfaceMethodProvider/View.js b/lib/Refactoring/StubInterfaceMethodProvider/View.js index 787a8513..b386767d 100644 --- a/lib/Refactoring/StubInterfaceMethodProvider/View.js +++ b/lib/Refactoring/StubInterfaceMethodProvider/View.js @@ -2,4 +2,4 @@ const MultiSelectionView = require('../Utility/MultiSelectionView'); module.exports = -class View extends MultiSelectionView {} +class View extends MultiSelectionView {}; diff --git a/lib/Refactoring/Utility/MultiSelectionView.js b/lib/Refactoring/Utility/MultiSelectionView.js index 1a6b5932..4426e3c7 100644 --- a/lib/Refactoring/Utility/MultiSelectionView.js +++ b/lib/Refactoring/Utility/MultiSelectionView.js @@ -108,7 +108,7 @@ class MultiSelectionView extends SelectListView { }, cancelButtonText); this.button({ class: 'btn btn-success inline-block-tight pull-right icon icon-gear button--confirm' - }, confirmButtonText) + }, confirmButtonText); return this.div({ class: 'clear-float' }); }); });