How to add YAML syntax validation to ACE editor

Valentin Shamsnejad
5 min readFeb 17, 2020

--

Yes, it requires code.

Here at Jam, we heavily rely on the YAML format to write content for our chatbots. Everyday, our writers are using a YAML editor embedded in a webpage to create meaningful and interactive conversations.

Ace is an awesome code editor to embed in a web page, lots of great features that are expected from a code editor. But… wait… oh no. It doesn’t have a YAML syntax checker ! 😱

Let’s do this. Let’s plug a YAML syntax checker in Ace.

I’m working with VueJS as my front-end framework, but most of what I’ll explain here will happen outside of the framework. I’m sure you’ll figure out how to adapt it with your own tools.

Introduction

The goal here is to use the parse method from js-yaml, and plug its error output to Ace’s syntax validation system.

At first, I tried to follow Ace’s Creating or Extending an Edit Mode documentation, but the part about the workers for syntax validation is not very detailed.

Then I found Ace’s Syntax validation documentation, way more helpful. But still, I had some unanswered questions.

So I decided to copy paste the logic from the existing JSON syntax validation worker, and work my way through it until I got what I wanted.

In this post, I will explain how I ended up implemening it.

Let’s go !

The editor component

For starters, you need to already have a working ace editor running. Based on the Ace documentation, you need this :

<div id="editor">some text</div>
<script src="src/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
var editor = ace.edit("editor");
</script>

For my own app, I made a Vue component importing ace-builds and its webpack-resolver (I found this import trick here), and initialized the editor in the component’s mounted hook :

My Vue component with ace editor

You should be able to get something like this on your web page :

Example of yaml in Ace editor

Extend the yaml mode

You can see that I already imported a script named extendYamlMode.js line 10, and used it line 12 :

import extendYamlMode from './extendYamlMode.js'
extendYamlMode(ace)

This is the script where you will extend the YAML mode with an additional worker to manage the syntax validation.

It was recommended in the documentation to create a new language mode in order to add your own worker, so that’s what you’re going to do :

Then inside the block ace.define("ace/mode/yaml"... add the call to the worker, by copying the way it was done in mode-json.js : https://github.com/ajaxorg/ace-builds/blob/master/src-noconflict/mode-json.js#L299. The modifications needed are :

Add line 283 :

// Added requires for yaml syntax validation
require("ace/config").set("workerPath", "/yaml_linter")
var WorkerClient = require("../worker/worker_client").WorkerClient

Add line 316 :

// Added worker for yaml syntax validation
this.createWorker = function(session) {
var worker = new WorkerClient(["ace"], "ace/mode/yaml_worker", "YamlWorker");
worker.attachToDocument(session.getDocument());
worker.on("annotate", function(e) {
session.setAnnotations(e.data);
});
worker.on("terminate", function() {
session.clearAnnotations();
});
return worker;
};

The block inside ace.define("ace/mode/yaml"... now looks like this :

Modifications are line 10 and line 47
Halfway through, keep it up !

The web worker

Now the yaml mode for Ace is looking for a web worker at your.domain/yaml_linter/worker-yaml.js. I know it’s not written anywhere like this in the code we just wrote, but that’s how Ace does it, by convention.

Once again, we’re going to copy the way it was done for the json worker :

  • Create a file public/yaml_linter/worker-yaml.js (my folder for static resources is named public, it might be different for you)
  • Copy the content of worker-json.js from the folder src-noconflict in ace-builds : https://github.com/ajaxorg/ace-builds/blob/master/src-noconflict/worker-json.js
  • Replace alloccurences of json by yaml, and all occurences of Json by Yaml (what a hack lol)
  • But wait, this file is huuuge (> 2k lines !) and nobody wants to edit a big fatty like this. So we’re going to write our logic in another file, and just call it there. Replace the bloc ace.define("ace/mode/yaml/yaml_parse" ... by the following lines :
importScripts(self.location.origin + '/yaml_linter/yaml_parse.js');
ace.define("ace/mode/yaml/yaml_parse",[], yaml_parse);

This will look for a file inpublic/yaml_linter/yaml_parse.js which creates a method yaml_parse().

Almost there !

The yaml_parse method

Create the much needed separated file in public/yaml_linter/yaml_parse.js.

(Once again, it might not be the public folder for you)

Paste this code in the file :

yaml_parse.js

This will convert the errors raised by js-yaml into a format made for the ace syntax worker.

The last piece missing here is the file js-yaml.min.js . Copy it from the js-yaml lib : https://github.com/nodeca/js-yaml/blob/master/dist/js-yaml.min.js

Put the js-yaml.min.js with your other worker files, in the folder public/yaml_linter.

You should now, after all these efforts, get an error like this when your yaml is invalid :

It’s working, yeah !

The end

You did it.

Congratulations, you finally plugged js-yaml as a syntax validator for your embedded Ace editor.

I mean, I hope so. Otherwise it would mean I didn’t do a good job writing this article.

--

--