120 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @dgService
 | |
|  * @description
 | |
|  * Parse the text from a cheatsheetItem tag into a cheatsheet item object
 | |
|  * The text must contain a syntax block followed by zero or more bold matchers and finally a description
 | |
|  * The syntax block and bold matchers must be wrapped in backticks and be separated by pipes.
 | |
|  * For example
 | |
|  *
 | |
|  * ```
 | |
|  * `<div [ng-switch]="conditionExpression">
 | |
|  *   <template [ng-switch-when]="case1Exp">...</template>
 | |
|  *   <template ng-switch-when="case2LiteralString">...</template>
 | |
|  *   <template ng-switch-default>...</template>
 | |
|  * </div>`|`[ng-switch]`|`[ng-switch-when]`|`ng-switch-when`|`ng-switch-default`
 | |
|  * Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of conditionExpression.
 | |
|  * ```
 | |
|  *
 | |
|  * will be parsed into
 | |
|  *
 | |
|  * ```
 | |
|  * {
 | |
|  *   syntax: '<div [ng-switch]="conditionExpression">\n'+
 | |
|  *           '  <template [ng-switch-when]="case1Exp">...</template>\n'+
 | |
|  *           '  <template ng-switch-when="case2LiteralString">...</template>\n'+
 | |
|  *           '  <template ng-switch-default>...</template>\n'+
 | |
|  *           '</div>',
 | |
|  *   bold: ['[ng-switch]', '[ng-switch-when]', 'ng-switch-when', 'ng-switch-default'],
 | |
|  *   description: 'Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of conditionExpression.'
 | |
|  * }
 | |
|  * ```
 | |
|  */
 | |
| module.exports = function cheatsheetItemParser(targetEnvironments) {
 | |
|   return function(text) {
 | |
|     var fields = getFields(text, ['syntax', 'description']);
 | |
| 
 | |
|     var item = {
 | |
|       syntax: '',
 | |
|       bold: [],
 | |
|       description: ''
 | |
|     };
 | |
| 
 | |
|     fields.forEach(function(field) {
 | |
|       if (!field.languages || targetEnvironments.someActive(field.languages)) {
 | |
|         switch(field.name) {
 | |
|           case 'syntax':
 | |
|             parseSyntax(field.value.trim());
 | |
|             break;
 | |
|           case 'description':
 | |
|             item.description = field.value.trim();
 | |
|             break;
 | |
|         }
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     return item;
 | |
| 
 | |
|     function parseSyntax(text) {
 | |
|       var index = 0;
 | |
| 
 | |
|       if (text.charAt(index) !== '`') throw new Error('item syntax must start with a backtick');
 | |
| 
 | |
|       var start = index + 1;
 | |
|       index = text.indexOf('`', start);
 | |
|       if (index === -1) throw new Error('item syntax must end with a backtick');
 | |
|       item.syntax = text.substring(start, index);
 | |
|       start = index + 1;
 | |
| 
 | |
|       // skip to next pipe
 | |
|       while(index < text.length && text.charAt(index) !== '|') index += 1;
 | |
| 
 | |
|       while(text.charAt(start) === '|') {
 | |
| 
 | |
|         start += 1;
 | |
| 
 | |
|         // skip whitespace
 | |
|         while(start < text.length && /\s/.test(text.charAt(start))) start++;
 | |
| 
 | |
|         if (text.charAt(start) !== '`') throw new Error('bold matcher must start with a backtick');
 | |
| 
 | |
|         start += 1;
 | |
|         index = text.indexOf('`', start);
 | |
|         if (index === -1) throw new Error('bold matcher must end with a backtick');
 | |
|         item.bold.push(text.substring(start, index));
 | |
|         start = index + 1;
 | |
| 
 | |
|       }
 | |
| 
 | |
|       if (start !== text.length) {
 | |
|         throw new Error('syntax field must only contain a syntax code block and zero or more bold ' +
 | |
|                         'matcher code blocks, delimited by pipes.\n' +
 | |
|                         'Instead it was "' + text + '"');
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| }
 | |
| 
 | |
| 
 | |
| function getFields(text, fieldNames) {
 | |
|   var FIELD_START = /^([^:(]+)\(?([^)]+)?\)?:$/;
 | |
|   var lines = text.split('\n');
 | |
|   var fields = [];
 | |
|   var field, line;
 | |
|   while(lines.length) {
 | |
|     line = lines.shift();
 | |
|     var match = FIELD_START.exec(line);
 | |
|     if (match && fieldNames.indexOf(match[1]) !== -1) {
 | |
|       // start new field
 | |
|       if (field) {fields.push(field);}
 | |
|       field = { name: match[1], languages: (match[2] && match[2].split(' ')), value: ''};
 | |
|     } else {
 | |
|       if (!field) throw new Error('item must start with one of the following field specifiers:\n' +
 | |
|                             fieldNames.map(function(field) { return field + ':'; }).join('\n') + '\n' +
 | |
|                             'but instead it contained: "' + text + '"');
 | |
|       field.value += line + '\n';
 | |
|     }
 | |
|   }
 | |
|   if (field) {fields.push(field);}
 | |
| 
 | |
|   return fields;
 | |
| } |