mongodb-ace-mode

MongoDB Mode for the ACE Editor

Usage no npm install needed!

<script type="module">
  import mongodbAceMode from 'https://cdn.skypack.dev/mongodb-ace-mode';
</script>

README

mongodb-ace-mode

ACE mode that provides highlighting for MongoDB

Installation

npm install --save mongodb-ace-mode

Related

Highlighting Rules

Operators -> ace_function

MongoDB operator highlighting

Why? Mental model of operators to functions. (e.g. $avg: 'a', avg(a))

Given:

max_cpi: {$max: "$trends.icecream_cpi"}
<div class="ace_line" style="height:15px">
  <span class="ace_identifier">max_cpi</span>
  <span class="ace_punctuation ace_operator">:</span>
  <span class="ace_paren ace_lparen">{</span>
  <span class="ace_support ace_function">$max</span>
  <span class="ace_punctuation ace_operator">:</span>
  <span class="ace_string ace_quasi ace_start">"</span>
  <span class="ace_variable ace_language">$trends.icecream_cpi</span>
  <span class="ace_string ace_quasi ace_end">"</span>
  <span class="ace_paren ace_rparen">}</span>
</div>

Field usage -> ace_variable

MongoDB field highlighting

Why? Nothing worse than off by one typos... So now really easy to catch because "field" and "$field" will be styled differently.

Given:

type: "$type"
<div class="ace_line" style="height:15px">
  <span class="ace_identifier">type</span>
  <span class="ace_punctuation ace_operator">:</span> 
  <span class="ace_string ace_quasi ace_start">"</span>
  <span class="ace_variable ace_parameter">$type</span>
  <span class="ace_punctuation ace_operator">"</span>
</div>

Discovery

Thinking

/**
 * Gathering stats when items are in an array using 
 * $project accumulators.
 */

 /**
  * 1. Default JS highlighter 
  */
db.icecream_data.aggregate([
  {
    _id: 0,
    average_cpi: {
      $avg: "$trends.icecream_cpi"
    },
    max_cpi: {
      $max: "$trends.icecream_cpi"
    },
    min_cpi: {
      $min: "$trends.icecream_cpi"
    },
    cpi_deviation: {
      $stdDevPop: "$trends.icecream_cpi"
    }
  }
]);

/**
 * 2. What if `

	
		
		
		
		
		
		
		
	npm:mongodb-ace-mode | Skypack
	
		
		
		
		 operators were JS functions
 *    like in various "aggy" helper experiments?
 */
db.icecream_data.aggregate([{
  _id: include(false),
  average_cpi: avg('trends.icecream_cpi'),
  max_cpi: max('trends.icecream_cpi'),
  min_cpi: min('trends.icecream_cpi'),
  cpi_deviation: stdDevPop('trends.icecream_cpi')
}]);

/**
 * 3. What if `

	
		
		
		
		
		
		
		
	npm:mongodb-ace-mode | Skypack
	
		
		
		
		 operators same as 2 but with 
 *  "magic" template strings?
 */
db.icecream_data.aggregate([{
  _id: include(false),
  average_cpi: avg(`${trends.icecream_cpi}`),
  max_cpi: max(`${trends.icecream_cpi}`),
  min_cpi: min(`${trends.icecream_cpi}`),
  cpi_deviation: stdDevPop(`${trends.icecream_cpi}`)
}]);

There are 3 different ways I was thinking about this to get as close to what a developer would expect. (Top left editor panel in screenshot).

Case #3 of js template strings: We can discriminate between "|' and $field in aggregation styling, just like `\, ${|}, and field for a template string. The power here is:

  • field links back visually to the property on the left
  • Avoid typos of 'field' instead of '$field' (especially when creating a view!) by distinguishing those two.

Data

The Best Visual Studio Code Dark and Light Themes (Updated Feb 2019)

OneDark Pro Most installed by a giant margin

Pertsonal preference: Monokai Used for more than a decade as Editor of choice has changed (TextMate :arrow_right: SublimeText :arrow_right: Atom :arrow_right: VSCode)

Links

Basic

Given:

average_cpi: {$avg: "$trends.icecream_cpi" }

Want to highlight:

  • $trends.icecream_cpi
  • $avg
  • " around $trends.icecream_cpi separated

See

HTML we want looks something like:

<div class="ace_line" style="height: 16px; top: 32px;">  
  <span class="ace_identifier">average_cpi</span>
  <span class="ace_punctuation ace_operator">:</span> 
  <span class="ace_paren ace_lparen">{</span>
  <span class="ace_identifier ace_support ace_function">$avg</span>
  <span class="ace_punctuation ace_operator">:</span>
  <span class="ace_string ace_quasi ace_start">"</span>
  <span class="ace_variable">$trends.icecream_cpi</span>
  <span class="ace_string ace_quasi ace_end">"</span>
  <span class="ace_paren ace_rparen">}</span>
</div>

$avg Agg Operator:

  • ace_support.ace_function
  • ace_keyword.ace_operator
  • ace_function

$trends.icecream_cpi Field:

  • ace_variable
  • ace_identifier -> nice as it links back to semantics of average_cpi

Base on interpolated strings. JSX mode kind of implements this:

https://github.com/ajaxorg/ace/blob/master/lib/ace/mode/javascript_highlight_rules.js#L375-L391

{
  token : "string.quasi.start",
  regex : /`/,
  push  : [{
      token : "constant.language.escape",
      regex : escapedRe
  }, {
      token : "paren.quasi.start",
      regex : /\${/,
      push  : "start"
  }, {
      token : "string.quasi.end",
      regex : /`/,
      next  : "pop"
  }, {
      defaultToken: "string.quasi"
  }]
}

average_cpi

  • ace_identifier
  • ace_variable.ace_parameter?

Advanced

$lookup:

  • special props at top level: from, let, pipeline
...
stageOperator: '$lookup',
stage: `{
  from: "air_airlines",
  let: { maybe_name: "$airlines" },
  pipeline: [
    {
      $match: {
...

$and $or conditionals:

  • ace_keyword.ace_operator
  • ace_keyword.ace_control -> flow control keywords

https://codepen.io/imlucas/pen/eXJOrm

<div class="ace-mongodb">
  <div class="ace_layer ace_text-layer" style="padding: 0px 4px;">
    <div class="ace_line" style="height:15px">
      <span class="ace_paren ace_lparen">{</span>
    </div>
    <div class="ace_line" style="height:15px">&nbsp;&nbsp;<span class="ace_identifier">_id</span><span class="ace_punctuation ace_operator">:</span><span class="ace_constant ace_numeric"> 0</span><span class="ace_punctuation ace_operator">,</span></div>
    <div class="ace_line" style="height:15px">&nbsp;&nbsp;<span class="ace_identifier">average_cpi</span><span class="ace_punctuation ace_operator">:</span> <span class="ace_paren ace_lparen">{</span><span class="ace_support ace_function">$avg</span><span class="ace_punctuation ace_operator">:</span><span class="ace_string ace_quasi ace_start">"</span><span class="ace_variable ace_language">$trends.icecream_cpi</span><span class="ace_string ace_quasi ace_end">"</span><span class="ace_paren ace_rparen">}</span><span class="ace_punctuation ace_operator">,</span></div>
    <div class="ace_line" style="height:15px">&nbsp;&nbsp;<span class="ace_identifier">max_cpi</span><span class="ace_punctuation ace_operator">:</span><span class="ace_paren ace_lparen">{</span><span class="ace_support ace_function">$max</span><span class="ace_punctuation ace_operator">:</span><span class="ace_string ace_quasi ace_start">"</span><span class="ace_variable ace_language">$trends.icecream_cpi</span><span class="ace_string ace_quasi ace_end">"</span><span class="ace_paren ace_rparen">}</span><span class="ace_punctuation ace_operator">,</span>
      </div>
    <div class="ace_line" style="height:15px">
      &nbsp;&nbsp;<span class="ace_identifier">min_cpi</span><span class="ace_punctuation ace_operator">:</span><span class="ace_paren ace_lparen">{</span><span class="ace_support ace_function">$min</span><span class="ace_punctuation ace_operator">:</span><span class="ace_string ace_quasi ace_start">"</span><span class="ace_variable ace_language">$trends.icecream_cpi</span><span class="ace_string ace_quasi ace_end">"</span><span class="ace_paren ace_rparen">}</span><span class="ace_punctuation ace_operator">,</span></div>
    <div class="ace_line" style="height:15px">
      &nbsp;&nbsp;<span class="ace_identifier">cpi_deviation</span><span class="ace_punctuation ace_operator">:</span><span class="ace_paren ace_lparen">{</span><span class="ace_support ace_function">$stdDevPop</span><span class="ace_punctuation ace_operator">:</span><span class="ace_string ace_quasi ace_start">"</span><span class="ace_variable ace_language">$trends.icecream_cpi</span><span class="ace_string ace_quasi ace_end">"</span><span class="ace_paren ace_rparen">}</span></div>
    <div class="ace_line" style="height:15px"><span class="ace_paren ace_rparen">}</span>
    </div>
  </div>
</div>