github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/app/public/codemirror/mode/puppet/puppet.js (about)

     1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
     2  // Distributed under an MIT license: http://codemirror.net/LICENSE
     3  
     4  (function(mod) {
     5    if (typeof exports == "object" && typeof module == "object") // CommonJS
     6      mod(require("../../lib/codemirror"));
     7    else if (typeof define == "function" && define.amd) // AMD
     8      define(["../../lib/codemirror"], mod);
     9    else // Plain browser env
    10      mod(CodeMirror);
    11  })(function(CodeMirror) {
    12  "use strict";
    13  
    14  CodeMirror.defineMode("puppet", function () {
    15    // Stores the words from the define method
    16    var words = {};
    17    // Taken, mostly, from the Puppet official variable standards regex
    18    var variable_regex = /({)?([a-z][a-z0-9_]*)?((::[a-z][a-z0-9_]*)*::)?[a-zA-Z0-9_]+(})?/;
    19  
    20    // Takes a string of words separated by spaces and adds them as
    21    // keys with the value of the first argument 'style'
    22    function define(style, string) {
    23      var split = string.split(' ');
    24      for (var i = 0; i < split.length; i++) {
    25        words[split[i]] = style;
    26      }
    27    }
    28  
    29    // Takes commonly known puppet types/words and classifies them to a style
    30    define('keyword', 'class define site node include import inherits');
    31    define('keyword', 'case if else in and elsif default or');
    32    define('atom', 'false true running present absent file directory undef');
    33    define('builtin', 'action augeas burst chain computer cron destination dport exec ' +
    34      'file filebucket group host icmp iniface interface jump k5login limit log_level ' +
    35      'log_prefix macauthorization mailalias maillist mcx mount nagios_command ' +
    36      'nagios_contact nagios_contactgroup nagios_host nagios_hostdependency ' +
    37      'nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service ' +
    38      'nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo ' +
    39      'nagios_servicegroup nagios_timeperiod name notify outiface package proto reject ' +
    40      'resources router schedule scheduled_task selboolean selmodule service source ' +
    41      'sport ssh_authorized_key sshkey stage state table tidy todest toports tosource ' +
    42      'user vlan yumrepo zfs zone zpool');
    43  
    44    // After finding a start of a string ('|") this function attempts to find the end;
    45    // If a variable is encountered along the way, we display it differently when it
    46    // is encapsulated in a double-quoted string.
    47    function tokenString(stream, state) {
    48      var current, prev, found_var = false;
    49      while (!stream.eol() && (current = stream.next()) != state.pending) {
    50        if (current === '$' && prev != '\\' && state.pending == '"') {
    51          found_var = true;
    52          break;
    53        }
    54        prev = current;
    55      }
    56      if (found_var) {
    57        stream.backUp(1);
    58      }
    59      if (current == state.pending) {
    60        state.continueString = false;
    61      } else {
    62        state.continueString = true;
    63      }
    64      return "string";
    65    }
    66  
    67    // Main function
    68    function tokenize(stream, state) {
    69      // Matches one whole word
    70      var word = stream.match(/[\w]+/, false);
    71      // Matches attributes (i.e. ensure => present ; 'ensure' would be matched)
    72      var attribute = stream.match(/(\s+)?\w+\s+=>.*/, false);
    73      // Matches non-builtin resource declarations
    74      // (i.e. "apache::vhost {" or "mycustomclasss {" would be matched)
    75      var resource = stream.match(/(\s+)?[\w:_]+(\s+)?{/, false);
    76      // Matches virtual and exported resources (i.e. @@user { ; and the like)
    77      var special_resource = stream.match(/(\s+)?[@]{1,2}[\w:_]+(\s+)?{/, false);
    78  
    79      // Finally advance the stream
    80      var ch = stream.next();
    81  
    82      // Have we found a variable?
    83      if (ch === '$') {
    84        if (stream.match(variable_regex)) {
    85          // If so, and its in a string, assign it a different color
    86          return state.continueString ? 'variable-2' : 'variable';
    87        }
    88        // Otherwise return an invalid variable
    89        return "error";
    90      }
    91      // Should we still be looking for the end of a string?
    92      if (state.continueString) {
    93        // If so, go through the loop again
    94        stream.backUp(1);
    95        return tokenString(stream, state);
    96      }
    97      // Are we in a definition (class, node, define)?
    98      if (state.inDefinition) {
    99        // If so, return def (i.e. for 'class myclass {' ; 'myclass' would be matched)
   100        if (stream.match(/(\s+)?[\w:_]+(\s+)?/)) {
   101          return 'def';
   102        }
   103        // Match the rest it the next time around
   104        stream.match(/\s+{/);
   105        state.inDefinition = false;
   106      }
   107      // Are we in an 'include' statement?
   108      if (state.inInclude) {
   109        // Match and return the included class
   110        stream.match(/(\s+)?\S+(\s+)?/);
   111        state.inInclude = false;
   112        return 'def';
   113      }
   114      // Do we just have a function on our hands?
   115      // In 'ensure_resource("myclass")', 'ensure_resource' is matched
   116      if (stream.match(/(\s+)?\w+\(/)) {
   117        stream.backUp(1);
   118        return 'def';
   119      }
   120      // Have we matched the prior attribute regex?
   121      if (attribute) {
   122        stream.match(/(\s+)?\w+/);
   123        return 'tag';
   124      }
   125      // Do we have Puppet specific words?
   126      if (word && words.hasOwnProperty(word)) {
   127        // Negates the initial next()
   128        stream.backUp(1);
   129        // Acutally move the stream
   130        stream.match(/[\w]+/);
   131        // We want to process these words differently
   132        // do to the importance they have in Puppet
   133        if (stream.match(/\s+\S+\s+{/, false)) {
   134          state.inDefinition = true;
   135        }
   136        if (word == 'include') {
   137          state.inInclude = true;
   138        }
   139        // Returns their value as state in the prior define methods
   140        return words[word];
   141      }
   142      // Is there a match on a reference?
   143      if (/(^|\s+)[A-Z][\w:_]+/.test(word)) {
   144        // Negate the next()
   145        stream.backUp(1);
   146        // Match the full reference
   147        stream.match(/(^|\s+)[A-Z][\w:_]+/);
   148        return 'def';
   149      }
   150      // Have we matched the prior resource regex?
   151      if (resource) {
   152        stream.match(/(\s+)?[\w:_]+/);
   153        return 'def';
   154      }
   155      // Have we matched the prior special_resource regex?
   156      if (special_resource) {
   157        stream.match(/(\s+)?[@]{1,2}/);
   158        return 'special';
   159      }
   160      // Match all the comments. All of them.
   161      if (ch == "#") {
   162        stream.skipToEnd();
   163        return "comment";
   164      }
   165      // Have we found a string?
   166      if (ch == "'" || ch == '"') {
   167        // Store the type (single or double)
   168        state.pending = ch;
   169        // Perform the looping function to find the end
   170        return tokenString(stream, state);
   171      }
   172      // Match all the brackets
   173      if (ch == '{' || ch == '}') {
   174        return 'bracket';
   175      }
   176      // Match characters that we are going to assume
   177      // are trying to be regex
   178      if (ch == '/') {
   179        stream.match(/.*?\//);
   180        return 'variable-3';
   181      }
   182      // Match all the numbers
   183      if (ch.match(/[0-9]/)) {
   184        stream.eatWhile(/[0-9]+/);
   185        return 'number';
   186      }
   187      // Match the '=' and '=>' operators
   188      if (ch == '=') {
   189        if (stream.peek() == '>') {
   190            stream.next();
   191        }
   192        return "operator";
   193      }
   194      // Keep advancing through all the rest
   195      stream.eatWhile(/[\w-]/);
   196      // Return a blank line for everything else
   197      return null;
   198    }
   199    // Start it all
   200    return {
   201      startState: function () {
   202        var state = {};
   203        state.inDefinition = false;
   204        state.inInclude = false;
   205        state.continueString = false;
   206        state.pending = false;
   207        return state;
   208      },
   209      token: function (stream, state) {
   210        // Strip the spaces, but regex will account for them eitherway
   211        if (stream.eatSpace()) return null;
   212        // Go through the main process
   213        return tokenize(stream, state);
   214      }
   215    };
   216  });
   217  
   218  CodeMirror.defineMIME("text/x-puppet", "puppet");
   219  
   220  });