Определите, допустим ли синтаксис JavaScript в обработчике изменений ACE - PullRequest
23 голосов
/ 01 марта 2012

Я использую редактор 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's an error
  if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
  try{
    eval(editor.getSession().getValue());
  }catch(e){}
});

Однако:

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

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

editor.getSession().on('change',function(){
  setTimeout(function(){
    // bail out if ACE thinks there's 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, спросить, есть ли какие-либо ошибки или нет?

Ответы [ 4 ]

25 голосов
/ 19 мая 2012

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

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

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

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

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

// 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, когда аннотации меняются!

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

3 голосов
/ 30 марта 2012

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

Вот как я устанавливаю свой обратный вызов для включения '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);
        }
    }
}

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

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

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

2 голосов
/ 19 марта 2015

Я обнаружил, что вы можете подписать рабочие события в 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' и«ОК» событие:

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);
});
2 голосов
/ 02 марта 2012

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

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

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

...