How to add YAML syntax validation to ACE editor
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.
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 :
You should be able to get something like this on your web page :
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 :
- Make a file
extendYamlMode.js
- Copy the content of
mode-yaml.js
from the foldersrc-noconflict
inace-builds
: https://github.com/ajaxorg/ace-builds/blob/master/src-noconflict/mode-yaml.js - Add
export default (ace) => { ... }
around the whole file, to be able to give it a reference toace
when callingextendYamlMode(ace)
from the component importing this file
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 :
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 namedpublic
, it might be different for you) - Copy the content of
worker-json.js
from the foldersrc-noconflict
inace-builds
: https://github.com/ajaxorg/ace-builds/blob/master/src-noconflict/worker-json.js - Replace alloccurences of
json
byyaml
, and all occurences ofJson
byYaml
(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()
.
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 :
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 :
The end
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.