api-builder: add cheatsheet-package to generate cheatsheet data

Closes #348
This commit is contained in:
Peter Bacon Darwin
2015-11-06 12:56:28 +00:00
parent bc7d3241c8
commit 66a7edd8cb
12 changed files with 713 additions and 2 deletions
@@ -2,12 +2,15 @@ var path = require('canonical-path');
var Package = require('dgeni').Package;
var basePackage = require('../docs-package');
var targetPackage = require('../target-package');
var cheatsheetPackage = require('../cheatsheet-package');
var PROJECT_PATH = path.resolve(__dirname, "../../..");
var PUBLIC_PATH = path.resolve(PROJECT_PATH, 'public');
var DOCS_PATH = path.resolve(PUBLIC_PATH, 'docs');
var ANGULAR2_DOCS_PATH = path.resolve(__dirname, '../../../../angular/modules/angular2/docs');
module.exports = new Package('angular.io', [basePackage, targetPackage])
module.exports = new Package('angular.io', [basePackage, targetPackage, cheatsheetPackage])
.factory(require('./services/renderMarkdown'))
.processor(require('./processors/addJadeDataDocsProcessor'))
@@ -41,6 +44,11 @@ module.exports = new Package('angular.io', [basePackage, targetPackage])
readTypeScriptModules.hidePrivateMembers = true;
readFilesProcessor.basePath = DOCS_PATH;
readFilesProcessor.sourceFiles = [{
basePath: ANGULAR2_DOCS_PATH,
include: path.resolve(ANGULAR2_DOCS_PATH, 'cheatsheet/*.md')
}];
writeFilesProcessor.outputFolder = 'js/latest/api';
})
@@ -51,7 +59,6 @@ module.exports = new Package('angular.io', [basePackage, targetPackage])
.config(function(readFilesProcessor, generateNavigationDoc, createOverviewDump) {
// Clear out unwanted processors
readFilesProcessor.$enabled = false;
generateNavigationDoc.$enabled = false;
createOverviewDump.$enabled = false;
})
@@ -0,0 +1 @@
{$ doc.sections | json $}
@@ -0,0 +1,10 @@
var Package = require('dgeni').Package;
module.exports = new Package('cheatsheet', [require('../content-package')])
.factory(require('./services/cheatsheetItemParser'))
.processor(require('./processors/createCheatsheetDoc'))
.config(function(parseTagsProcessor, getInjectables) {
parseTagsProcessor.tagDefinitions = parseTagsProcessor.tagDefinitions.concat(getInjectables(require('./tag-defs')));
});
@@ -0,0 +1,9 @@
var Package = require('dgeni').Package;
module.exports = function mockPackage() {
return new Package('mockPackage', [require('../'), require('dgeni-packages/nunjucks')])
// provide a mock log service
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); });
};
@@ -0,0 +1,41 @@
var _ = require('lodash');
module.exports = function createCheatsheetDoc(createDocMessage, renderMarkdown) {
return {
$runAfter: ['processing-docs'],
$runBefore: ['docs-processed'],
$process: function(docs) {
var cheatsheetDoc = {
id: 'cheatsheet',
aliases: ['cheatsheet'],
docType: 'json-data',
sections: []
};
docs = docs.filter(function(doc) {
if (doc.docType === 'cheatsheet-section') {
var section = _.pick(doc, ['name', 'description', 'items', 'index']);
// Let's make sure that the descriptions are rendered as markdown
section.description = renderMarkdown(section.description);
section.items.forEach(function(item) {
item.description = renderMarkdown(item.description);
});
cheatsheetDoc.sections.push(section);
return false;
}
return true;
});
// Sort the sections by their index
cheatsheetDoc.sections.sort(function(a,b) { return a.index - b.index; });
docs.push(cheatsheetDoc);
return docs;
}
};
};
@@ -0,0 +1,85 @@
/**
* @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() {
return function(text) {
var index = 0;
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;
}
},
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;
};
}
@@ -0,0 +1,52 @@
var mockPackage = require('../mocks/mockPackage');
var Dgeni = require('dgeni');
describe('cheatsheetItemParser', function() {
var dgeni, injector, cheatsheetItemParser;
beforeEach(function() {
dgeni = new Dgeni([mockPackage()]);
injector = dgeni.configureInjector();
cheatsheetItemParser = injector.get('cheatsheetItemParser');
});
it('should extract the syntax', function() {
expect(cheatsheetItemParser('`abc`')).toEqual({
syntax: 'abc',
bold: [],
description: ''
});
});
it('should extract the bolds', function() {
expect(cheatsheetItemParser('`abc`|`bold1`|`bold2`')).toEqual({
syntax: 'abc',
bold: ['bold1', 'bold2'],
description: ''
});
});
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'
});
})
});
@@ -0,0 +1,13 @@
module.exports = function(createDocMessage) {
return {
name: 'cheatsheetIndex',
docProperty: 'index',
transforms: function(doc, tag, value) {
try {
return parseInt(value, 10);
} catch(x) {
throw new Error(createDocMessage('"@'+ tag.tagName +'" must be followed by a number', doc));
}
}
};
};
@@ -0,0 +1,14 @@
module.exports = function(createDocMessage, cheatsheetItemParser) {
return {
name: 'cheatsheetItem',
multi: true,
docProperty: 'items',
transforms: function(doc, tag, value) {
try {
return cheatsheetItemParser(value);
} catch(x) {
throw new Error(createDocMessage('"@'+ tag.tagName +'" tag has an invalid format - ' + x.message, doc));
}
}
};
};
@@ -0,0 +1,10 @@
module.exports = function() {
return {
name: 'cheatsheetSection',
docProperty: 'docType',
transforms: function(doc, tag, value) {
doc.name = value ? value.trim() : '';
return 'cheatsheet-section';
}
};
};
@@ -0,0 +1,5 @@
module.exports = [
require('./cheatsheet-section'),
require('./cheatsheet-index'),
require('./cheatsheet-item')
];