Inserts tokens before another token in a language definition or any other grammar.
Usage
This helper method makes it easy to modify existing languages. For example, the CSS language definition
not only defines CSS styling for CSS documents, but also needs to define styling for CSS embedded
in HTML through <style> elements. To do this, it needs to modify syntax_styler.get_lang('markup') and add the
appropriate tokens. However, syntax_styler.get_lang('markup') is a regular JS object literal, so if you do
this:
syntax_styler.get_lang('markup').style = {
};then the style token will be added (and processed) at the end. insert_before allows you to insert tokens
before existing tokens. For the CSS example above, you would use it like this:
grammar_insert_before('markup', 'cdata', {
'style': {
}
});Special cases
If the grammars of inside and insert have tokens with the same name, the tokens in inside's grammar
will be ignored.
This behavior can be used to insert tokens after before:
grammar_insert_before('markup', 'comment', {
'comment': syntax_styler.get_lang('markup').comment,
});Limitations
The main problem insert_before has to solve is iteration order. Since ES2015, the iteration order for object
properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
differently when keys are deleted and re-inserted. So insert_before can't be implemented by temporarily
deleting properties which is necessary to insert at arbitrary positions.
To solve this problem, insert_before doesn't actually insert the given tokens into the target object.
Instead, it will create a new object and replace all references to the target object with the new one. This
can be done without temporarily deleting properties, so the iteration order is well-defined.
However, only references that can be reached from syntax_styler.langs or insert will be replaced. I.e. if
you hold the target object in a variable, then the value of the variable will not change.
var oldMarkup = syntax_styler.get_lang('markup');
var newMarkup = grammar_insert_before('markup', 'comment', { ... });
assert(oldMarkup !== syntax_styler.get_lang('markup'));
assert(newMarkup === syntax_styler.get_lang('markup'));