/** * @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 * * ``` * `
* * * *
`|`[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: '
\n'+ * ' \n'+ * ' \n'+ * ' \n'+ * '
', * 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; }