diff --git a/tools/api-builder/cheatsheet-package/index.js b/tools/api-builder/cheatsheet-package/index.js index ad016ae602..5b30c5e1f7 100644 --- a/tools/api-builder/cheatsheet-package/index.js +++ b/tools/api-builder/cheatsheet-package/index.js @@ -1,6 +1,6 @@ var Package = require('dgeni').Package; -module.exports = new Package('cheatsheet', [require('../content-package')]) +module.exports = new Package('cheatsheet', [require('../content-package'), require('../target-package')]) .factory(require('./services/cheatsheetItemParser')) .processor(require('./processors/createCheatsheetDoc')) diff --git a/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.js b/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.js index 76393a8b97..35acda31d3 100644 --- a/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.js +++ b/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.js @@ -29,57 +29,92 @@ * } * ``` */ -module.exports = function cheatsheetItemParser() { - +module.exports = function cheatsheetItemParser(targetEnvironments) { return function(text) { - var index = 0; + var fields = getFields(text, ['syntax', 'description']); + var item = { syntax: '', bold: [], description: '' }; - var STATES = { - inSyntax: function() { - if (text.charAt(index) !== '`') throw new Error('item syntax must start with a backtick'); - index += 1; - var syntaxStart = index; - while(index < text.length && text.charAt(index) !== '`') index++; - if (index === text.length) throw new Error('item syntax must end with a backtick'); - item.syntax = text.substring(syntaxStart, index); - state = STATES.pipe; - index++; - }, - pipe: function() { - if (text.charAt(index) === '|') { - index++; - while(index < text.length && /\s/.test(text.charAt(index))) index++; - state = STATES.bold; - } else { - state = STATES.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; } - }, - bold: function() { - if (text.charAt(index) !== '`') throw new Error('bold matcher must start with a backtick'); - index += 1; - var boldStart = index; - while(index < text.length && text.charAt(index) !== '`') index++; - if (index === text.length) throw new Error('bold matcher must end with a backtick'); - item.bold.push(text.substring(boldStart, index)); - state = STATES.pipe; - index++; - }, - description: function() { - item.description = text.substring(index); - state = null; } - }; - - var state = STATES.inSyntax; - while(state) { - state(); - } + }); 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; } \ No newline at end of file diff --git a/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.spec.js b/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.spec.js index 9b3ec227fe..67aa2b04ca 100644 --- a/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.spec.js +++ b/tools/api-builder/cheatsheet-package/services/cheatsheetItemParser.spec.js @@ -8,45 +8,86 @@ describe('cheatsheetItemParser', function() { dgeni = new Dgeni([mockPackage()]); injector = dgeni.configureInjector(); cheatsheetItemParser = injector.get('cheatsheetItemParser'); + var targetEnvironments = injector.get('targetEnvironments'); + targetEnvironments.addAllowed('js'); + targetEnvironments.addAllowed('ts', true); }); - it('should extract the syntax', function() { - expect(cheatsheetItemParser('`abc`')).toEqual({ - syntax: 'abc', - bold: [], - description: '' + describe('no language targets', function() { + it('should extract the syntax', function() { + expect(cheatsheetItemParser('syntax:\n`abc`')).toEqual({ + syntax: 'abc', + bold: [], + description: '' + }); + }); + + it('should extract the bolds', function() { + expect(cheatsheetItemParser('syntax:\n`abc`|`bold1`|`bold2`')).toEqual({ + syntax: 'abc', + bold: ['bold1', 'bold2'], + description: '' + }); + }); + + it('should extract the description', function() { + expect(cheatsheetItemParser('syntax:\n`abc`|`bold1`|`bold2`\ndescription:\nsome description')).toEqual({ + syntax: 'abc', + bold: ['bold1', 'bold2'], + description: 'some description' + }); + }); + + it('should allow bold to be optional', function() { + expect(cheatsheetItemParser('syntax:\n`abc`\ndescription:\nsome description')).toEqual({ + syntax: 'abc', + bold: [], + description: 'some description' + }); + }); + + it('should allow whitespace between the parts', function() { + expect(cheatsheetItemParser('syntax:\n`abc`| `bold1`| `bold2`\ndescription:\n\nsome description')).toEqual({ + syntax: 'abc', + bold: ['bold1', 'bold2'], + description: 'some description' + }); }); }); - it('should extract the bolds', function() { - expect(cheatsheetItemParser('`abc`|`bold1`|`bold2`')).toEqual({ - syntax: 'abc', - bold: ['bold1', 'bold2'], - description: '' + describe('with language targets', function() { + it('should extract the active language', function() { + expect(cheatsheetItemParser('syntax(ts):\n`abc`|`bold1`|`bold2`\ndescription(ts):\nsome description')).toEqual({ + syntax: 'abc', + bold: ['bold1', 'bold2'], + description: 'some description' + }); + }); + + it('should ignore the non-active language', function() { + expect(cheatsheetItemParser('syntax(js):\n`abc`|`bold1`|`bold2`\ndescription(js):\nsome description')).toEqual({ + syntax: '', + bold: [], + description: '' + }); + }); + + it('should select the active language and ignore non-active language', function() { + expect(cheatsheetItemParser( + 'syntax(js):\n`JS`|`boldJS``\n' + + 'syntax(ts):\n`TS`|`boldTS`\n' + + 'description(js):\nJS description\n' + + 'description(ts):\nTS description')).toEqual({ + syntax: 'TS', + bold: ['boldTS'], + description: 'TS description' + }); + }); + + it('should error if a language target is used that is not allowed', function() { + expect(function() { + cheatsheetItemParser('syntax(dart):\n`abc`|`bold1`|`bold2`\ndescription(ts):\nsome description'); + }).toThrowError('Error accessing target "dart". It is not in the list of allowed targets: js,ts'); }); }); - - it('should extract the description', function() { - expect(cheatsheetItemParser('`abc`|`bold1`|`bold2`some description')).toEqual({ - syntax: 'abc', - bold: ['bold1', 'bold2'], - description: 'some description' - }); - }); - - it('should allow bold to be optional', function() { - expect(cheatsheetItemParser('`abc`some description')).toEqual({ - syntax: 'abc', - bold: [], - description: 'some description' - }); - }); - - it('should allow whitespace between the parts', function() { - expect(cheatsheetItemParser('`abc`| `bold1`| `bold2`\n\nsome description')).toEqual({ - syntax: 'abc', - bold: ['bold1', 'bold2'], - description: '\n\nsome description' - }); - }) }); \ No newline at end of file