125 lines
4.0 KiB
JavaScript
125 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;
|
||
|
}
|