Подтвердить что ты не робот

Определите, является ли синтаксис JavaScript действительным в обработчике изменений ACE

Я использую редактор ACE для интерактивного редактирования JavaScript. Когда я устанавливаю редактор в режим JavaScript, ACE автоматически определяет, является ли код действительным или нет, с сообщением об ошибке и номером строки, выделенным, когда это не так.

Во время обработчика событий change я хочу определить, действительно ли ACE считает код действительным или нет, прежде чем я попытаюсь выполнить его eval(). Единственный способ, которым я думал, что я могу это сделать:

var jsMode = require("ace/mode/javascript").Mode;
var editor = ace.edit('mycode'), edEl = document.querySelector('#mycode');
editor.getSession().setMode(new jsMode);
editor.getSession().on('change',function(){
  // bail out if ACE thinks there an error
  if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
  try{
    eval(editor.getSession().getValue());
  }catch(e){}
});

Однако:

  • Опираясь на присутствие элемента в пользовательском интерфейсе с определенным классом, кажется ужасно хрупким, но что более важно,
  • Визуальное обновление для синтаксического анализа происходит после обратного вызова change.

Таким образом, мне действительно нужно подождать более 500 мс (задержка перед тем, как работает рабочий JavaScript):

editor.getSession().on('change',function(){
  setTimeout(function(){
    // bail out if ACE thinks there an error
    if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
    try{
      eval(editor.getSession().getValue());
    }catch(e){}
  },550); // Must be longer than timeout delay in javascript_worker.js
});

Есть ли лучший способ, что-то в недокументированном API для режима JS, спросить, есть ли какие-либо ошибки или нет?

4b9b3361

Ответ 1

Текущая сессия вызывает событие onChangeAnnotation при изменении аннотаций.

после этого новый набор аннотаций можно получить следующим образом

var annotations = editor.getSession().getAnnotations();

похоже, делает трюк. Он возвращает объект JSON, который имеет ключ row и массив как значение. Массив значений может иметь более одного объекта, в зависимости от того, существует ли более чем одна аннотация для каждой строки.

структура выглядит следующим образом (скопировано из firebug - для теста script, который я написал)

// annotations would look like
({

82:[
    {/*annotation*/
        row:82, 
        column:22, 
        text:"Use the array literal notation [].", 
        type:"warning", 
        lint:{/*raw output from jslint*/}
    }
],

rownumber : [ {anotation1}, {annotation2} ],

...

});

так..

editor.getSession().on("changeAnnotation", function(){

    var annot = editor.getSession().getAnnotations();

    for (var key in annot){
        if (annot.hasOwnProperty(key))
            console.log("[" + annot[key][0].row + " , " + annot[key][0].column + "] - \t" + annot[key][0].text);
    }

});

// thanks http://stackoverflow.com/a/684692/1405348 for annot.hasOwnProperty(key) :)

должен предоставить вам список всех аннотаций в текущем сеансе редактирования Ace, когда аннотации меняются!

Надеюсь, это поможет!

Ответ 2

Я нашел решение, которое, вероятно, быстрее, чем пересечение DOM. Сеанс редактора имеет метод getAnnotations, который вы можете использовать. Каждая аннотация имеет тип, который показывает, являются ли они ошибкой или нет.

Вот как я установил свой обратный вызов для on 'change'

function callback() {
    var annotation_lists = window.aceEditor.getSession().getAnnotations();
    var has_error = false;

    // Unfortunately, you get back a list of lists. However, the first list is
    //   always length one (but not always index 0)
    go_through:
    for (var l in annotation_lists) {
        for (var a in annotation_lists[l]) {
            var annotation = annotation_lists[l][a];
            console.log(annotation.type);
            if (annotation.type === "error") {
                has_error = true;
                break go_through;
            }
        }
    }

    if (!has_error) {
        try {
            eval(yourCodeFromTextBox);
            prevCode = yourCodeFromTextBox;
        }
        catch (error) {
            eval(prevCode);
        }
    }
}

Насколько я знаю, есть два других типа аннотаций: "предупреждение" и "информация", на всякий случай, если вы также захотите проверить их.

Я отслеживал прочный код, который работал в глобальной (ну, вне области функции обратного вызова), потому что часто бывают ошибки в коде, но не в списке аннотаций. В этом случае при определении кода с ошибкой это будет код и eval вместо старого кода.

Хотя кажется, что два анализа будут медленнее, мне кажется, что производительность пока не так уж плоха.

Ответ 3

Ace использует JsHint внутренне (в worker), и, как вы можете видеть в файле, выдается событие:

this.sender.emit("jslint", lint.errors);

Вы можете подписаться на это событие или сами вызвать код JSHint (это довольно короткий).

Ответ 4

Я обнаружил, что вы можете подписаться на рабочие события в Ace 1.1.7:

Для кода javascript подпишитесь на событие "jslint":

session.setMode('ace/mode/javascript}');
session.on('changeMode', function() {
  if (session.$worker) {
    session.$worker.on('jslint', function(lint) {
      var messages = lint.data, types;
      if (!messages.length) return ok();
      types = messages.map(function(item) {
        return item.type;
      });
      types.indexOf('error') !== -1 ? ko() : ok();
    });
  }
});

Для кода JSON подпишите "error" и "ok":

session.setMode('ace/mode/json');
session.on('changeMode', function() {

  // session.$worker is available when 'changeMode' event triggered
  // You could subscribe worker events here, whatever changes to the
  // content will trigger 'error' or 'ok' events.

  session.$worker.on('error', ko);
  session.$worker.on('ok', ok);
});