api-builder: add cheatsheet-package to generate cheatsheet data
Closes #348
This commit is contained in:
parent
bc7d3241c8
commit
66a7edd8cb
|
@ -0,0 +1,464 @@
|
|||
[
|
||||
{
|
||||
"name": "Bootstrapping",
|
||||
"description": "<p><code>import {bootstrap} from 'angular2/angular2';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "<input [value]=\"firstName\">",
|
||||
"bold": [
|
||||
"[value]"
|
||||
],
|
||||
"description": "<p>Binds property <code>value</code> to the result of expression <code>firstName</code>.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<div [attr.role]=\"myAriaRole\">",
|
||||
"bold": [
|
||||
"[attr.role]"
|
||||
],
|
||||
"description": "<p>Binds attribute <code>role</code> to the result of expression <code>myAriaRole</code>.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<div [class.extra-sparkle]=\"isDelightful\">",
|
||||
"bold": [
|
||||
"[class.extra-sparkle]"
|
||||
],
|
||||
"description": "<p>Binds the presence of the css class <code>extra-sparkle</code> on the element to the truthiness of the expression <code>isDelightful</code>.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<div [style.width.px]=\"mySize\">",
|
||||
"bold": [
|
||||
"[style.width.px]"
|
||||
],
|
||||
"description": "<p>Binds style property <code>width</code> to the result of expression <code>mySize</code> in pixels. Units are optional.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<button (click)=\"readRainbow($event)\">",
|
||||
"bold": [
|
||||
"(click)"
|
||||
],
|
||||
"description": "<p>Calls method <code>readRainbow</code> when a click event is triggered on this button element (or its children) and passes in the event object.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<div title=\"Hello {{ponyName}}\">",
|
||||
"bold": [
|
||||
"{{ponyName}}"
|
||||
],
|
||||
"description": "<p>Binds a property to an interpolated string, e.g. "Hello Seabiscuit". Equivalent to:\n<code><div [title]="'Hello' + ponyName"></code></p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<p>Hello {{ponyName}}</p>",
|
||||
"bold": [
|
||||
"{{ponyName}}"
|
||||
],
|
||||
"description": "<p>Binds text content to an interpolated string, e.g. "Hello Seabiscuit".</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<my-cmp [(title)]=\"name\">",
|
||||
"bold": [
|
||||
"[(title)]"
|
||||
],
|
||||
"description": "<p>Sets up two-way data binding. Equivalent to: <code><my-cmp [title]="name" (title-change)="name=$event"></code></p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<video #movieplayer ...>\n <button (click)=\"movieplayer.play()\">\n</video>",
|
||||
"bold": [
|
||||
"#movieplayer",
|
||||
"(click)"
|
||||
],
|
||||
"description": "<p>Creates a local variable <code>movieplayer</code> that provides access to the <code>video</code> element instance in data-binding and event-binding expressions in the current template.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<p *my-unless=\"myExpression\">...</p>",
|
||||
"bold": [
|
||||
"*my-unless"
|
||||
],
|
||||
"description": "<p>The <code>*</code> symbol means that the current element will be turned into an embedded template. Equivalent to:\n<code><template [myless]="myExpression"><p>...</p></template></code></p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<p>Card No.: {{cardNumber | myCreditCardNumberFormatter}}</p>",
|
||||
"bold": [
|
||||
"{{cardNumber | myCreditCardNumberFormatter}}"
|
||||
],
|
||||
"description": "<p>Transforms the current value of expression <code>cardNumber</code> via the pipe called <code>creditCardNumberFormatter</code>.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<p>Employer: {{employer?.companyName}}</p>",
|
||||
"bold": [
|
||||
"{{employer?.companyName}}"
|
||||
],
|
||||
"description": "<p>The Elvis operator (<code>?</code>) means that the <code>employer</code> field is optional and if <code>undefined</code>, the rest of the expression should be ignored.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"name": "Built-in directives",
|
||||
"description": "<p><code>import {NgIf, ...} from 'angular2/angular2';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "<section *ng-if=\"showSection\">",
|
||||
"bold": [
|
||||
"*ng-if"
|
||||
],
|
||||
"description": "<p>Removes or recreates a portion of the DOM tree based on the showSection expression.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<li *ng-for=\"#item of list\">",
|
||||
"bold": [
|
||||
"*ng-for"
|
||||
],
|
||||
"description": "<p>Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.</p>\n"
|
||||
},
|
||||
{
|
||||
"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": "<p>Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of conditionExpression.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<div [ng-class]=\"{active: isActive, disabled: isDisabled}\">",
|
||||
"bold": [
|
||||
"[ng-class]"
|
||||
],
|
||||
"description": "<p>Binds the presence of css classes on the element to the truthiness of the associated map values. The right-hand side expression should return {class-name: true/false} map.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 1
|
||||
},
|
||||
{
|
||||
"name": "Forms",
|
||||
"description": "<p><code>import {FORM_DIRECTIVES} from 'angular2/angular2';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "<input [(ng-model)]=\"userName\">",
|
||||
"bold": [
|
||||
"[(ng-model)]"
|
||||
],
|
||||
"description": "<p>Provides two-way data-binding, parsing and validation for form controls.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 2
|
||||
},
|
||||
{
|
||||
"name": "Class decorators",
|
||||
"description": "<p><code>import {Directive, ...} from 'angular2/angular2';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "@Component({...})\nclass MyComponent() {}",
|
||||
"bold": [
|
||||
"@Component({...})"
|
||||
],
|
||||
"description": "<p>Declares that a class is a component and provides metadata about the component.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@Pipe({...})\nclass MyPipe() {}",
|
||||
"bold": [
|
||||
"@Pipe({...})"
|
||||
],
|
||||
"description": "<p>Declares that a class is a pipe and provides metadata about the pipe.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@Injectable()\nclass MyService() {}",
|
||||
"bold": [
|
||||
"@Injectable()"
|
||||
],
|
||||
"description": "<p>Declares that a class has dependencies that should be injected into the constructor when the dependency\ninjector is creating an instance of this class.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 3
|
||||
},
|
||||
{
|
||||
"name": "Directive configuration",
|
||||
"description": "<p><code>@Directive({ property1: value1, ... }) )</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "selector: '.cool-button:not(a)'",
|
||||
"bold": [
|
||||
"selector:"
|
||||
],
|
||||
"description": "<p>Specifies a css selector that identifies this directive within a template. Supported selectors include: <code>element</code>,\n<code>[attribute]</code>, <code>.class</code>, and <code>:not()</code>.</p>\n<p>Does not support parent-child relationship selectors.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "providers: [MyService, provide(...)]",
|
||||
"bold": [
|
||||
"providers:"
|
||||
],
|
||||
"description": "<p>Array of dependency injection providers for this directive and its children.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 4
|
||||
},
|
||||
{
|
||||
"name": "Component configuration",
|
||||
"description": "<p><code>@Component</code> extends <code>@Directive</code>,\nso the <code>@Directive</code> configuration applies to components as well</p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "viewProviders: [MyService, provide(...)]",
|
||||
"bold": [
|
||||
"viewProviders:"
|
||||
],
|
||||
"description": "<p>Array of dependency injection providers scoped to this component's view.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "template: 'Hello {{name}}'\ntemplateUrl: 'my-component.html'",
|
||||
"bold": [
|
||||
"template:",
|
||||
"templateUrl:"
|
||||
],
|
||||
"description": "<p>Inline template / external template url of the component's view.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "styles: ['.primary {color: red}']\nstyleUrls: ['my-component.css']",
|
||||
"bold": [
|
||||
"styles:",
|
||||
"styleUrls:"
|
||||
],
|
||||
"description": "<p>List of inline css styles / external stylesheet urls for styling component’s view.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "directives: [MyDirective, MyComponent]",
|
||||
"bold": [
|
||||
"directives:"
|
||||
],
|
||||
"description": "<p>List of directives used in the the component’s template.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "pipes: [MyPipe, OtherPipe]",
|
||||
"bold": [
|
||||
"pipes:"
|
||||
],
|
||||
"description": "<p>List of pipes used in the component's template.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 5
|
||||
},
|
||||
{
|
||||
"name": "Class field decorators for directives and components",
|
||||
"description": "<p><code>import {Input, ...} from 'angular2/angular2';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "@Input() myProperty;",
|
||||
"bold": [
|
||||
"@Input()"
|
||||
],
|
||||
"description": "<p>Declares an input property that we can update via property binding, e.g.\n<code><my-cmp [my-property]="someExpression"></code></p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@Output() myEvent = new EventEmitter();",
|
||||
"bold": [
|
||||
"@Output()"
|
||||
],
|
||||
"description": "<p>Declares an output property that fires events to which we can subscribe with an event binding, e.g. <code><my-cmp (my-event)="doSomething()"></code></p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@HostBinding('[class.valid]') isValid;",
|
||||
"bold": [
|
||||
"@HostBinding('[class.valid]')"
|
||||
],
|
||||
"description": "<p>Binds a host element property (e.g. css class valid) to directive/component property (e.g. isValid)</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@HostListener('click', ['$event']) onClick(e) {...}",
|
||||
"bold": [
|
||||
"@HostListener('click', ['$event'])"
|
||||
],
|
||||
"description": "<p>Subscribes to a host element event (e.g. click) with a directive/component method (e.g., onClick), optionally passing an argument ($event)</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@ContentChild(myPredicate) myChildComponent;",
|
||||
"bold": [
|
||||
"@ContentChild(myPredicate)"
|
||||
],
|
||||
"description": "<p>Binds the first result of the component content query (myPredicate) to the myChildComponent property of the class.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@ContentChildren(myPredicate) myChildComponents;",
|
||||
"bold": [
|
||||
"@ContentChildren(myPredicate)"
|
||||
],
|
||||
"description": "<p>Binds the results of the component content query (myPredicate) to the myChildComponents property of the class.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@ViewChild(myPredicate) myChildComponent;",
|
||||
"bold": [
|
||||
"@ViewChild(myPredicate)"
|
||||
],
|
||||
"description": "<p>Binds the first result of the component view query (myPredicate) to the myChildComponent property of the class. Not available for directives.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@ViewChildren(myPredicate) myChildComponents;",
|
||||
"bold": [
|
||||
"@ViewChildren(myPredicate)"
|
||||
],
|
||||
"description": "<p>Binds the results of the component view query (myPredicate) to the myChildComponents property of the class. Not available for directives.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 6
|
||||
},
|
||||
{
|
||||
"name": "Directive and component change detection and lifecycle hooks",
|
||||
"description": "<p>(implemented as class methods)</p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "constructor(myService: MyService, ...) { ... }",
|
||||
"bold": [
|
||||
"constructor(myService: MyService, ...)"
|
||||
],
|
||||
"description": "<p>The class constructor is called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "onChanges(changeRecord) { ... }",
|
||||
"bold": [
|
||||
"onChanges(changeRecord)"
|
||||
],
|
||||
"description": "<p>Called after every change to input properties and before processing content or child views.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "onInit() { ... }",
|
||||
"bold": [
|
||||
"onInit()"
|
||||
],
|
||||
"description": "<p>Called after the constructor, initializing input properties, and the first call to onChanges.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "doCheck() { ... }",
|
||||
"bold": [
|
||||
"doCheck()"
|
||||
],
|
||||
"description": "<p>Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "afterContentInit() { ... }",
|
||||
"bold": [
|
||||
"afterContentInit()"
|
||||
],
|
||||
"description": "<p>Called after onInit when the component's or directive's content has been initialized.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "afterContentChecked() { ... }",
|
||||
"bold": [
|
||||
"afterContentChecked()"
|
||||
],
|
||||
"description": "<p>Called after every check of the component's or directive's content.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "afterViewInit() { ... }",
|
||||
"bold": [
|
||||
"afterViewInit()"
|
||||
],
|
||||
"description": "<p>Called after onContentInit when the component's view has been initialized. Applies to components only.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "afterViewChecked() { ... }",
|
||||
"bold": [
|
||||
"afterViewChecked()"
|
||||
],
|
||||
"description": "<p>Called after every check of the component's view. Applies to components only.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "onDestroy() { ... }",
|
||||
"bold": [
|
||||
"onDestroy()"
|
||||
],
|
||||
"description": "<p>Called once, before the instance is destroyed.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 6
|
||||
},
|
||||
{
|
||||
"name": "Dependency injection configuration",
|
||||
"description": "<p><code>import {provide} from 'angular2/angular2';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "provide(MyService, {useClass: MyMockService})",
|
||||
"bold": [],
|
||||
"description": "<p><code>provide</code>|<code>useClass</code>\nSets or overrides the provider for MyService to the MyMockService class.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "provide(MyService, {useFactory: myFactory})",
|
||||
"bold": [],
|
||||
"description": "<p><code>provide</code>|<code>useFactory</code>\nSets or overrides the provider for MyService to the myFactory factory function.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "provide(MyValue, {useValue: 41})",
|
||||
"bold": [],
|
||||
"description": "<p><code>provide</code>|<code>useValue</code>\nSets or overrides the provider for MyValue to the value 41.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 7
|
||||
},
|
||||
{
|
||||
"name": "Routing and navigation",
|
||||
"description": "<p><code>import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, ...} from 'angular2/router';</code></p>\n",
|
||||
"items": [
|
||||
{
|
||||
"syntax": "@RouteConfig([\n { path: '/:myParam', component: MyComponent, as: 'MyCmp' },\n { path: '/staticPath', component: ..., as: ...},\n { path: '/*wildCardParam', component: ..., as: ...}\n])\nclass MyComponent() {}",
|
||||
"bold": [
|
||||
"@RouteConfig"
|
||||
],
|
||||
"description": "<p>Configures routes for the decorated component. Supports static, parameterized and wildcard routes.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<router-outlet></router-outlet>",
|
||||
"bold": [
|
||||
"router-outlet"
|
||||
],
|
||||
"description": "<p>Marks the location to load the component of the active route.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "<a [router-link]=\"[ '/MyCmp', {myParam: 'value' } ]\">",
|
||||
"bold": [
|
||||
"[router-link]"
|
||||
],
|
||||
"description": "<p>Creates a link to a different view based on a route instruction consisting of a route name and optional parameters. The route name matches the as property of a configured route. Add the '/' prefix to navigate to a root route; add the './' prefix for a child route.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "@CanActivate(() => { ... })class MyComponent() {}",
|
||||
"bold": [
|
||||
"@CanActivate"
|
||||
],
|
||||
"description": "<p>A component decorator defining a function that the router should call first to determine if it should activate this component. Should return a boolean or a promise.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "onActivate(nextInstruction, prevInstruction) { ... }",
|
||||
"bold": [
|
||||
"onActivate"
|
||||
],
|
||||
"description": "<p>After navigating to a component, the router calls component's onActivate method (if defined).</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "canReuse(nextInstruction, prevInstruction) { ... }",
|
||||
"bold": [
|
||||
"canReuse"
|
||||
],
|
||||
"description": "<p>The router calls a component's canReuse method (if defined) to determine whether to reuse the instance or destroy it and create a new instance. Should return a boolean or a promise.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "onReuse(nextInstruction, prevInstruction) { ... }",
|
||||
"bold": [
|
||||
"onReuse"
|
||||
],
|
||||
"description": "<p>The router calls the component's onReuse method (if defined) when it re-uses a component instance.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "canDeactivate(nextInstruction, prevInstruction) { ... }",
|
||||
"bold": [
|
||||
"canDeactivate"
|
||||
],
|
||||
"description": "<p>The router calls the canDeactivate methods (if defined) of every component that would be removed after a navigation. The navigation proceeds if and only if all such methods return true or a promise that is resolved.</p>\n"
|
||||
},
|
||||
{
|
||||
"syntax": "onDeactivate(nextInstruction, prevInstruction) { ... }",
|
||||
"bold": [
|
||||
"onDeactivate"
|
||||
],
|
||||
"description": "<p>Called before the directive is removed as the result of a route change. May return a promise that pauses removing the directive until the promise resolves.</p>\n"
|
||||
}
|
||||
],
|
||||
"index": 8
|
||||
}
|
||||
]
|
|
@ -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')
|
||||
];
|
Loading…
Reference in New Issue