parent
983c00c495
commit
27e03591dd
|
@ -19,3 +19,6 @@ packages
|
||||||
pubspec.lock
|
pubspec.lock
|
||||||
.c9
|
.c9
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
|
||||||
|
docs/bower_components/
|
|
@ -0,0 +1,405 @@
|
||||||
|
|
||||||
|
.hide { display: none !important; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #3f51b5;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding: $baseline-grid ($baseline-grid * 2);
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
border-bottom: 2px solid #ddd;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre > code.highlight {
|
||||||
|
padding: 10px;
|
||||||
|
font-weight: 400;
|
||||||
|
-webkit-user-select: initial;
|
||||||
|
-moz-user-select: initial;
|
||||||
|
-ms-user-select: initial;
|
||||||
|
user-select: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre, code {
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
font-family: monospace, serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pre > code.highlight {
|
||||||
|
padding: 10px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-size: 14px;
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
code.highlight {
|
||||||
|
display: block;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
code:not(.highlight) {
|
||||||
|
color: #4285f4;
|
||||||
|
margin-left: 1px;
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-sidenav-inner {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-content,
|
||||||
|
.doc-content {
|
||||||
|
max-width: 864px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.layout-label {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
.layout-content code.highlight {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
background: none;
|
||||||
|
border-width: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
color: #333;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: 40px;
|
||||||
|
max-height: 40px;
|
||||||
|
opacity: 1;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
padding: 0px 28px;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
text-decoration: none;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
-webkit-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
-webkit-transition-property: max-height, background-color, opacity;
|
||||||
|
-moz-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
-moz-transition-property: max-height, background-color, opacity;
|
||||||
|
transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
transition-property: max-height, background-color, opacity;
|
||||||
|
}
|
||||||
|
.menu-item.ng-hide {
|
||||||
|
max-height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.menu-item:hover {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.menu-item:focus {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.menu-item.menu-title {
|
||||||
|
color: #888;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 16px;
|
||||||
|
text-align: left;
|
||||||
|
text-transform: uppercase;
|
||||||
|
transition: color 0.35s cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
}
|
||||||
|
.menu-item.menu-title:hover,
|
||||||
|
.menu-item.menu-title.active {
|
||||||
|
color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.app-toolbar .md-toolbar-tools h3 {
|
||||||
|
-webkit-margin-before: 0;
|
||||||
|
-webkit-margin-after: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-container {
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 16px;
|
||||||
|
-webkit-transition: 0.02s padding cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
transition: 0.02s padding cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
.demo-source-tabs {
|
||||||
|
z-index: 1;
|
||||||
|
-webkit-transition: all 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
transition: all 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||||
|
max-height: 448px;
|
||||||
|
min-height: 448px;
|
||||||
|
background: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
md-tabs.demo-source-tabs md-tab,
|
||||||
|
md-tabs.demo-source-tabs .md-header {
|
||||||
|
background-color: #444444 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
md-tabs.demo-source-tabs md-tab-label {
|
||||||
|
color: #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
md-tabs.demo-source-tabs .active md-tab-label {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-source-tabs.ng-hide {
|
||||||
|
max-height: 0px;
|
||||||
|
min-height: 0px;
|
||||||
|
}
|
||||||
|
.demo-source-tabs {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
.demo-content {
|
||||||
|
position: relative;
|
||||||
|
overflow:hidden;
|
||||||
|
min-height: 448px;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -moz-box;
|
||||||
|
display: -moz-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.small-demo .demo-source-tabs:not(.ng-hide) {
|
||||||
|
min-height: 224px;
|
||||||
|
max-height: 224px;
|
||||||
|
}
|
||||||
|
.small-demo .demo-content {
|
||||||
|
min-height: 128px;
|
||||||
|
}
|
||||||
|
.demo-content > * {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
-moz-box-flex: 1;
|
||||||
|
-moz-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-content > div[layout-fill] {
|
||||||
|
min-height: 448px;
|
||||||
|
}
|
||||||
|
.small-demo .demo-content > div[layout-fill] {
|
||||||
|
min-height: 224px;
|
||||||
|
}
|
||||||
|
.small-demo .demo-toolbar,
|
||||||
|
.small-demo .md-toolbar-tools {
|
||||||
|
min-height: 48px;
|
||||||
|
max-height: 48px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-source md-toolbar.demo-toolbar {
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.36);
|
||||||
|
}
|
||||||
|
.demo-toolbar .md-button {
|
||||||
|
color: #616161;
|
||||||
|
}
|
||||||
|
|
||||||
|
md-toolbar.demo-toolbar,
|
||||||
|
.demo-source-tabs md-tab,
|
||||||
|
.demo-source-tabs .tabs-header {
|
||||||
|
background: #E0E0E0 !important;
|
||||||
|
color: #616161;
|
||||||
|
}
|
||||||
|
md-toolbar.demo-toolbar md-tab-label {
|
||||||
|
color: #99E4EE
|
||||||
|
}
|
||||||
|
md-toolbar.demo-toolbar .md-button:hover,
|
||||||
|
md-toolbar.demo-toolbar .md-button:focus,
|
||||||
|
md-toolbar.demo-toolbar .md-button.active {
|
||||||
|
background: rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
md-toolbar.demo-toolbar .md-button {
|
||||||
|
-webkit-transition: all 0.3s linear;
|
||||||
|
-moz-transition: all 0.3s linear;
|
||||||
|
transition: all 0.3s linear;
|
||||||
|
}
|
||||||
|
.demo-source-container {
|
||||||
|
display: block;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-source-content {
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
.demo-source-content,
|
||||||
|
.demo-source-content pre,
|
||||||
|
.demo-source-content code {
|
||||||
|
background: #f6f6f6;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.demo-source-content pre {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-source div[demo-include] {
|
||||||
|
border-top: #ddd solid 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.menu-separator-icon {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.menu-module-name {
|
||||||
|
opacity: 0.6;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************
|
||||||
|
* DOCS
|
||||||
|
************/
|
||||||
|
.api-options-bar .md-button {
|
||||||
|
margin: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
.api-options-bar .md-button:hover,
|
||||||
|
.api-options-bar .md-button:focus {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.api-options-bar.with-icon md-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: -3px;
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
.api-options-bar.with-icon .md-button span {
|
||||||
|
margin-left: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-params-item {
|
||||||
|
min-height: 72px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.api-params-label {
|
||||||
|
margin-right: 8px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 14px;
|
||||||
|
-webkit-align-self: flex-start;
|
||||||
|
-moz-align-self: flex-start;
|
||||||
|
-ms-flex-item-align: start;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
.api-params-title {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
code.api-type {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
margin-top: 3px;
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
ul li:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-title {
|
||||||
|
color: #999999;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-params-content ul {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
ul.methods > li {
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.methods .method-function-syntax {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 20px;
|
||||||
|
margin: 0;
|
||||||
|
-webkit-margin-before: 0;
|
||||||
|
-webkit-margin-after: 0;
|
||||||
|
}
|
||||||
|
ul.methods li h3 {
|
||||||
|
/* border-bottom: 1px solid #eee; */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
ul.methods > li {
|
||||||
|
padding-left: 0;
|
||||||
|
border-left: none;
|
||||||
|
list-style: default;
|
||||||
|
}
|
||||||
|
ul.methods .method-function-syntax {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
padding-left: 10px;
|
||||||
|
text-decoration: underline;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-source-container pre,
|
||||||
|
.demo-source-container code {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
md-content.demo-source-container > hljs > pre > code.highlight {
|
||||||
|
position : absolute;
|
||||||
|
top : 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.extraPad {
|
||||||
|
padding-left:32px !important;
|
||||||
|
padding-right:32px !important;
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Angular 2 Docs</title>
|
||||||
|
<base href="/">
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="/lib/angular-material/angular-material.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/app.css">
|
||||||
|
|
||||||
|
<script src="/lib/hammerjs/hammer.js"></script>
|
||||||
|
<script src="/lib/angular/angular.js"></script>
|
||||||
|
<script src="/lib/angular-animate/angular-animate.js"></script>
|
||||||
|
<script src="/lib/angular-aria/angular-aria.js"></script>
|
||||||
|
<script src="/lib/angular-material/angular-material.js"></script>
|
||||||
|
<script src="/js/navigation-modules.js"></script>
|
||||||
|
<script src="/js/navigation-guides.js"></script>
|
||||||
|
<script src="/js/app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body ng-app="app" ng-controller="NavController as nav" layout="column">
|
||||||
|
|
||||||
|
<md-toolbar md-scroll-shrink>
|
||||||
|
<h1 class="md-toolbar-tools">Angular V2</h1>
|
||||||
|
</md-toolbar>
|
||||||
|
|
||||||
|
<section layout="row">
|
||||||
|
|
||||||
|
<md-content>
|
||||||
|
<h2>Navigation</h2>
|
||||||
|
<section ng-repeat="area in nav.areas">
|
||||||
|
<h3>{{ area.name }}</h3>
|
||||||
|
<md-list>
|
||||||
|
<md-item ng-repeat="section in area.sections">
|
||||||
|
<h3><a href="{{section.path}}">{{section.name}}</a></h3>
|
||||||
|
<ul>
|
||||||
|
<li ng-repeat="page in section.pages">
|
||||||
|
<a href="{{page.path}}">{{ page.name }}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</md-item>
|
||||||
|
</md-list>
|
||||||
|
</section>
|
||||||
|
</md-content>
|
||||||
|
|
||||||
|
|
||||||
|
<md-content class="md-padding">
|
||||||
|
<ng-include src="nav.currentPage.partial"></ng-include>
|
||||||
|
</md-content>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,47 @@
|
||||||
|
angular.module('app', ['ngMaterial', 'navigation-modules', 'navigation-guides'])
|
||||||
|
|
||||||
|
.config(function($locationProvider) {
|
||||||
|
$locationProvider.html5Mode(true);
|
||||||
|
})
|
||||||
|
|
||||||
|
.controller('NavController', ['$scope', '$location', 'MODULES', 'GUIDES',
|
||||||
|
function($scope, $location, MODULES, GUIDES) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
this.areas = [
|
||||||
|
{ name: 'Guides', sections: [ { pages: GUIDES.pages } ] },
|
||||||
|
{ name: 'Modules', sections: MODULES.sections }
|
||||||
|
];
|
||||||
|
|
||||||
|
this.updateCurrentPage = function(path) {
|
||||||
|
path = path.replace(/^\//, '');
|
||||||
|
console.log('path', path);
|
||||||
|
this.currentPage = null;
|
||||||
|
|
||||||
|
this.areas.forEach(function(area) {
|
||||||
|
area.sections.forEach(function(section) {
|
||||||
|
|
||||||
|
// Short-circuit out if the page has been found
|
||||||
|
if ( that.currentPage ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section.path === path) {
|
||||||
|
console.log('found!');
|
||||||
|
that.currentPage = section;
|
||||||
|
} else {
|
||||||
|
section.pages.forEach(function(page) {
|
||||||
|
if (page.path === path) {
|
||||||
|
that.currentPage = page;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watch(
|
||||||
|
function getLocationPath() { return $location.path(); },
|
||||||
|
function handleLocationPathChange(path) { that.updateCurrentPage(path); }
|
||||||
|
);
|
||||||
|
}]);
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "angular-docs",
|
||||||
|
"main": "index.js",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"homepage": "https://github.com/angular/angular",
|
||||||
|
"authors": [],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"private": true,
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"angular-material": "~0.6.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
var Package = require('dgeni').Package;
|
||||||
|
var jsdocPackage = require('dgeni-packages/jsdoc');
|
||||||
|
var nunjucksPackage = require('dgeni-packages/nunjucks');
|
||||||
|
var path = require('canonical-path');
|
||||||
|
|
||||||
|
var PARTIAL_PATH = 'partials';
|
||||||
|
var MODULES_DOCS_PATH = PARTIAL_PATH + '/modules';
|
||||||
|
var GUIDES_PATH = PARTIAL_PATH + '/guides';
|
||||||
|
|
||||||
|
// Define the dgeni package for generating the docs
|
||||||
|
module.exports = new Package('angular', [jsdocPackage, nunjucksPackage])
|
||||||
|
|
||||||
|
// Register the services and file readers
|
||||||
|
.factory(require('./services/atParser'))
|
||||||
|
.factory(require('./services/getJSDocComment'))
|
||||||
|
.factory(require('./services/ExportTreeVisitor'))
|
||||||
|
.factory(require('./readers/atScript'))
|
||||||
|
.factory(require('./readers/ngdoc'))
|
||||||
|
|
||||||
|
|
||||||
|
// Register the processors
|
||||||
|
.processor(require('./processors/generateDocsFromComments'))
|
||||||
|
.processor(require('./processors/processModuleDocs'))
|
||||||
|
.processor(require('./processors/processClassDocs'))
|
||||||
|
.processor(require('./processors/generateNavigationDoc'))
|
||||||
|
|
||||||
|
|
||||||
|
// Configure the log service
|
||||||
|
.config(function(log) {
|
||||||
|
log.level = 'info';
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Configure file reading
|
||||||
|
.config(function(readFilesProcessor, atScriptFileReader, ngdocFileReader) {
|
||||||
|
readFilesProcessor.fileReaders = [atScriptFileReader, ngdocFileReader];
|
||||||
|
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
||||||
|
readFilesProcessor.sourceFiles = [
|
||||||
|
{ include: 'modules/*/src/**/*.js', basePath: 'modules' },
|
||||||
|
{ include: 'modules/*/docs/**/*.md', basePath: 'modules' },
|
||||||
|
{ include: 'docs/content/**/*.md', basePath: 'docs/content' }
|
||||||
|
];
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Configure file writing
|
||||||
|
.config(function(writeFilesProcessor) {
|
||||||
|
writeFilesProcessor.outputFolder = 'build/docs';
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Configure rendering
|
||||||
|
.config(function(templateFinder, templateEngine) {
|
||||||
|
|
||||||
|
// Nunjucks and Angular conflict in their template bindings so change Nunjucks
|
||||||
|
templateEngine.config.tags = {
|
||||||
|
variableStart: '{$',
|
||||||
|
variableEnd: '$}'
|
||||||
|
};
|
||||||
|
|
||||||
|
templateFinder.templateFolders
|
||||||
|
.unshift(path.resolve(__dirname, 'templates'));
|
||||||
|
|
||||||
|
templateFinder.templatePatterns = [
|
||||||
|
'${ doc.template }',
|
||||||
|
'${ doc.id }.${ doc.docType }.template.html',
|
||||||
|
'${ doc.id }.template.html',
|
||||||
|
'${ doc.docType }.template.html',
|
||||||
|
'common.template.html'
|
||||||
|
];
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Configure ids and paths
|
||||||
|
.config(function(computeIdsProcessor, computePathsProcessor) {
|
||||||
|
|
||||||
|
computeIdsProcessor.idTemplates.push({
|
||||||
|
docTypes: [
|
||||||
|
'class',
|
||||||
|
'function',
|
||||||
|
'NAMED_EXPORT',
|
||||||
|
'VARIABLE_STATEMENT'
|
||||||
|
],
|
||||||
|
idTemplate: '${moduleDoc.id}.${name}',
|
||||||
|
getAliases: function(doc) { return [doc.id]; }
|
||||||
|
});
|
||||||
|
|
||||||
|
computeIdsProcessor.idTemplates.push({
|
||||||
|
docTypes: ['member'],
|
||||||
|
idTemplate: '${classDoc.id}.${name}',
|
||||||
|
getAliases: function(doc) { return [doc.id]; }
|
||||||
|
});
|
||||||
|
|
||||||
|
computeIdsProcessor.idTemplates.push({
|
||||||
|
docTypes: ['guide'],
|
||||||
|
getId: function(doc) {
|
||||||
|
return doc.fileInfo.relativePath
|
||||||
|
// path should be relative to `modules` folder
|
||||||
|
.replace(/.*\/?modules\//, '')
|
||||||
|
// path should not include `/docs/`
|
||||||
|
.replace(/\/docs\//, '/')
|
||||||
|
// path should not have a suffix
|
||||||
|
.replace(/\.\w*$/, '');
|
||||||
|
},
|
||||||
|
getAliases: function(doc) { return [doc.id]; }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
computePathsProcessor.pathTemplates.push({
|
||||||
|
docTypes: ['module'],
|
||||||
|
pathTemplate: '${id}',
|
||||||
|
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.html'
|
||||||
|
});
|
||||||
|
|
||||||
|
computePathsProcessor.pathTemplates.push({
|
||||||
|
docTypes: [
|
||||||
|
'class',
|
||||||
|
'function',
|
||||||
|
'NAMED_EXPORT',
|
||||||
|
'VARIABLE_STATEMENT'
|
||||||
|
],
|
||||||
|
pathTemplate: '${moduleDoc.path}/${name}',
|
||||||
|
outputPathTemplate: MODULES_DOCS_PATH + '/${path}/index.html'
|
||||||
|
});
|
||||||
|
|
||||||
|
computePathsProcessor.pathTemplates.push({
|
||||||
|
docTypes: ['member'],
|
||||||
|
pathTemplate: '${classDoc.path}/${name}',
|
||||||
|
getOutputPath: function() {} // These docs are not written to their own file, instead they are part of their class doc
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
computePathsProcessor.pathTemplates.push({
|
||||||
|
docTypes: ['guide'],
|
||||||
|
pathTemplate: '${id}',
|
||||||
|
outputPathTemplate: GUIDES_PATH + '/${id}.html'
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
var Package = require('dgeni').Package;
|
||||||
|
|
||||||
|
module.exports = function mockPackage() {
|
||||||
|
|
||||||
|
return new Package('mockPackage', [require('../')])
|
||||||
|
|
||||||
|
// provide a mock log service
|
||||||
|
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); });
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,34 @@
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = function generateDocsFromComments(log) {
|
||||||
|
return {
|
||||||
|
$runAfter: ['files-read'],
|
||||||
|
$runBefore: ['parsing-tags'],
|
||||||
|
$process: function(docs) {
|
||||||
|
var commentDocs = [];
|
||||||
|
docs = _.filter(docs, function(doc) {
|
||||||
|
if (doc.docType !== 'atScriptFile') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
_.forEach(doc.fileInfo.comments, function(comment) {
|
||||||
|
|
||||||
|
// we need to check for `/**` at the start of the comment to find all the jsdoc style comments
|
||||||
|
comment.range.toString().replace(/^\/\*\*([\w\W]*)\*\/$/g, function(match, commentBody) {
|
||||||
|
|
||||||
|
// Create a doc from this comment
|
||||||
|
commentDocs.push({
|
||||||
|
fileInfo: doc.fileInfo,
|
||||||
|
startingLine: comment.range.start.line,
|
||||||
|
endingLine: comment.range.end.line,
|
||||||
|
content: commentBody,
|
||||||
|
codeTree: comment.treeAfter,
|
||||||
|
docType: 'atScriptDoc'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return docs.concat(commentDocs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,66 @@
|
||||||
|
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) {
|
||||||
|
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.id,
|
||||||
|
type: 'guide'
|
||||||
|
};
|
||||||
|
guidesDoc.value.pages.push(guideDoc)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
docs.push(guidesDoc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = function processClassDocs(log, getJSDocComment) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
$runAfter: ['processModuleDocs'],
|
||||||
|
$runBefore: ['parsing-tags', 'generateDocsFromComments'],
|
||||||
|
$process: function(docs) {
|
||||||
|
var memberDocs = [];
|
||||||
|
_.forEach(docs, function(classDoc) {
|
||||||
|
if ( classDoc.docType === 'class' ) {
|
||||||
|
|
||||||
|
classDoc.members = [];
|
||||||
|
|
||||||
|
// Create a new doc for each member of the class
|
||||||
|
_.forEach(classDoc.elements, function(memberDoc) {
|
||||||
|
|
||||||
|
classDoc.members.push(memberDoc);
|
||||||
|
memberDocs.push(memberDoc);
|
||||||
|
|
||||||
|
memberDoc.docType = 'member';
|
||||||
|
memberDoc.classDoc = classDoc;
|
||||||
|
memberDoc.name = memberDoc.name.literalToken.value;
|
||||||
|
|
||||||
|
if (memberDoc.commentBefore ) {
|
||||||
|
// If this export has a comment, remove it from the list of
|
||||||
|
// comments collected in the module
|
||||||
|
var index = classDoc.moduleDoc.comments.indexOf(memberDoc.commentBefore);
|
||||||
|
if ( index !== -1 ) {
|
||||||
|
classDoc.moduleDoc.comments.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.assign(memberDoc, getJSDocComment(memberDoc.commentBefore));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return docs.concat(memberDocs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,46 @@
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = function processModuleDocs(log, ExportTreeVisitor, getJSDocComment) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
$runAfter: ['files-read'],
|
||||||
|
$runBefore: ['parsing-tags', 'generateDocsFromComments'],
|
||||||
|
$process: function(docs) {
|
||||||
|
var exportDocs = [];
|
||||||
|
_.forEach(docs, function(doc) {
|
||||||
|
if ( doc.docType === 'module' ) {
|
||||||
|
|
||||||
|
log.debug('processing', doc.moduleTree.moduleName);
|
||||||
|
|
||||||
|
doc.exports = [];
|
||||||
|
|
||||||
|
if ( doc.moduleTree.visit ) {
|
||||||
|
var visitor = new ExportTreeVisitor();
|
||||||
|
visitor.visit(doc.moduleTree);
|
||||||
|
|
||||||
|
_.forEach(visitor.exports, function(exportDoc) {
|
||||||
|
|
||||||
|
doc.exports.push(exportDoc);
|
||||||
|
exportDocs.push(exportDoc);
|
||||||
|
exportDoc.moduleDoc = doc;
|
||||||
|
|
||||||
|
if (exportDoc.comment) {
|
||||||
|
// If this export has a comment, remove it from the list of
|
||||||
|
// comments collected in the module
|
||||||
|
var index = doc.comments.indexOf(exportDoc.comment);
|
||||||
|
if ( index !== -1 ) {
|
||||||
|
doc.comments.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.assign(exportDoc, getJSDocComment(exportDoc.comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return docs.concat(exportDocs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
var path = require('canonical-path');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dgService atScriptFileReader
|
||||||
|
* @description
|
||||||
|
* This file reader will create a simple doc for each
|
||||||
|
* file including a code AST of the AtScript in the file.
|
||||||
|
*/
|
||||||
|
module.exports = function atScriptFileReader(log, atParser) {
|
||||||
|
var reader = {
|
||||||
|
name: 'atScriptFileReader',
|
||||||
|
defaultPattern: /\.js$/,
|
||||||
|
getDocs: function(fileInfo) {
|
||||||
|
|
||||||
|
var moduleDoc = atParser.parseModule(fileInfo);
|
||||||
|
moduleDoc.docType = 'module';
|
||||||
|
moduleDoc.id = moduleDoc.moduleTree.moduleName;
|
||||||
|
moduleDoc.aliases = [moduleDoc.id];
|
||||||
|
|
||||||
|
// Readers return a collection of docs read from the file
|
||||||
|
// but in this read there is only one document (module) to return
|
||||||
|
return [moduleDoc];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return reader;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,55 @@
|
||||||
|
var mockPackage = require('../mocks/mockPackage');
|
||||||
|
var Dgeni = require('dgeni');
|
||||||
|
|
||||||
|
describe('atScript file reader', function() {
|
||||||
|
|
||||||
|
var dgeni, injector, reader;
|
||||||
|
|
||||||
|
var fileContent =
|
||||||
|
'import {CONST} from "facade/lang";\n' +
|
||||||
|
'\n' +
|
||||||
|
'/**\n' +
|
||||||
|
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||||
|
'*\n' +
|
||||||
|
'* class AComponent {\n' +
|
||||||
|
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||||
|
'* }\n' +
|
||||||
|
'*\n' +
|
||||||
|
'*/\n' +
|
||||||
|
'export class Inject {\n' +
|
||||||
|
'token;\n' +
|
||||||
|
'@CONST()\n' +
|
||||||
|
'constructor(token) {\n' +
|
||||||
|
'this.token = token;\n' +
|
||||||
|
'}\n' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
dgeni = new Dgeni([mockPackage()]);
|
||||||
|
injector = dgeni.configureInjector();
|
||||||
|
reader = injector.get('atScriptFileReader');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should provide a default pattern', function() {
|
||||||
|
expect(reader.defaultPattern).toEqual(/\.js$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should parse the file using the atParser and return a single doc', function() {
|
||||||
|
|
||||||
|
var atParser = injector.get('atParser');
|
||||||
|
spyOn(atParser, 'parseModule').and.callThrough();
|
||||||
|
|
||||||
|
var docs = reader.getDocs({
|
||||||
|
content: fileContent,
|
||||||
|
relativePath: 'di/src/annotations.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(atParser.parseModule).toHaveBeenCalled();
|
||||||
|
expect(docs.length).toEqual(1);
|
||||||
|
expect(docs[0].docType).toEqual('module');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
var path = require('canonical-path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dgService ngdocFileReader
|
||||||
|
* @description
|
||||||
|
* This file reader will pull the contents from a text file (by default .ngdoc)
|
||||||
|
*
|
||||||
|
* The doc will initially have the form:
|
||||||
|
* ```
|
||||||
|
* {
|
||||||
|
* content: 'the content of the file',
|
||||||
|
* startingLine: 1
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
module.exports = function ngdocFileReader() {
|
||||||
|
var reader = {
|
||||||
|
name: 'ngdocFileReader',
|
||||||
|
defaultPattern: /\.md$/,
|
||||||
|
getDocs: function(fileInfo) {
|
||||||
|
|
||||||
|
// We return a single element array because ngdoc files only contain one document
|
||||||
|
return [{
|
||||||
|
docType: 'guide',
|
||||||
|
content: fileInfo.content,
|
||||||
|
startingLine: 1
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return reader;
|
||||||
|
};
|
|
@ -0,0 +1,45 @@
|
||||||
|
var ngdocFileReaderFactory = require('./ngdoc');
|
||||||
|
var path = require('canonical-path');
|
||||||
|
|
||||||
|
describe('ngdocFileReader', function() {
|
||||||
|
|
||||||
|
var fileReader;
|
||||||
|
|
||||||
|
var createFileInfo = function(file, content, basePath) {
|
||||||
|
return {
|
||||||
|
fileReader: fileReader.name,
|
||||||
|
filePath: file,
|
||||||
|
baseName: path.basename(file, path.extname(file)),
|
||||||
|
extension: path.extname(file).replace(/^\./, ''),
|
||||||
|
basePath: basePath,
|
||||||
|
relativePath: path.relative(basePath, file),
|
||||||
|
content: content
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
fileReader = ngdocFileReaderFactory();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('defaultPattern', function() {
|
||||||
|
it('should match .md files', function() {
|
||||||
|
expect(fileReader.defaultPattern.test('abc.md')).toBeTruthy();
|
||||||
|
expect(fileReader.defaultPattern.test('abc.js')).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('getDocs', function() {
|
||||||
|
it('should return an object containing info about the file and its contents', function() {
|
||||||
|
var fileInfo = createFileInfo('project/path/modules/someModule/foo/docs/subfolder/bar.ngdoc', 'A load of content', 'project/path');
|
||||||
|
expect(fileReader.getDocs(fileInfo)).toEqual([{
|
||||||
|
docType: 'guide',
|
||||||
|
content: 'A load of content',
|
||||||
|
startingLine: 1
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
var traceur = require('traceur/src/node/traceur.js');
|
||||||
|
var ParseTreeVisitor = System.get("traceur@0.0.74/src/syntax/ParseTreeVisitor").ParseTreeVisitor;
|
||||||
|
|
||||||
|
module.exports = function ExportTreeVisitor(log) {
|
||||||
|
|
||||||
|
function ExportTreeVisitorImpl() {
|
||||||
|
ParseTreeVisitor.call(this);
|
||||||
|
}
|
||||||
|
ExportTreeVisitorImpl.prototype = {
|
||||||
|
|
||||||
|
__proto__: ParseTreeVisitor.prototype,
|
||||||
|
|
||||||
|
visitExportDeclaration: function(tree) {
|
||||||
|
// We are entering an export declaration - create an object to track it
|
||||||
|
this.currentExport = {
|
||||||
|
comment: tree.commentBefore,
|
||||||
|
location: tree.location
|
||||||
|
};
|
||||||
|
log.silly('enter', tree.type, tree.commentBefore ? 'has comment' : '');
|
||||||
|
ParseTreeVisitor.prototype.visitExportDeclaration.call(this, tree);
|
||||||
|
log.silly('exit', this.currentExport);
|
||||||
|
|
||||||
|
// We are exiting the export declaration - store the export object
|
||||||
|
this.exports.push(this.currentExport);
|
||||||
|
this.currentExport = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
visitVariableStatement: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
this.currentExport.name = "VARIABLE_STATEMENT";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visitVariableDeclaration: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
this.currentExport.name = tree.lvalue;
|
||||||
|
this.currentExport.variableDeclaration = tree;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visitFunctionDeclaration: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
this.currentExport.name = tree.name.identifierToken.value;
|
||||||
|
this.currentExport.functionKind = tree.functionKind;
|
||||||
|
this.currentExport.parameters = tree.parameterList.parameters;
|
||||||
|
this.currentExport.typeAnnotation = tree.typeAnnotation;
|
||||||
|
this.currentExport.annotations = tree.annotations;
|
||||||
|
this.currentExport.docType = 'function';
|
||||||
|
|
||||||
|
log.silly(tree.type, tree.commentBefore ? 'has comment' : '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
visitClassDeclaration: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
this.currentExport.name = tree.name.identifierToken.value;
|
||||||
|
this.currentExport.superClass = tree.superClass;
|
||||||
|
this.currentExport.annotations = tree.annotations;
|
||||||
|
this.currentExport.elements = tree.elements;
|
||||||
|
this.currentExport.docType = 'class';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
visitAsyncFunctionDeclaration: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visitExportDefault: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
this.currentExport.name = 'DEFAULT';
|
||||||
|
this.currentExport.defaultExport = tree;
|
||||||
|
// Default exports are either classes, functions or expressions
|
||||||
|
// So we let the super class continue down...
|
||||||
|
ParseTreeVisitor.prototype.visitExportDefault.call(this, tree);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visitNamedExport: function(tree) {
|
||||||
|
if ( this.currentExport ) {
|
||||||
|
this.updateExport(tree);
|
||||||
|
|
||||||
|
this.currentExport.namedExport = tree;
|
||||||
|
this.currentExport.name = 'NAMED_EXPORT';
|
||||||
|
// TODO: work out this bit!!
|
||||||
|
// We need to cope with any export specifiers in the named export
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO - if the export is an expression, find the thing that is being
|
||||||
|
// exported and use it and its comments for docs
|
||||||
|
|
||||||
|
updateExport: function(tree) {
|
||||||
|
this.currentExport.comment = this.currentExport.comment || tree.commentBefore;
|
||||||
|
this.currentExport.docType = tree.type;
|
||||||
|
},
|
||||||
|
|
||||||
|
visit: function(tree) {
|
||||||
|
this.exports = [];
|
||||||
|
ParseTreeVisitor.prototype.visit.call(this, tree);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ExportTreeVisitorImpl;
|
||||||
|
};
|
|
@ -0,0 +1,97 @@
|
||||||
|
var traceur = require('traceur/src/node/traceur.js');
|
||||||
|
var ParseTreeVisitor = System.get(System.map.traceur + '/src/syntax/ParseTreeVisitor').ParseTreeVisitor;
|
||||||
|
var file2modulename = require('../../../file2modulename');
|
||||||
|
/**
|
||||||
|
* Wrapper around traceur that can parse the contents of a file
|
||||||
|
*/
|
||||||
|
module.exports = function atParser(log) {
|
||||||
|
|
||||||
|
var service = {
|
||||||
|
/**
|
||||||
|
* The options to pass to traceur
|
||||||
|
*/
|
||||||
|
traceurOptions: {
|
||||||
|
annotations: true, // parse annotations
|
||||||
|
types: true, // parse types
|
||||||
|
memberVariables: true, // parse class fields
|
||||||
|
commentCallback: true // handle comments
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a module AST from the contents of a file.
|
||||||
|
* @param {Object} fileInfo information about the file to parse
|
||||||
|
* @return { { moduleTree: Object, comments: Array } } An object containing the parsed module
|
||||||
|
* AST and an array of all the comments found in the file
|
||||||
|
*/
|
||||||
|
parseModule: parseModule
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
|
||||||
|
// Parse the contents of the file using traceur
|
||||||
|
function parseModule(fileInfo) {
|
||||||
|
|
||||||
|
var moduleName = file2modulename(fileInfo.relativePath);
|
||||||
|
var sourceFile = new traceur.syntax.SourceFile(moduleName, fileInfo.content);
|
||||||
|
var parser = new traceur.syntax.Parser(sourceFile);
|
||||||
|
var comments = [];
|
||||||
|
var moduleTree;
|
||||||
|
|
||||||
|
// Configure the parser
|
||||||
|
parser.handleComment = function(range) {
|
||||||
|
comments.push({ range: range });
|
||||||
|
};
|
||||||
|
traceur.options.setFromObject(service.traceurOptions);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Parse the file as a module, attaching the comments
|
||||||
|
moduleTree = parser.parseModule();
|
||||||
|
attachComments(moduleTree, comments);
|
||||||
|
} catch(ex) {
|
||||||
|
// HACK: sometime traceur crashes for various reasons including
|
||||||
|
// Not Yet Implemented (NYI)!
|
||||||
|
log.error(ex.stack);
|
||||||
|
moduleTree = {};
|
||||||
|
}
|
||||||
|
log.debug(moduleName);
|
||||||
|
moduleTree.moduleName = moduleName;
|
||||||
|
|
||||||
|
// We return the module AST but also a collection of all the comments
|
||||||
|
// since it can be helpful to iterate through them without having to
|
||||||
|
// traverse the AST again
|
||||||
|
return {
|
||||||
|
moduleTree: moduleTree,
|
||||||
|
comments: comments
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach the comments to their nearest code tree
|
||||||
|
function attachComments(tree, comments) {
|
||||||
|
|
||||||
|
var visitor = new ParseTreeVisitor();
|
||||||
|
var index = 0;
|
||||||
|
var currentComment = comments[index];
|
||||||
|
|
||||||
|
if (currentComment) log.silly('comment: ' + currentComment.range.start.line + ' - ' + currentComment.range.end.line);
|
||||||
|
|
||||||
|
// Really we ought to subclass ParseTreeVisitor but this is fiddly in ES5 so
|
||||||
|
// it is easier to simply override the prototype's method on the instance
|
||||||
|
visitor.visitAny = function(tree) {
|
||||||
|
if (tree && tree.location && tree.location.start && currentComment) {
|
||||||
|
if (currentComment.range.end.offset < tree.location.start.offset) {
|
||||||
|
log.silly('tree: ' + tree.constructor.name + ' - ' + tree.location.start.line);
|
||||||
|
tree.commentBefore = currentComment;
|
||||||
|
currentComment.treeAfter = tree;
|
||||||
|
index++;
|
||||||
|
currentComment = comments[index];
|
||||||
|
if (currentComment) log.silly('comment: ' + currentComment.range.start.line + ' - ' + currentComment.range.end.line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ParseTreeVisitor.prototype.visitAny.call(this, tree);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Visit every node of the tree using our custom method
|
||||||
|
visitor.visit(tree);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,80 @@
|
||||||
|
var mockPackage = require('../mocks/mockPackage');
|
||||||
|
var Dgeni = require('dgeni');
|
||||||
|
|
||||||
|
describe('atParser service', function() {
|
||||||
|
|
||||||
|
var dgeni, injector, parser;
|
||||||
|
|
||||||
|
var fileContent =
|
||||||
|
'import {CONST} from "facade/lang";\n' +
|
||||||
|
'\n' +
|
||||||
|
'/**\n' +
|
||||||
|
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||||
|
'*\n' +
|
||||||
|
'* class AComponent {\n' +
|
||||||
|
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||||
|
'* }\n' +
|
||||||
|
'*\n' +
|
||||||
|
'*/\n' +
|
||||||
|
'export class Inject {\n' +
|
||||||
|
'token;\n' +
|
||||||
|
'@CONST()\n' +
|
||||||
|
'constructor(token) {\n' +
|
||||||
|
'this.token = token;\n' +
|
||||||
|
'}\n' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
dgeni = new Dgeni([mockPackage()]);
|
||||||
|
injector = dgeni.configureInjector();
|
||||||
|
parser = injector.get('atParser');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract the comments from the file', function() {
|
||||||
|
var result = parser.parseModule({
|
||||||
|
content: fileContent,
|
||||||
|
relativePath: 'di/src/annotations.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.comments[0].range.toString()).toEqual(
|
||||||
|
'/**\n' +
|
||||||
|
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||||
|
'*\n' +
|
||||||
|
'* class AComponent {\n' +
|
||||||
|
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||||
|
'* }\n' +
|
||||||
|
'*\n' +
|
||||||
|
'*/'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract a module AST from the file', function() {
|
||||||
|
var result = parser.parseModule({
|
||||||
|
content: fileContent,
|
||||||
|
relativePath: 'di/src/annotations.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.moduleTree.moduleName).toEqual('di/annotations');
|
||||||
|
expect(result.moduleTree.scriptItemList[0].type).toEqual('IMPORT_DECLARATION');
|
||||||
|
|
||||||
|
expect(result.moduleTree.scriptItemList[1].type).toEqual('EXPORT_DECLARATION');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should attach comments to their following AST', function() {
|
||||||
|
var result = parser.parseModule({
|
||||||
|
content: fileContent,
|
||||||
|
relativePath: 'di/src/annotations.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.moduleTree.scriptItemList[1].commentBefore.range.toString()).toEqual(
|
||||||
|
'/**\n' +
|
||||||
|
'* A parameter annotation that creates a synchronous eager dependency.\n' +
|
||||||
|
'*\n' +
|
||||||
|
'* class AComponent {\n' +
|
||||||
|
'* constructor(@Inject("aServiceToken") aService) {}\n' +
|
||||||
|
'* }\n' +
|
||||||
|
'*\n' +
|
||||||
|
'*/'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
var LEADING_STAR = /^[^\S\r\n]*\*[^\S\n\r]?/gm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extact comment info from a comment object
|
||||||
|
* @param {Object} comment object to process
|
||||||
|
* @return { {startingLine, endingLine, content, codeTree}= } a comment info object
|
||||||
|
* or undefined if the comment is not a jsdoc style comment
|
||||||
|
*/
|
||||||
|
module.exports = function getJSDocComment() {
|
||||||
|
return function(comment) {
|
||||||
|
|
||||||
|
var commentInfo;
|
||||||
|
|
||||||
|
// we need to check for `/**` at the start of the comment to find all the jsdoc style comments
|
||||||
|
comment.range.toString().replace(/^\/\*\*([\w\W]*)\*\/$/g, function(match, commentBody) {
|
||||||
|
commentBody = commentBody.replace(LEADING_STAR, '').trim();
|
||||||
|
|
||||||
|
commentInfo = {
|
||||||
|
startingLine: comment.range.start.line,
|
||||||
|
endingLine: comment.range.end.line,
|
||||||
|
content: commentBody,
|
||||||
|
codeTree: comment.treeAfter
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return commentInfo;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,67 @@
|
||||||
|
var mockPackage = require('../mocks/mockPackage');
|
||||||
|
var Dgeni = require('dgeni');
|
||||||
|
|
||||||
|
describe('getJSDocComment service', function() {
|
||||||
|
|
||||||
|
var dgeni, injector, getJSDocComment;
|
||||||
|
|
||||||
|
function createComment(commentString, start, end, codeTree) {
|
||||||
|
return {
|
||||||
|
range: {
|
||||||
|
toString: function() { return commentString; },
|
||||||
|
start: { line: start },
|
||||||
|
end: { line: end },
|
||||||
|
},
|
||||||
|
treeAfter: codeTree
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
dgeni = new Dgeni([mockPackage()]);
|
||||||
|
injector = dgeni.configureInjector();
|
||||||
|
getJSDocComment = injector.get('getJSDocComment');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only return an object if the comment starts with /** and ends with */', function() {
|
||||||
|
var result = getJSDocComment(createComment('/** this is a jsdoc comment */'));
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
|
||||||
|
result = getJSDocComment(createComment('/* this is a normal comment */'));
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
result = getJSDocComment(createComment('this is not a valid comment */'));
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
result = getJSDocComment(createComment('nor is this'));
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
result = getJSDocComment(createComment('/* or even this'));
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
result = getJSDocComment(createComment('/** and this'));
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should return a result that contains info about the comment', function() {
|
||||||
|
var codeTree = {};
|
||||||
|
var result = getJSDocComment(createComment('/** this is a comment */', 10, 20, codeTree));
|
||||||
|
expect(result.startingLine).toEqual(10);
|
||||||
|
expect(result.endingLine).toEqual(20);
|
||||||
|
expect(result.codeTree).toBe(codeTree);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should strip off leading stars from each line', function() {
|
||||||
|
var result = getJSDocComment(createComment(
|
||||||
|
'/** this is a jsdoc comment */\n' +
|
||||||
|
' *\n' +
|
||||||
|
' * some content\n' +
|
||||||
|
' */'
|
||||||
|
));
|
||||||
|
expect(result.content).toEqual(
|
||||||
|
'this is a jsdoc comment */\n' +
|
||||||
|
'\n' +
|
||||||
|
'some content'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends 'layout/base.template.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1>{$ doc.name $} <span class="type">class</span></h1>
|
||||||
|
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a></p>
|
||||||
|
<p>{$ doc.description | marked $}</p>
|
||||||
|
|
||||||
|
<h2>Members</h2>
|
||||||
|
{% for member in doc.members %}
|
||||||
|
<h3>{$ member.name $}</h3>
|
||||||
|
<p>{$ member.description | marked $}</p>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends 'layout/base.template.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1>{$ doc.id $}</h1>
|
||||||
|
<h2>({$ doc.docType $})</h2>
|
||||||
|
<div>
|
||||||
|
{$ doc.description | marked $}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
angular.module('{$ doc.moduleName $}', [])
|
||||||
|
|
||||||
|
.value('{$ doc.serviceName $}', {$ doc.value | json $});
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends 'layout/base.template.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{$ doc.description | marked $}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1 @@
|
||||||
|
{% block body %}{% endblock %}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends 'layout/base.template.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<h1 class="id">{$ doc.id $} <span class="type">module</span></h1>
|
||||||
|
|
||||||
|
<p>{$ doc.description | marked $}</p>
|
||||||
|
|
||||||
|
{% if doc.exports.length %}
|
||||||
|
<h2>Exports</h2>
|
||||||
|
<ul>
|
||||||
|
{%- for exportDoc in doc.exports %}
|
||||||
|
<li><a href="/{$ exportDoc.path $}">{$ exportDoc.name $} {$ exportDoc.docType $}</a></li>
|
||||||
|
{%- endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
55
gulpfile.js
55
gulpfile.js
|
@ -399,3 +399,58 @@ gulp.task('build', function(done) {
|
||||||
gulp.task('analyze', function(done) {
|
gulp.task('analyze', function(done) {
|
||||||
runSequence('analyze/analyzer.dart');
|
runSequence('analyze/analyzer.dart');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// --------------
|
||||||
|
// doc generation
|
||||||
|
var Dgeni = require('dgeni');
|
||||||
|
gulp.task('docs/dgeni', function() {
|
||||||
|
try {
|
||||||
|
var dgeni = new Dgeni([require('./docs/dgeni-package')]);
|
||||||
|
return dgeni.generate();
|
||||||
|
} catch(x) {
|
||||||
|
console.log(x.stack);
|
||||||
|
throw x;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var bower = require('bower');
|
||||||
|
gulp.task('docs/bower', function() {
|
||||||
|
var bowerTask = bower.commands.install(undefined, undefined, { cwd: 'docs' });
|
||||||
|
bowerTask.on('log', function (result) {
|
||||||
|
console.log('bower:', result.id, result.data.endpoint.name);
|
||||||
|
});
|
||||||
|
bowerTask.on('error', function(error) {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
return bowerTask;
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('docs/assets', ['docs/bower'], function() {
|
||||||
|
return gulp.src('docs/bower_components/**/*')
|
||||||
|
.pipe(gulp.dest('build/docs/lib'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('docs/app', function() {
|
||||||
|
return gulp.src('docs/app/**/*')
|
||||||
|
.pipe(gulp.dest('build/docs'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('docs', ['docs/assets', 'docs/app', 'docs/dgeni']);
|
||||||
|
gulp.task('docs-watch', function() {
|
||||||
|
return gulp.watch('docs/app/**/*', ['docs-app']);
|
||||||
|
});
|
||||||
|
|
||||||
|
var jasmine = require('gulp-jasmine');
|
||||||
|
gulp.task('docs/test', function () {
|
||||||
|
return gulp.src('docs/**/*.spec.js')
|
||||||
|
.pipe(jasmine());
|
||||||
|
});
|
||||||
|
|
||||||
|
var webserver = require('gulp-webserver');
|
||||||
|
gulp.task('docs/serve', function() {
|
||||||
|
gulp.src('build/docs/')
|
||||||
|
.pipe(webserver({
|
||||||
|
fallback: 'index.html'
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
|
@ -28,11 +28,18 @@
|
||||||
"which": "~1"
|
"which": "~1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"bower": "^1.3.12",
|
||||||
|
"canonical-path": "0.0.2",
|
||||||
|
"dgeni": "^0.4.1",
|
||||||
|
"dgeni-packages": "^0.10.7",
|
||||||
"gulp": "^3.8.8",
|
"gulp": "^3.8.8",
|
||||||
"gulp-changed": "^1.0.0",
|
"gulp-changed": "^1.0.0",
|
||||||
"gulp-ejs": "^0.3.1",
|
"gulp-ejs": "^0.3.1",
|
||||||
|
"gulp-jasmine": "^1.0.1",
|
||||||
"gulp-load-plugins": "^0.7.1",
|
"gulp-load-plugins": "^0.7.1",
|
||||||
"gulp-rename": "^1.2.0",
|
"gulp-rename": "^1.2.0",
|
||||||
"gulp-shell": "^0.2.10"
|
"gulp-shell": "^0.2.10",
|
||||||
|
"gulp-webserver": "^0.8.7",
|
||||||
|
"lodash": "^2.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue