refact(api-builder): move into tools folder

This commit is contained in:
Peter Bacon Darwin
2015-11-04 11:20:07 +00:00
parent ce298009e6
commit 83fbe75980
88 changed files with 63 additions and 2 deletions
@@ -0,0 +1,31 @@
var _ = require('lodash');
/**
* @dgProcessor checkUnbalancedBackTicks
* @description
* Searches the rendered content for an odd number of (```) backticks,
* which would indicate an unbalanced pair and potentially a typo in the
* source content.
*/
module.exports = function checkUnbalancedBackTicks(log, createDocMessage) {
var BACKTICK_REGEX = /^ *```/gm;
return {
// $runAfter: ['checkAnchorLinksProcessor'],
$runAfter: ['inlineTagProcessor'],
$runBefore: ['writeFilesProcessor'],
$process: function(docs) {
_.forEach(docs, function(doc) {
if ( doc.renderedContent ) {
var matches = doc.renderedContent.match(BACKTICK_REGEX);
if (matches && matches.length % 2 !== 0) {
doc.unbalancedBackTicks = true;
log.warn(createDocMessage('checkUnbalancedBackTicks processor: unbalanced backticks found in rendered content', doc));
log.warn(doc.renderedContent);
}
}
});
}
};
};
@@ -0,0 +1,32 @@
var mockPackage = require('../mocks/mockPackage');
var Dgeni = require('dgeni');
var path = require('canonical-path');
var _ = require('lodash');
describe('checkUnbalancedBackTicks', function() {
var dgeni, injector, processor, log;
beforeEach(function() {
dgeni = new Dgeni([mockPackage()]);
injector = dgeni.configureInjector();
processor = injector.get('checkUnbalancedBackTicks');
log = injector.get('log');
});
it('should warn if there are an odd number of back ticks in the rendered content', function() {
var docs = [
{ renderedContent:
'```\n' +
'code block\n' +
'```\n' +
'```\n' +
'code block with missing closing back ticks\n'
}
];
processor.$process(docs);
expect(log.warn).toHaveBeenCalledWith('checkUnbalancedBackTicks processor: unbalanced backticks found in rendered content - doc');
expect(docs[0].unbalancedBackTicks).toBe(true);
});
});
@@ -0,0 +1,61 @@
var _ = require('lodash');
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
// captures below
// 1st is entire ``` including leading whitespace
// 2nd is the leading whitespace on the line before the ``` fence
// 3rd is the name of the language (if any) specified after the ```
// 4th is the contents of the ``` block up until but not including the first non whitespace char after the end ```
// 5th is the padding of the first nonblank line following the backtick block
// 6th is the first char on the next line.
var BACKTICK_CAPTURE = /(( *)```(.*$)([^]*?)```\s*)^(\s*)(\S)/m;
var CODE_EXAMPLE = 'code-example(format="linenums" language="js").';
module.exports = function convertBackticksToCodeBlocks() {
return {
$runAfter: ['checkUnbalancedBackTicks'],
$runBefore: ['writeFilesProcessor'],
$process: function(docs) {
_.forEach(docs, function(doc) {
if (!doc.unbalancedBackTicks) {
// Idea here is to translate backtick ``` regions into code-example blocks.
var captures = BACKTICK_CAPTURE.exec(doc.renderedContent);
while (captures) {
var entireBlock = captures[1];
var prePad = captures[2];
var language = captures[3];
var blockContents = captures[4];
var postPad = captures[5];
var nextBlockStartChar = captures[6];
var codeExamplePrefix = language.length ? CODE_EXAMPLE.replace('js', language) : CODE_EXAMPLE;
// modulo op in next line insures that pad is always a multiple of 2 ( jade whitespace).
var newPrePad = prePad.substr(2 + (prePad.length % 2)); // exdent
var replaceVal = '\n' + newPrePad + codeExamplePrefix + escapeHtml(blockContents) + '\n';
// if nextBlock does NOT start with a '.' then we want to restart a markdown block.
// and that block needs to be exdented from the preceding code-example content.
if (nextBlockStartChar != '.') {
if (postPad.length >= 2) {
// modulo op in next line insures that pad is always a multiple of 2 ( jade whitespace).
postPad = postPad.substr(2 + (postPad.length % 2)); // exdent
}
replaceVal = replaceVal + postPad + ':markdown\n';
}
doc.renderedContent = doc.renderedContent.replace(entireBlock, replaceVal);
captures = BACKTICK_CAPTURE.exec(doc.renderedContent);
}
}
});
}
};
};
@@ -0,0 +1,59 @@
var mockPackage = require('../mocks/mockPackage');
var Dgeni = require('dgeni');
var path = require('canonical-path');
var _ = require('lodash');
describe('convertBackticksToCodeBlocks', function() {
var dgeni, injector, processor;
beforeEach(function() {
dgeni = new Dgeni([mockPackage()]);
injector = dgeni.configureInjector();
processor = injector.get('convertBackticksToCodeBlocks');
});
it('should convert backtick code blocks to code-example blocks', function() {
var docs = [{
renderedContent:
'preamble\n' +
'```ts\n' +
'export class TypeScriptClass {\n' +
'}\n' +
'```\n' +
'postamble\n'
}];
processor.$process(docs);
expect(docs[0].renderedContent).toEqual(
'preamble\n' +
'\n' +
'code-example(format="linenums" language="ts").\n' +
'export class TypeScriptClass {\n' +
'}\n' +
'\n' +
':markdown\n' +
'postamble\n'
);
});
it('should ignore docs that have been marked as having unbalanced backticks', function() {
var docs = [{
renderedContent:
'preamble\n' +
'```ts\n' +
'export class TypeScriptClass {\n' +
'}\n' +
'postamble\n'
}];
processor.$process(docs);
expect(docs[0].renderedContent).toEqual(
'preamble\n' +
'```ts\n' +
'export class TypeScriptClass {\n' +
'}\n' +
'postamble\n'
);
})
});
@@ -0,0 +1,10 @@
module.exports = function convertPrivateClassesToInterfacesProcessor(convertPrivateClassesToInterfaces) {
return {
$runAfter: ['processing-docs'],
$runBefore: ['docs-processed'],
$process: function(docs) {
convertPrivateClassesToInterfaces(docs, false);
return docs;
}
};
};
@@ -0,0 +1,24 @@
var _ = require('lodash');
module.exports = function createOverviewDump() {
return {
$runAfter: ['processing-docs'],
$runBefore: ['docs-processed'],
$process: function(docs) {
var overviewDoc = {
id: 'overview-dump',
aliases: ['overview-dump'],
path: 'overview-dump',
outputPath: 'overview-dump.html',
modules: []
};
_.forEach(docs, function(doc) {
if ( doc.docType === 'module' ) {
overviewDoc.modules.push(doc);
}
});
docs.push(overviewDoc);
}
};
};
@@ -0,0 +1,32 @@
var _ = require('lodash');
var vm = require('vm');
module.exports = function extractDirectiveClassesProcessor() {
return {
$runAfter: ['processing-docs'],
$runBefore: ['docs-processed'],
decoratorTypes: ['Directive', 'Component', 'View'],
$process: function(docs) {
var decoratorTypes = this.decoratorTypes;
_.forEach(docs, function(doc) {
_.forEach(doc.decorators, function(decorator) {
if (decoratorTypes.indexOf(decorator.name) !== -1) {
// We use this sneaky vm trick to extract the object literal
// argument from the decorator's constructor call
var args = decorator.arguments ?
vm.runInNewContext('dummy = ' + decorator.arguments[0]) : {};
doc[decorator.name.toLowerCase() + 'Options'] = args;
doc.docType = 'directive';
}
});
});
return docs;
}
};
};
@@ -0,0 +1,45 @@
var mockPackage = require('../mocks/mockPackage');
var Dgeni = require('dgeni');
describe('extractDirectiveClasses processor', function() {
var dgeni, injector, processor;
beforeEach(function() {
dgeni = new Dgeni([mockPackage()]);
injector = dgeni.configureInjector();
processor = injector.get('extractDirectiveClassesProcessor');
});
it('should extract specified decorator arguments', function() {
var doc = {
id: 'angular2/angular2.ngFor',
name: 'ngFor',
docType: 'class',
decorators: [
{
name: 'Directive',
arguments: ['{selector: \'[ng-for][ng-for-of]\', properties: [\'ngForOf\']}']
}
]
};
var docs = processor.$process([doc]);
expect(doc).toEqual(jasmine.objectContaining({
id: 'angular2/angular2.ngFor',
name: 'ngFor',
docType: 'directive',
decorators: [
{
name: 'Directive',
arguments: ['{selector: \'[ng-for][ng-for-of]\', properties: [\'ngForOf\']}']
}
]
}));
expect(doc.directiveOptions).toEqual({
selector: '[ng-for][ng-for-of]',
properties: ['ngForOf']
});
});
});
@@ -0,0 +1,24 @@
var _ = require('lodash');
module.exports = function extractTitleFromGuides() {
return {
$runAfter: ['processing-docs'],
$runBefore: ['docs-processed'],
$process: function(docs) {
_(docs).forEach(function(doc) {
if (doc.docType === 'guide') {
doc.name = doc.name || getNameFromHeading(doc.description);
}
});
}
};
};
function getNameFromHeading(text) {
var match = /^\s*#\s*(.*)/.exec(text);
if (match) {
return match[1];
}
}
@@ -0,0 +1,68 @@
var _ = require('lodash');
module.exports = function generateNavigationDoc() {
return {
$runAfter: ['docs-processed'],
$runBefore: ['rendering-docs'],
$process: function(docs) {
var modulesDoc = {
value: { sections: [] },
moduleName: 'navigation-modules',
serviceName: 'MODULES',
template: 'data-module.template.js',
outputPath: 'js/navigation-modules.js'
};
_.forEach(docs, function(doc) {
if ( doc.docType === 'module' ) {
var moduleNavItem = {
path: doc.path,
partial: doc.outputPath,
name: doc.id,
type: 'module',
pages: []
};
modulesDoc.value.sections.push(moduleNavItem);
_.forEach(doc.exports, function(exportDoc) {
if (!exportDoc.internal) {
var exportNavItem = {
path: exportDoc.path,
partial: exportDoc.outputPath,
name: exportDoc.name,
type: exportDoc.docType
};
moduleNavItem.pages.push(exportNavItem);
}
});
}
});
docs.push(modulesDoc);
var guidesDoc = {
value: { pages: [] },
moduleName: 'navigation-guides',
serviceName: 'GUIDES',
template: 'data-module.template.js',
outputPath: 'js/navigation-guides.js'
};
_.forEach(docs, function(doc) {
if ( doc.docType === 'guide' ) {
var guideDoc = {
path: doc.path,
partial: doc.outputPath,
name: doc.name,
type: 'guide'
};
guidesDoc.value.pages.push(guideDoc);
}
});
docs.push(guidesDoc);
}
};
};