Js-beautify: Daisy-Chain-Einrückung führt zu Übereinrückung

Erstellt am 20. Juni 2014  ·  18Kommentare  ·  Quelle: beautify-web/js-beautify

Verwenden Sie dies über https://github.com/enginespot/js-beautify-sublime

Erwartet:

.foo()
.bar();

Tatsächlich:

  .foo()
  .bar();

Um das Problem zu veranschaulichen: Die aktuelle Einrückung kann zu EOFs wie diesen führen:

      });
    });
})();

Das sieht für mich wie ein Fehler aus und wird mich dazu veranlassen, nach der Ursache zu suchen – oder schlimmer noch, mich für die wahren Ursachen blind machen =(

enhancement

Hilfreichster Kommentar

Ich muss dieser Anfrage +1 geben, das ist besonders praktisch, wenn man mit Promises arbeitet.

Promise.resolve()
.then(function() {
  return foo.bar()
})
.then(function() {
  return foo.baz();
})
.then(function() {
 //...
}) //...
//...

Diese Verkettung kann eine Weile andauern, besonders wenn Sie einen komplizierteren API-Endpunkt schreiben, und wenn Sie nach unten schauen, sind Sie ständig überrascht, wie die Einrückung relativ zu etwas in der Nähe endet.

Ich glaube, es ist wichtig, dass alle abschließenden Einkerbungen eine Tiefendifferenz von der nächsten sind.

Alle 18 Kommentare

Könnten Sie uns die vollständige Eingabe und die erwartete Ausgabe zusammen mit Ihrer Konfiguration geben? Ich habe Schwierigkeiten, Ihr erwartetes Fragment (das ehrlich gesagt falsch aussieht) mit den schließenden Blöcken zu korrelieren. Danke!

Wie vieles in diesem Bereich ist dies natürlich eher eine Frage der persönlichen Vorlieben und Gewohnheiten als eine objektive Wahrheit.

Nach der Verarbeitung sehen Sie möglicherweise Folgendes:

(function () {
    'use strict';

    angular
        .module('module', [])
        .directive('appVersion', ['version',
            function (version) {
                return function (scope, elm, attrs) {
                    elm.text(version);
                };
            }
        ])
        .directive('foo', [

            function () {
                return {};
            }
        ])
        .directive('bar', [

            function () {
                return {};
            }
        ]);
})();

Das würde mir gefallen:

(function () {
    'use strict';

    angular
    .module('module', [])
    .directive('appVersion', ['version',
        function (version) {
            return function (scope, elm, attrs) {
                elm.text(version);
            };
        }
    ])
    .directive('foo', [
        function () {
            return {};
        }
    ])
    .directive('bar', [
        function () {
            return {};
        }
    ]);
})();

Dies ist meine Konfiguration:

{
    "indent_level": 0,
    "indent_with_tabs": true,
    "preserve_newlines": true,
    "max_preserve_newlines": 5,
    "jslint_happy": true,
    "brace_style": "collapse",
    "keep_array_indentation": false,
    "keep_function_indentation": false,
    "space_before_conditional": true,
    "break_chained_methods": true,
    "eval_code": false,
    "unescape_strings": false,
    "wrap_line_length": 0,

    // jsbeautify options
    "format_on_save": true,
    "use_original_indentation": true
}

+1

Das Problem, von dem Sie sprechen, ist dieser eine Einzug:

    angular
        .module('module', [])

Ich werde mir eine Minute Zeit nehmen, um einen Hauch von Ehrfurcht zu empfinden, dass wir so nah an dem sind, was Sie sehen möchten. Früher wären wir nicht einmal in die Nähe gekommen. :Lächeln:

Die Einrückung dort soll klarstellen, welche Elemente Teil einer bestimmten Aussage sind. Im allgemeinen Fall ist die Einrückung grundsätzlich korrekt. In diesem speziellen Fall haben Sie eine sehr lange Aussage, aber bei #200 weiß der Verschönerer nicht, dass das keine signifikanten Aussagen nach dieser sind. Der Beautifier soll kein vollständig konfigurierbarer Formatierer sein – er soll den allgemeinen Fall ansprechen

Um dieser Diskussion etwas Tiefe zu verleihen, werfen Sie bitte einen Blick auf diese Beispiele und sagen Sie mir, wie die Formatierung aussehen sollte.

alpha
    .cooker(function() {
        some
            .thing()
            .should()
            .happen();
        elsewhere
            .some_other_thing()
            .should()
            .happen();
    })
    .thenclose()
beta(zeta);
omega
    .cage(function() {
        random
            .things()
            .should()
            .happen();
        elsewhere
            .some_other_thing()
            .should()
            .happen();
    })
    .thendie()

Ich werde mir eine Minute Zeit nehmen, um einen Hauch von Ehrfurcht zu empfinden, dass wir so nah an dem sind, was Sie sehen möchten.

Absolut! =)

In Bezug auf die Einrückung denke ich, dass Ihr Beispiel so aussehen sollte:

alpha
.cooker(function() {
    some
        .thing()
        .should()
        .happen();
    elsewhere
        .some_other_thing()
        .should()
        .happen();
})
.thenclose()
beta(zeta);
omega
.cage(function() {
    random
        .things()
        .should()
        .happen();
    elsewhere
        .some_other_thing()
        .should()
        .happen();
})
.thendie()

Auch hier gilt die Maxime wie bei den geschweiften Klammern: Anfang und Ende sollten an der gleichen Einrückung liegen. Darüber hinaus schreiben die Codekonventionen von Douglas Crockford das switch genau so vor, wie sie es tun, um übermäßige Einrückungen zu vermeiden.

Abgesehen davon, dass js-beautify standardmäßig nicht crockford folgt, und wenn Sie das obige über jslint ausführen, wird es sich beschweren, dass .cooker( an der falschen Einrückung ist.

In Ihrem Beispiel scheint es mir viel zu leicht, dass beta(zeta); übersehen wird.
Außerdem zeigen Sie einige Daisy-Chains-Einrückungen und andere nicht. Welche Logik sollte der Verschönerer anwenden, um zu entscheiden, welche einrücken und welche nicht?

Ich werde dies offen lassen - das von Ihnen angegebene Beispiel scheint auf AngularJS zu basieren, sodass diese Redewendung im Laufe der Zeit eine breitere Akzeptanz finden kann. Aber es ist nicht etwas, das wir in absehbarer Zeit einbauen können.

Es tut mir schrecklich leid: Ich habe den Einzug verpfuscht. Keiner von ihnen sollte eingerückt sein. Und damit beta(zeta); nicht übersehen wird, würde ich leere Zeilen verwenden, etwa so:

alpha
.cooker(function() {
    some
    .thing()
    .should()
    .happen();

    elsewhere
    .some_other_thing()
    .should()
    .happen();
})
.thenclose();

beta(zeta);

omega
.cage(function() {
    random
    .things()
    .should()
    .happen();

    elsewhere
    .some_other_thing()
    .should()
    .happen();
})
.thendie();

Wie ich eingangs sagte, ich denke, es ist eine Frage des persönlichen Geschmacks. Und speziell bei einsträngigen Ketten bin ich weniger geneigt, die Einbuchtung zu verkleinern. Aber ich finde den mehrzeiligen Fall sehr schlecht und gemischte Stile wären schrecklich, also würde ich auf jeden Fall immer an der Strategie mit weniger Einrückungen festhalten.

Sie können sich #485 ansehen. Mit diesem bevorstehenden Fix bleibt Folgendes nun unverändert, wenn es durch die Verschönerung geht:

(function () {
    'use strict';

    angular
        .module('module', [])
        .directive('appVersion', ['version', function (version) {
            return function (scope, elm, attrs) {
                elm.text(version);
            };
        }])
        .directive('foo', [function () {
            return {};
        }])
        .directive('bar', [function () {
            return {};
        }]);
})();

Immer noch nicht das, was Sie möchten, aber der Verschönerer zwingt die Funktionsdeklaration nicht mehr zu einem Zeilenumbruch (während ein Zeilenumbruch immer noch respektiert wird, wenn Sie ihn einfügen).

Ich muss dieser Anfrage +1 geben, das ist besonders praktisch, wenn man mit Promises arbeitet.

Promise.resolve()
.then(function() {
  return foo.bar()
})
.then(function() {
  return foo.baz();
})
.then(function() {
 //...
}) //...
//...

Diese Verkettung kann eine Weile andauern, besonders wenn Sie einen komplizierteren API-Endpunkt schreiben, und wenn Sie nach unten schauen, sind Sie ständig überrascht, wie die Einrückung relativ zu etwas in der Nähe endet.

Ich glaube, es ist wichtig, dass alle abschließenden Einkerbungen eine Tiefendifferenz von der nächsten sind.

:+1:

Ich glaube, es ist wichtig, dass alle abschließenden Einkerbungen eine Tiefendifferenz von der nächsten sind.

Für mich ist dies der entscheidende Beweis dafür, dass zusätzliche Einrückungen irreführend und letztendlich ein Fehler sind. Mir ist klar, dass einige das Gefühl haben, dass es einen gewissen Sinn gibt

Promise.resolve()
  .then(function() {
    return foo.bar()
  })

scheint widerzuspiegeln, dass das then() in gewissem Sinne eine Eltern-Kind-Beziehung mit Promise.resolve() hat, aber wenn das stimmt, dann hat auch jedes nachfolgende then() diese Beziehung mit dem zurück then() . Natürlich gibt es wirklich _keine_ solche Eltern-Kind-Beziehung, und Einrücken, als ob es ganz nach unten gäbe, würde ein großes Durcheinander anrichten, also tut es niemand. Aber das Einrücken der ersten then() macht nur ein _kleines_ Durcheinander statt eines riesigen—es ist nur so, dass einige Leute bereit zu sein scheinen, dieses kleine Durcheinander in Kauf zu nehmen, während einige von uns es vorziehen, _irgendeinen_ Durcheinander in unserem Code zu haben, wenn wir können ihm helfen.

Es mag schön sein, den visuellen Hinweis zu haben, den die Einrückung bietet, aber in diesem Fall überladen sie die Bedeutung der Einrückung – sie geben nicht nur einen neuen Gültigkeitsbereich an, sondern auch eine verkettete Methode. Wir haben jedoch bereits das . , um eine verkettete Methode anzuzeigen, und da das . am Anfang des Textes in der Zeile steht, bietet es wirklich alle erforderlichen (Pseudo-)Einzüge solange man darauf achtet.

Es ist also nicht _eigentlich_ _nur _ eine Frage der persönlichen Vorlieben – es ist eine Frage der Vor- und Nachteile beider Ansätze. (Persönliche Vorlieben _sind natürlich beteiligt, weil einige sich vielleicht nicht um bestimmte Nachteile oder Vorteile kümmern, aber die Diskussion kann fruchtbarer sein, wenn wir diskutieren, was diese Vor- und Nachteile sind_, anstatt nur zu sagen "Ich bevorzuge _x_" oder "Ich bevorzuge _y_".)

Ich denke, dass die Argumente stark sind, dass die Nachteile einer zusätzlichen Einrückung erheblich sind, während die Vorteile auf andere Weise erzielt werden können.

Nachteile der zusätzlichen Einrückung für verkettete Methoden:

  • Ihre Einrückung ist kein zuverlässiger Indikator für den Umfang mehr
  • Ihre schließende Interpunktion lässt Sie wahrscheinlich glauben, dass Sie einen Fehler gemacht haben

Leistungen:

  • Sie erhalten einen größeren visuellen Hinweis auf die Methodenverkettung als nur ein . allein bietet (ABER Sie _tun_ diesen Hinweis mit nur einem . )

+1

+1 Dies führt zu Expected exactly one space between '{a}' and '{b}' Fehlern in jslint.

Beispiel:

gulp.task('changelog', function () {
    return gulp.src('CHANGELOG.md', {
            buffer: false
        })
        .pipe(conventionalChangelog({
            preset: 'angular' // Or to any other commit message convention you use.
        }))
        .pipe(gulp.dest('./'));
});

Fehler:

4   Expected 'buffer' at column 9, not column 13.    buffer: false
5   Expected '}' at column 5, not column 9.  })

Richtiger Weg (für jslint):

gulp.task('changelog', function () {
    return gulp.src('CHANGELOG.md', {
        buffer: false
    })
        .pipe(conventionalChangelog({
            preset: 'angular' // Or to any other commit message convention you use.
        }))
        .pipe(gulp.dest('./'));
});

Ich würde es sehr bevorzugen, dies als Option zu haben, hauptsächlich um unnötige zusätzliche Einrückungen bei der Verkettung von Versprechen zu vermeiden:

  // fetch `config.json` and then set as constant
  $http.get('config.json').then(function(response) {
    angular.module('myApp').constant('CONFIG', response.data);
  })
  .then(function() {
    angular.bootstrap(document, ['myApp']);
  })
  .catch(function(err) {
    var message = (err && err.data || err && err.message);
    console.error('Unable to bootstrap application.', err);
    window.alert('Unable to bootstrap application.' + (message ? '\n\n' + message : ''));
  });

Ich denke, die zusätzliche Einrückung ist das Äquivalent zu:

try {
    // 4 spaces
  } // 2
  catch () {
    // 4
  }

Es ist sinnvoll, wenn sich das untergeordnete Token, das einen Einrückungsblock umschließt, in einer neuen Zeile von der Anfangsvariablen befindet:

    .module('module', function() {
      // .module starts on new line, so this block has 2 indents
    })

vs.

  angular.module('module', function() {
    // .module is on the same line as the initial variable angular, so this block has 1 indent
  })

Aber wenn alles in eine Zeile passt, sollte die doppelte Einrückung nicht vorkommen.

(So ​​wie es aussieht, würde das Obige gelinst/erwartet werden als:)

angular.module('module', function() {
    // double indent
  });

Ich habe dies als Verbesserung markiert.
Ich bestreite nicht, dass es eine gute Idee ist, ich habe einfach keine Zeit.

Alle "+1"-ler und diejenigen, die kommentiert haben, können gerne einen Pull-Request beisteuern.

+1 wollen

Dazu habe ich eine PR eröffnet

https://github.com/beautify-web/js-beautify/pull/927

Wenn die kontinuierliche Integration endlich den PR-Status aktualisieren würde, sollte sie zum Zusammenführen bereit sein.

+1 Das ist höllisch langweilig

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen