NodeJs editor with CodeMirror

by Julien Roche

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/codemirror.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/codemirror.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/keymap/sublime.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/theme/nord.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/comment/comment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/edit/closebrackets.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/edit/matchbrackets.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/hint/show-hint.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/hint/show-hint.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/hint/javascript-hint.js"></script>
<script src="https://unpkg.com/[email protected]/dist/jshint.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/lint/lint.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/lint/javascript-lint.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/lint/lint.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/fold/foldcode.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/fold/foldgutter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/fold/brace-fold.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.2/addon/fold/xml-fold.js"></script>
<script...

CSS

html,
body {
  border: none;
  height: 100%;
  margin: 0 0 0 0;
  padding: 0 0 0 0;
  width: 100%;
}

.readonly--code {
  opacity: 0.5;
}

.readonly--line {
    background-color: rgba(0, 0, 0, 0.5);
}

Babel + JSX

const readOnlyLines = [ 0, 3, 6 ];

// Using regexp words will help us to find the unallowed keywords
// See https://regexr.com/4jgr2
// With this, we could have the following information:
/*
const regexp = /\brequire\b/g
undefined
const text = `const a = require('something');
const b = requireText();
const c = require;
const d = require ('something else');`;

text.matchAll(regexp).next();
{ done: false, value: { groups: null, index: 10, input: '..' } }
*/

const INVALID_KEYWORDS = [
  'require',
  'module',
  'import',
  'export',
  'process',
  'global'
];

function generateErrorHintForInvalidKeywords(text, codeMirrorInstance) {
	const hints = [];

	for (const word of INVALID_KEYWORDS) {
  	const regexp = new RegExp(`\\b${word}\\b`, 'g');
    const iterator = text.matchAll(regexp);
    let next = iterator.next();
    
    while(!next.done) {
    	const index = next.value.index;
      const from = codeMirrorInstance.posFromIndex(index);
      const line = from.line;
      const information = codeMirrorInstance.lineInfo(line);
      
      if (!information.wrapClass || !information.wrapClass.includes('readonly--line')) {
        hints.push({
          message: `The keyword ${word} is not allowed`,
          severity: 'error',
          from,
          to: codeMirrorInstance.posFromIndex(index + word.length)
        });
      }
      
    	next = iterator.next();
    }
  }
  
  return hints;
}

function parseErrors(errors, output) {
  for ( var i = 0; i < errors.length; i++) {
    var error = errors[i];
    if (error) {
      if (error.line <= 0) {
        if (window.console) {
          window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error);
        }
        continue;
      }

      var start = error.character - 1, end = start + 1;
      if (error.evidence) {
        var index = error.evidence.substring(start).search(/.\b/);
        if (index > -1) {
          end += index;
        }
      }

      // Convert to format...