Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 31f8840

Browse files
committed
docs(api/dart): add support for generation and display
Fixes #1880. Supersedes #1593. ### Task breakdown **Package dependencies:** - [ ] [**BLOCKING**] Update to new [harp](https://github.com/sintaxi/harp) package which depends on latest [terraform](https://github.com/sintaxi/terraform) release. This is needed so that dots (`.`) can be supported in site URIs; something that is essential for Dart given that library names contain dots. See sintaxi/harp#526 (/cc @sintaxi).<br>Blocked awaiting the new release. **Gulp tasks / build scripts:** - [x] New tasks to run `pub` and `dartdoc` over (existing) `angular-dart` repo, peer to ng.io repo. - [x] `build-api-docs` should also do Dart API docs. - [x] Shredder should run over Dart sources and generate example fragments. - [x] Create script to patch local `terraform` package, while we await new harp release, as a means of **unblocking**. **Generator package:** - [x] New `tools/dart-api-builder`; stand alone tool re-using part of the basis of a Dart API dgeni package. **Harp/Jade site infrastructure:** - [x] New `public/docs/_layout-dart-api.jade`. - [x] Updates to other Harp/Jade template files. **API List directive:** - [x] Create new or update existing `<api-list>` directive: - [x] Display only filter categories that are relevant to Dart. **Site data and Jade file generation:** - [x] Main API page - [x] Generate `api-list.json`. - [x] Add warning that API is preliminary and that code might still appear as TS. - [x] Generate data (`_data.json`) and Jade files for - [x] For each library (i.e., top-level folder). - [x] `_data.json` - [x] Library "index" Jade page. - [x] Each member Jade page. - [x] For library subfolders (e.g., containing class member details). - [x] `_data.json` - [x] Folder "index" page (it actually has the same name as the container -- e.g., class name). - [x] Each member page. - [x] API Jade file page contents: - [x] Attributes like name and type - [x] Breadcrumbs - [ ] Page header section tabs. - [x] Core page content excerpt from dartdoc-generated page - [x] Exclude the "left" nav menu (full ng2 package content list) from the core page content. - [x] `{@example ...}` tags are replaced by their designated example code fragments. - [x] Filter generated API pages (configurable via regExp in build file): exclude entries from - [x] Non-public, developer/internal libraries. - [x] Top-level catch all `angular2` library -- otherwise every entry appears twice. - [x] Support developer & production modes for data (JSON) file generation - [x] Developer mode (pretty-printed). - [x] [NOT implemented] ~~Production mode (compact).~~ Note about the API subsite design: - I had to resort to using Jade extends/includes; hence disabling Harp _layout/partials. cc: @naomiblack @kwalrath @ferhatb @keertip
1 parent aacab56 commit 31f8840

File tree

18 files changed

+735
-24
lines changed

18 files changed

+735
-24
lines changed

gulpfile.js

+139-11
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ var tslint = require('gulp-tslint');
3030
// 2. Think about using spawn instead of exec in case of long error messages.
3131

3232
var TOOLS_PATH = './tools';
33+
var ANGULAR_IO_PROJECT_PATH = path.resolve('.');
3334
var ANGULAR_PROJECT_PATH = '../angular';
3435
var PUBLIC_PATH = './public';
3536
var TEMP_PATH = './_temp';
@@ -63,12 +64,21 @@ var _devguideShredJadeOptions = {
6364
};
6465

6566
var _apiShredOptions = {
67+
lang: 'ts',
6668
examplesDir: path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/examples'),
6769
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
6870
zipDir: path.join(RESOURCES_PATH, 'zips/api'),
6971
logLevel: _dgeniLogLevel
7072
};
7173

74+
var _apiShredOptionsForDart = {
75+
lang: 'dart',
76+
examplesDir: path.resolve(ngPathFor('dart'), 'examples'),
77+
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
78+
zipDir: path.join(RESOURCES_PATH, 'zips/api'),
79+
logLevel: _dgeniLogLevel
80+
};
81+
7282
var _excludePatterns = ['**/node_modules/**', '**/typings/**', '**/packages/**'];
7383

7484
var _excludeMatchers = _excludePatterns.map(function(excludePattern){
@@ -96,6 +106,14 @@ var _exampleProtractorBoilerplateFiles = [
96106

97107
var _exampleConfigFilename = 'example-config.json';
98108

109+
var lang, langs;
110+
function configLangs(langOption) {
111+
lang = (langOption || 'all').toLowerCase();
112+
if (lang === 'all') { lang = '(ts|js|dart)'; }
113+
langs = lang.match(/\w+/g); // the languages in `lang` as an array
114+
}
115+
configLangs(argv.lang);
116+
99117
function isDartPath(path) {
100118
// Testing via indexOf() for now. If we need to match only paths with folders
101119
// named 'dart' vs 'dart*' then try: path.match('/dart(/|$)') != null;
@@ -131,6 +149,7 @@ gulp.task('run-e2e-tests', runE2e);
131149
* all means (ts|js|dart)
132150
*/
133151
function runE2e() {
152+
if (!argv.lang) configLangs('ts|js'); // Exclude dart by default
134153
var promise;
135154
if (argv.fast) {
136155
// fast; skip all setup
@@ -183,8 +202,6 @@ function runE2e() {
183202
// each app/spec collection sequentially.
184203
function findAndRunE2eTests(filter, outputFile) {
185204
// create an output file with header.
186-
var lang = (argv.lang || '(ts|js)').toLowerCase();
187-
if (lang === 'all') { lang = '(ts|js|dart)'; }
188205
var startTime = new Date().getTime();
189206
var header = `Doc Sample Protractor Results for ${lang} on ${new Date().toLocaleString()}\n`;
190207
header += argv.fast ?
@@ -496,7 +513,7 @@ gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunker
496513
// Stop zipping examples Feb 28, 2016
497514
//gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']);
498515

499-
gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs', 'build-dart-cheatsheet']);
516+
gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs', 'build-dart-api-docs']);
500517

501518
gulp.task('build-devguide-docs', ['_shred-devguide-examples', '_shred-devguide-shared-jade'], function() {
502519
return buildShredMaps(true);
@@ -510,12 +527,40 @@ gulp.task('build-js-api-docs', ['_shred-api-examples'], function() {
510527
return buildApiDocs('js');
511528
});
512529

530+
gulp.task('build-dart-api-docs', ['_shred-api-examples', 'dartdoc'], function() {
531+
// TODO(chalin): also build build-dart-cheatsheet
532+
return buildApiDocsForDart();
533+
});
534+
513535
gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() {
514536
return plunkerBuilder.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log });
515537
});
516538

517539
gulp.task('build-dart-cheatsheet', [], function() {
518-
return buildApiDocs('dart');
540+
gutil.log('build-dart-cheatsheet - NOT IMPLEMENTED YET');
541+
// return buildApiDocsForDart();
542+
});
543+
544+
gulp.task('dartdoc', ['pub upgrade'], function() {
545+
const ngRepoPath = ngPathFor('dart');
546+
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'doc'))) {
547+
gutil.log('Skipping dartdoc: --fast flag enabled and "doc" dir exists');
548+
return true;
549+
}
550+
checkAngularProjectPath(ngRepoPath);
551+
const dartdoc = spawnExt('dartdoc', ['--output', 'doc/api', '--add-crossdart'], { cwd: ngRepoPath});
552+
return dartdoc.promise;
553+
});
554+
555+
gulp.task('pub upgrade', [], function() {
556+
const ngRepoPath = ngPathFor('dart');
557+
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'packages'))) {
558+
gutil.log('Skipping pub upgrade: --fast flag enabled and "packages" dir exists');
559+
return true;
560+
}
561+
checkAngularProjectPath(ngRepoPath);
562+
const pubUpgrade = spawnExt('pub', ['upgrade'], { cwd: ngRepoPath});
563+
return pubUpgrade.promise;
519564
});
520565

521566
gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
@@ -564,6 +609,35 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
564609
});
565610
});
566611

612+
gulp.task('harp-compile', [], function() {
613+
return harpCompile()
614+
});
615+
616+
gulp.task('serve', [], function() {
617+
// Harp will serve files from workspace.
618+
const cmd = 'npm run harp -- server .';
619+
gutil.log('Launching harp server (over project files)');
620+
gutil.log(` > ${cmd}`);
621+
gutil.log('Note: issuing this command directly from the command line will show harp comiple warnings.');
622+
return execPromise(cmd);
623+
});
624+
625+
gulp.task('serve-www', [], function() {
626+
// Serve generated site.
627+
return execPromise('npm run live-server ./www');
628+
});
629+
630+
gulp.task('check', ['build-docs'], function() {
631+
return harpCompile();
632+
});
633+
634+
gulp.task('check-serve', ['build-docs'], function() {
635+
return harpCompile().then(function() {
636+
gutil.log('Launching live-server over ./www');
637+
return execPromise('npm run live-server ./www');
638+
});
639+
});
640+
567641
gulp.task('check-deploy', ['build-docs'], function() {
568642
return harpCompile().then(function() {
569643
gutil.log('compile ok');
@@ -661,8 +735,15 @@ gulp.task('_shred-clean-devguide', function(cb) {
661735
});
662736

663737
gulp.task('_shred-api-examples', ['_shred-clean-api'], function() {
664-
checkAngularProjectPath();
665-
return docShredder.shred(_apiShredOptions);
738+
const promises = [];
739+
gutil.log('Shredding API examples for languages: ' + langs.join(', '));
740+
langs.forEach((lang) => {
741+
if (lang === 'js') return; // JS is handled via TS.
742+
checkAngularProjectPath(ngPathFor(lang));
743+
const options = lang == 'dart' ? _apiShredOptionsForDart : _apiShredOptions;
744+
promises.push(docShredder.shred(options));
745+
});
746+
return Q.all(promises);
666747
});
667748

668749
gulp.task('_shred-clean-api', function(cb) {
@@ -1053,8 +1134,8 @@ function buildApiDocs(targetLanguage) {
10531134
var dgeni = new Dgeni([package]);
10541135
return dgeni.generate();
10551136
} catch(err) {
1056-
gutil.log(err);
1057-
gutil.log(err.stack);
1137+
console.error(err);
1138+
console.error(err.stack);
10581139
throw err;
10591140
}
10601141

@@ -1065,6 +1146,48 @@ function buildApiDocs(targetLanguage) {
10651146
}
10661147
}
10671148

1149+
1150+
function buildApiDocsForDart() {
1151+
const apiDir = 'api';
1152+
const vers = 'latest';
1153+
const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH);
1154+
const log = dab.log;
1155+
1156+
log.level = _dgeniLogLevel;
1157+
const dabInfo = dab.dartPkgConfigInfo;
1158+
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, apiDir);
1159+
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'doc', apiDir);
1160+
// Exclude API entries for developer/internal libraries. Also exclude entries for
1161+
// the top-level catch all "angular2" library (otherwise every entry appears twice).
1162+
dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|\.testing|_|codegen|^angular2$/);
1163+
1164+
try {
1165+
checkAngularProjectPath('dart');
1166+
var destPath = dabInfo.ngIoDartApiDocPath;
1167+
var sourceDirs = fs.readdirSync(dabInfo.ngDartDocPath)
1168+
.filter((name) => !name.match(/^index/))
1169+
.map((name) => path.join(dabInfo.ngDartDocPath, name));
1170+
log.info(`Building Dart API pages for ${sourceDirs.length} libraries`);
1171+
1172+
return copyFiles(sourceDirs, [destPath]).then(() => {
1173+
log.debug('Finished copying', sourceDirs.length, 'directories from', dabInfo.ngDartDocPath, 'to', destPath);
1174+
1175+
const apiEntries = dab.loadApiDataAndSaveToApiListFile();
1176+
const tmpDocsPath = path.resolve(path.join(process.env.HOME, 'tmp/docs.json'));
1177+
if (argv.dumpDocsJson) fs.writeFileSync(tmpDocsPath, JSON.stringify(apiEntries, null, 2));
1178+
dab.createApiDataAndJadeFiles(apiEntries);
1179+
1180+
}).catch((err) => {
1181+
console.log(err);
1182+
});
1183+
1184+
} catch(err) {
1185+
console.error(err);
1186+
console.error(err.stack);
1187+
throw err;
1188+
}
1189+
}
1190+
10681191
function buildShredMaps(shouldWrite) {
10691192
var options = {
10701193
devguideExamplesDir: _devguideShredOptions.examplesDir,
@@ -1236,8 +1359,13 @@ function execCommands(cmds, options, cb) {
12361359
});
12371360
}
12381361

1239-
function checkAngularProjectPath() {
1240-
if (!fs.existsSync(ANGULAR_PROJECT_PATH)) {
1241-
throw new Error('API related tasks require the angular2 repo to be at ' + path.resolve(ANGULAR_PROJECT_PATH));
1362+
function ngPathFor(lang) {
1363+
return ANGULAR_PROJECT_PATH + (lang === 'dart' ? '-dart' : '');
1364+
}
1365+
1366+
function checkAngularProjectPath(lang) {
1367+
var ngPath = path.resolve(ngPathFor(lang || 'ts'));
1368+
if (!fs.existsSync(ngPath)) {
1369+
throw new Error('API related tasks require the angular2 repo to be at ' + ngPath);
12421370
}
12431371
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"broken-link-checker": "0.7.1",
3131
"browser-sync": "^2.9.3",
3232
"canonical-path": "0.0.2",
33+
"cheerio": "^0.20.0",
3334
"cross-spawn": "^4.0.0",
3435
"codelyzer": "0.0.22",
3536
"del": "^2.2.0",

public/_includes/_hero.jade

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
// Refer to jade.template.html and addJadeDataDocsProcessor to figure out where the context of this jade file originates
1+
// template: public/_includes/_hero
2+
//- Refer to jade.template.html and addJadeDataDocsProcessor to figure out where the context of this jade file originates
23
- var textFormat = '';
34
- var headerTitle = title + (typeof varType !== 'undefined' ? (': ' + varType) : '');
45
- var capitalize = function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); }
56
- var useBadges = docType || stability;
6-
7-
// renamer :: String -> String
8-
// Renames `Let` and `Var` into `Const`
7+
//- renamer :: String -> String
8+
//- Renames `Let` and `Var` into `Const`
99
- var renamer = function renamer(docType) {
1010
- return (docType === 'Let' || docType === 'Var') ? 'Const' : docType
1111
- }
1212

1313
if current.path[4] && current.path[3] == 'api'
1414
- var textFormat = 'is-standard-case'
1515

16-
header(class="hero background-sky")
16+
header(class="hero background-sky", style=fixHeroCss ? "height:auto" : "")
1717
div(class="inner-header")
1818
h1(class="hero-title text-display-1 #{textFormat}") #{headerTitle}
1919
if useBadges
@@ -33,5 +33,7 @@ header(class="hero background-sky")
3333
if subtitle
3434
h2.hero-subtitle.text-subhead #{subtitle}
3535

36+
else if current.path[3] == 'api' && current.path[1] == 'dart'
37+
block breadcrumbs
3638
else if current.path[0] == "docs"
3739
!= partial("_version-dropdown")

public/docs/_layout-dart-api.jade

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//- WARNING: _layout.jade and _layout-dart-api.jade should match in terms of content
2+
//- except that one uses Harp partial/yield and the other uses Jade extends/include.
3+
doctype
4+
html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework")
5+
// template: public/docs/_layout-dart-api
6+
head
7+
include ../_includes/_head-include
8+
block head-extra
9+
10+
block var-def
11+
body(class="l-offset-nav l-offset-side-nav" ng-controller="AppCtrl as appCtrl")
12+
include ../_includes/_main-nav
13+
if current.path[2]
14+
include _includes/_side-nav
15+
include ../_includes/_hero
16+
include ../_includes/_banner
17+
18+
if current.path[3] == 'api'
19+
if current.path[4] == 'index'
20+
block main-content
21+
else
22+
article(class="l-content-small grid-fluid docs-content")
23+
block main-content
24+
else if current.path.indexOf('cheatsheet') > 0
25+
block main-content
26+
else
27+
if current.path[3] == 'index' || current.path[3] == 'styleguide'
28+
article(class="l-content-small grid-fluid docs-content")
29+
block main-content
30+
else
31+
article(class="l-content-small grid-fluid docs-content")
32+
div(class="c10")
33+
.showcase
34+
.showcase-content
35+
block main-content
36+
if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4]
37+
include ../_includes/_next-item
38+
39+
include ../_includes/_footer
40+
include ../_includes/_scripts-include

public/docs/_layout.jade

+5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
//- WARNING: _layout.jade and _layout-dart-api.jade should match in terms of content
2+
//- except that one uses Harp partial/yield and the other uses Jade extends/include.
13
doctype
24
html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework")
5+
// template: public/docs/_layout
36
head
47
!= partial("../_includes/_head-include")
8+
block head-extra
59

10+
//-
611
body(class="l-offset-nav l-offset-side-nav" ng-controller="AppCtrl as appCtrl")
712
!= partial("../_includes/_main-nav")
813
if current.path[2]
+11-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
.l-main-section
2-
h2 Beta
1+
:marked
2+
> **WARNING:** API documentation is preliminary and subject to change.
33

4-
p.
5-
The proposed Angular 2 API does not yet have Dart-specific documentation.
6-
However, because the Dart and JavaScript APIs are generated from the same source,
7-
you might find the JavaScript API docs helpful:
4+
> **Known issues:** Although this generated API reference displays Dart
5+
APIs, individual pages sometimes describe TypeScript APIs accompanied with
6+
TypeScript code. The angular.io issue tracker contains [all known
7+
issues][api-issues]; if you notice others, please [report
8+
them][new-issue]. Thanks!
89

9-
p.text-center
10-
<b><a href="/docs/js/latest/api/">Angular 2 API Preview (JavaScript)</a></b>
10+
[new-issue]: https://github.com/angular/angular.io/issues/new?labels=dart,api&title=%5BDart%5D%5BAPI%5D%20
11+
[api-issues]: https://github.com/angular/angular.io/issues?q=label%3Aapi+label%3Adart
12+
13+
api-list(src="api-list.json" lang="dart")

public/resources/js/directives/api-list.js

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ angularIO.directive('apiList', function () {
2626
controller: function($scope, $attrs, $http, $location) {
2727
var $ctrl = this;
2828

29+
var isForDart = $attrs.lang === 'dart';
30+
2931
$ctrl.apiTypes = [
3032
{ cssClass: 'stable', title: 'Stable', matches: ['stable']},
3133
{ cssClass: 'directive', title: 'Directive', matches: ['directive'] },
@@ -37,6 +39,9 @@ angularIO.directive('apiList', function () {
3739
{ cssClass: 'const', title: 'Const', matches: ['var', 'let', 'const'] }
3840
];
3941

42+
if (isForDart) $ctrl.apiTypes = $ctrl.apiTypes.filter((t) =>
43+
!t.cssClass.match(/^(stable|directive|decorator|interface|enum)$/));
44+
4045
$ctrl.apiFilter = getApiFilterFromLocation();
4146
$ctrl.apiType = getApiTypeFromLocation();
4247
$ctrl.groupedSections = [];

scripts/patch.sh

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
set -e -o pipefail
4+
5+
TARGET=node_modules/terraform/lib/helpers/raw.js
6+
7+
# Around line 282 change from/to:
8+
# var namespace = sourcePath.split(".")[0].split("/")
9+
# var namespace = sourcePath.split('.').slice(0, -1).join('.').split('/')
10+
11+
if [ -e "$TARGET" ]; then
12+
perl -i.bak -pe 's/^(\s+var namespace.*split\("."\))\[0\]/\1.slice(0, -1).join(".")/' "$TARGET"
13+
echo "Patched '$TARGET'."
14+
else
15+
echo "Nothing to patch. Can't find file '$TARGET'."
16+
exit 1;
17+
fi

0 commit comments

Comments
 (0)