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

Commit 9c65189

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 08d051d commit 9c65189

File tree

19 files changed

+735
-28
lines changed

19 files changed

+735
-28
lines changed

.travis.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ env:
1515
- TASK=lint
1616
- TASK="run-e2e-tests --fast" SCRIPT=examples-install.sh
1717
- TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh
18-
- TASK=harp-compile SCRIPT=deploy-install.sh
19-
- TASK=harp-compile SCRIPT=deploy-install-preview.sh
18+
- TASK=check SCRIPT=deploy-install.sh
19+
- TASK=check SCRIPT=deploy-install-preview.sh
2020
matrix:
2121
fast_finish: true
2222
allow_failures:
2323
- env: "TASK=\"run-e2e-tests --fast\" SCRIPT=examples-install-preview.sh"
24-
- env: "TASK=harp-compile SCRIPT=deploy-install-preview.sh"
24+
- env: "TASK=check SCRIPT=deploy-install-preview.sh"
2525
before_install:
2626
- npm install -g gulp --no-optional
2727
install:

gulpfile.js

+136-12
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 ?
@@ -528,7 +545,7 @@ gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunker
528545
// Stop zipping examples Feb 28, 2016
529546
//gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']);
530547

531-
gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs', 'build-dart-cheatsheet']);
548+
gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs', 'build-dart-api-docs']);
532549

533550
gulp.task('build-devguide-docs', ['_shred-devguide-examples', '_shred-devguide-shared-jade'], function() {
534551
return buildShredMaps(true);
@@ -542,12 +559,40 @@ gulp.task('build-js-api-docs', ['_shred-api-examples'], function() {
542559
return buildApiDocs('js');
543560
});
544561

562+
gulp.task('build-dart-api-docs', ['_shred-api-examples', 'dartdoc'], function() {
563+
// TODO(chalin): also build build-dart-cheatsheet
564+
return buildApiDocsForDart();
565+
});
566+
545567
gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() {
546568
return plunkerBuilder.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log });
547569
});
548570

549571
gulp.task('build-dart-cheatsheet', [], function() {
550-
return buildApiDocs('dart');
572+
gutil.log('build-dart-cheatsheet - NOT IMPLEMENTED YET');
573+
// return buildApiDocsForDart();
574+
});
575+
576+
gulp.task('dartdoc', ['pub upgrade'], function() {
577+
const ngRepoPath = ngPathFor('dart');
578+
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'doc'))) {
579+
gutil.log('Skipping dartdoc: --fast flag enabled and "doc" dir exists');
580+
return true;
581+
}
582+
checkAngularProjectPath(ngRepoPath);
583+
const dartdoc = spawnExt('dartdoc', ['--output', 'doc/api', '--add-crossdart'], { cwd: ngRepoPath});
584+
return dartdoc.promise;
585+
});
586+
587+
gulp.task('pub upgrade', [], function() {
588+
const ngRepoPath = ngPathFor('dart');
589+
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'packages'))) {
590+
gutil.log('Skipping pub upgrade: --fast flag enabled and "packages" dir exists');
591+
return true;
592+
}
593+
checkAngularProjectPath(ngRepoPath);
594+
const pubUpgrade = spawnExt('pub', ['upgrade'], { cwd: ngRepoPath});
595+
return pubUpgrade.promise;
551596
});
552597

553598
gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
@@ -596,10 +641,35 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
596641
});
597642
});
598643

599-
gulp.task('harp-compile', ['build-docs'], function() {
644+
gulp.task('harp-compile', [], function() {
645+
return harpCompile()
646+
});
647+
648+
gulp.task('serve', [], function() {
649+
// Harp will serve files from workspace.
650+
const cmd = 'npm run harp -- server .';
651+
gutil.log('Launching harp server (over project files)');
652+
gutil.log(` > ${cmd}`);
653+
gutil.log('Note: issuing this command directly from the command line will show harp comiple warnings.');
654+
return execPromise(cmd);
655+
});
656+
657+
gulp.task('serve-www', [], function() {
658+
// Serve generated site.
659+
return execPromise('npm run live-server ./www');
660+
});
661+
662+
gulp.task('check', ['build-docs'], function() {
600663
return harpCompile();
601664
});
602665

666+
gulp.task('check-serve', ['build-docs'], function() {
667+
return harpCompile().then(function() {
668+
gutil.log('Launching live-server over ./www');
669+
return execPromise('npm run live-server ./www');
670+
});
671+
});
672+
603673
gulp.task('check-deploy', ['build-docs'], function() {
604674
return harpCompile().then(function() {
605675
gutil.log('compile ok');
@@ -693,8 +763,15 @@ gulp.task('_shred-clean-devguide', function(cb) {
693763
});
694764

695765
gulp.task('_shred-api-examples', ['_shred-clean-api'], function() {
696-
checkAngularProjectPath();
697-
return docShredder.shred(_apiShredOptions);
766+
const promises = [];
767+
gutil.log('Shredding API examples for languages: ' + langs.join(', '));
768+
langs.forEach((lang) => {
769+
if (lang === 'js') return; // JS is handled via TS.
770+
checkAngularProjectPath(ngPathFor(lang));
771+
const options = lang == 'dart' ? _apiShredOptionsForDart : _apiShredOptions;
772+
promises.push(docShredder.shred(options));
773+
});
774+
return Q.all(promises);
698775
});
699776

700777
gulp.task('_shred-clean-api', function(cb) {
@@ -1087,8 +1164,8 @@ function buildApiDocs(targetLanguage) {
10871164
var dgeni = new Dgeni([package]);
10881165
return dgeni.generate();
10891166
} catch(err) {
1090-
gutil.log(err);
1091-
gutil.log(err.stack);
1167+
console.error(err);
1168+
console.error(err.stack);
10921169
throw err;
10931170
}
10941171

@@ -1099,6 +1176,48 @@ function buildApiDocs(targetLanguage) {
10991176
}
11001177
}
11011178

1179+
1180+
function buildApiDocsForDart() {
1181+
const apiDir = 'api';
1182+
const vers = 'latest';
1183+
const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH);
1184+
const log = dab.log;
1185+
1186+
log.level = _dgeniLogLevel;
1187+
const dabInfo = dab.dartPkgConfigInfo;
1188+
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, apiDir);
1189+
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'doc', apiDir);
1190+
// Exclude API entries for developer/internal libraries. Also exclude entries for
1191+
// the top-level catch all "angular2" library (otherwise every entry appears twice).
1192+
dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|\.testing|_|codegen|^angular2$/);
1193+
1194+
try {
1195+
checkAngularProjectPath('dart');
1196+
var destPath = dabInfo.ngIoDartApiDocPath;
1197+
var sourceDirs = fs.readdirSync(dabInfo.ngDartDocPath)
1198+
.filter((name) => !name.match(/^index/))
1199+
.map((name) => path.join(dabInfo.ngDartDocPath, name));
1200+
log.info(`Building Dart API pages for ${sourceDirs.length} libraries`);
1201+
1202+
return copyFiles(sourceDirs, [destPath]).then(() => {
1203+
log.debug('Finished copying', sourceDirs.length, 'directories from', dabInfo.ngDartDocPath, 'to', destPath);
1204+
1205+
const apiEntries = dab.loadApiDataAndSaveToApiListFile();
1206+
const tmpDocsPath = path.resolve(path.join(process.env.HOME, 'tmp/docs.json'));
1207+
if (argv.dumpDocsJson) fs.writeFileSync(tmpDocsPath, JSON.stringify(apiEntries, null, 2));
1208+
dab.createApiDataAndJadeFiles(apiEntries);
1209+
1210+
}).catch((err) => {
1211+
console.log(err);
1212+
});
1213+
1214+
} catch(err) {
1215+
console.error(err);
1216+
console.error(err.stack);
1217+
throw err;
1218+
}
1219+
}
1220+
11021221
function buildShredMaps(shouldWrite) {
11031222
var options = {
11041223
devguideExamplesDir: _devguideShredOptions.examplesDir,
@@ -1270,8 +1389,13 @@ function execCommands(cmds, options, cb) {
12701389
});
12711390
}
12721391

1273-
function checkAngularProjectPath() {
1274-
if (!fs.existsSync(ANGULAR_PROJECT_PATH)) {
1275-
throw new Error('API related tasks require the angular2 repo to be at ' + path.resolve(ANGULAR_PROJECT_PATH));
1392+
function ngPathFor(lang) {
1393+
return ANGULAR_PROJECT_PATH + (lang === 'dart' ? '-dart' : '');
1394+
}
1395+
1396+
function checkAngularProjectPath(lang) {
1397+
var ngPath = path.resolve(ngPathFor(lang || 'ts'));
1398+
if (!fs.existsSync(ngPath)) {
1399+
throw new Error('API related tasks require the angular2 repo to be at ' + ngPath);
12761400
}
12771401
}

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 = [];

0 commit comments

Comments
 (0)