// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:math' as math;

import 'package:js/js.dart';

import 'package:dart_style/dart_style.dart';

@JS()
@anonymous
class FormatResult {
  external factory FormatResult({String code, String error});
  external String get code;
  external String get error;
}

@JS('exports.formatCode')
external set formatCode(Function formatter);

void main() {
  formatCode = allowInterop((String source) {
    var formatter = new DartFormatter();

    var exception;
    try {
      return new FormatResult(code: new DartFormatter().format(source));
    } on FormatterException catch (err) {
      // Couldn't parse it as a compilation unit.
      exception = err;
    }

    // Maybe it's a statement.
    try {
      return new FormatResult(code: formatter.formatStatement(source));
    } on FormatterException catch (err) {
      // There is an error when parsing it both as a compilation unit and a
      // statement, so we aren't sure which one the user intended. As a
      // heuristic, we'll choose that whichever one we managed to parse more of
      // before hitting an error is probably the right one.
      if (_firstOffset(exception) < _firstOffset(err)) {
        exception = err;
      }
    }

    // If we get here, it couldn't be parsed at all.
    return new FormatResult(code: source, error: "$exception");
  });
}

/// Returns the offset of the error nearest the beginning of the file out of
/// all the errors in [exception].
int _firstOffset(FormatterException exception) =>
    exception.errors.map((error) => error.offset).reduce(math.min);
