commit 17c7e154672dbf5feeeb971ed3b594d318703748 Author: Filipe Silva <filipematossilva@gmail.com> Date: Mon Nov 14 23:11:37 2016 +0000 chore: update to 2.2.0 (#2797) commit 1e5facfb980b85313d51559b3272950f662ce20c Merge: 5c4cc9a db0fac9 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 12:44:51 2016 -0800 Merge pull request #2799 from IdeaBlade/docs-changelog-2.2.0 chore(changelog): update docs changelog for Ng v.2.2.0 commit 5c4cc9a3c8b2718b71ab7c3d1b5dd02bfdd5f1fc Merge: 43457e9 1afe5dc Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 12:43:09 2016 -0800 docs(router): Updated usage of observables in router tutorial and developer guide (#2696) Moved route configuration into separate variable for consistency Added async pipe to handle subscriptions for list items commit 43457e9765c63b3889ab449959fe295327390315 Merge: a423a5a 2649647 Author: Jesús Rodríguez <Foxandxss@gmail.com> Date: Mon Nov 14 21:38:49 2016 +0100 chore: add upgrade/static to API reference (#2755) commit 1afe5dc97d457e045adb6c0e03d27023aa97eea5 Author: Brandon Roberts <robertsbt@gmail.com> Date: Sat Oct 29 16:08:54 2016 -0500 docs(router): Updated usage of observables in router tutorial and developer guide Moved route configuration into separate variable for consistency Added async pipe to handle subscriptions for list items commit db0fac94c980c99d9575a90d4b6bb15f572f9161 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 10:48:09 2016 -0800 chore(changelog): update docs changelog for Ng v.2.2.0 commit a423a5abc704280794b6dea69cf1c9e76bbc9da1 Author: ikilled <ikilled@users.noreply.github.com> Date: Mon Nov 14 18:39:46 2016 +0000 clicking on Books & Training sends user to Education (#2701) When user clicks in Books & Training item in footer the website should take them to Education section (anchor) in the middle of the page, not to the top where Development section is. commit d63b1ccea36f4cf52333c846184b8e6876284a0a Merge: f627706 8508140 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 10:35:48 2016 -0800 docs(router): fixed verbiage about router-outlet (#2746) commit f627706779c418ca8357aacd52aba5b5b7d05cb0 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 10:26:13 2016 -0800 docs(cookbook-aot-compiler): improve Ahead-of-Time compilation cookbook (#2798) closes #2790 commit 75464d585cac944e3cffb4401663e4c1185b7cb5 Merge: 78e2584 02f5559 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 09:34:36 2016 -0800 Merge pull request #2794 from IdeaBlade/chalin-guide-misc-fix-1113 docs: guide/index misc Jade fixes commit 78e25840b229b0fe345feacf786f34e62b2cb963 Merge: 182493f 85062c4 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 09:33:55 2016 -0800 Merge pull request #2795 from IdeaBlade/chalin-util-js-getExampleName-1114 chore(util.js): getExampleName - support optional .html suffix commit 182493f8779fa37422dd942813fc5681dbdac55f Merge: 9e9666b 53f5538 Author: Ward Bell <wardbell@hotmail.com> Date: Mon Nov 14 09:28:40 2016 -0800 feat(cb-ts-to-js): add es6 examples (#2606) * feat(cb-ts-to-js): add es6 examples update docshredder to shred .es6 optimized focus gulp task convert imports and metadate sections add DI section add host and query metadata section add intro fix capitalization and grammar * docs(ts-to-js): ward's edits (incomplete) * docs(ts-to-js): add separate template files for some components * docs(cb-ts-to-js): refactor sample code commit 53f5538859c4d243552d288872e8c8fc8156f446 Author: Ward Bell <wardbell@hotmail.com> Date: Sun Nov 13 14:09:28 2016 -0800 docs(cb-ts-to-js): refactor sample code commit 9e9666b2cc3ce57cac172894e935f0c6b9f7d6f4 Author: Patrice Chalin <chalin@users.noreply.github.com> Date: Mon Nov 14 08:34:10 2016 -0800 docs(template-syntax/dart): updates to match TS (#2751) * docs(template-syntax): refresh _cache * docs(template-syntax/dart): updates to match TS - Propagates TS-side changes: - update #2639 - new two-way binding section, and - fix #2687 - invalid attr syntax - Fixes - #1898 - currency symbols - #2748 - Dart template-syntax e2e is failing - #2749 - deprecated `[className]` * updated _cache file following Kathy's post-review edits * Post Ward's review w/ cache updated - Keep `my-` and `my` prefixes on selectors (for components and directives, respectively). - Drop `my-` from file names. - Drop `My` as component class prefix. commit 5dcffd69dc09b48d99af4acd0dd06b029416e103 Author: Patrice Chalin <pchalin@gmail.com> Date: Sun Nov 13 19:37:13 2016 -0800 docs: dart glossary - fix misnamed Jade block commit 6680acc513a0178bb522f5bc99d66f366542d33c Merge: 14db838 3b03573 Author: Kathy Walrath <kathyw@google.com> Date: Mon Nov 14 08:31:11 2016 -0800 docs(toh): avoid dup header title (#2796) * remove redundant headings * update _cache * misc: make block comment a Jade comment (This prevents the text from appearing in the generated HTML as an HTML comment.) commit 3b03573f340cc7fc43e2642bdf52fb1bae61aff0 Author: Patrice Chalin <pchalin@gmail.com> Date: Mon Nov 14 05:30:05 2016 -0800 misc: make block comment a Jade comment (This prevents the text from appearing in the generated HTML as an HTML comment.) commit 470426d5e03829442449cb59c0528811c6011c37 Author: Patrice Chalin <pchalin@gmail.com> Date: Mon Nov 14 05:25:36 2016 -0800 update _cache commit c12d75a477a1e33ea37886c0bd5942ddb9c955b3 Author: Patrice Chalin <pchalin@gmail.com> Date: Mon Nov 14 05:23:35 2016 -0800 remove redundant headings commit 85062c47cac44d63b06b97ae86b2a4f596889ad6 Author: Patrice Chalin <pchalin@gmail.com> Date: Mon Nov 14 04:56:12 2016 -0800 chore(util.js): getExampleName - support optional .html suffix commit 02f55592b232618407a3a8fce70845589ee78978 Author: Patrice Chalin <pchalin@gmail.com> Date: Mon Nov 14 04:29:17 2016 -0800 docs: guide/index misc Jade fixes - Eliminate use of deprecated `clear=“all”` in `<br>`. - No need for local `langName`; use global `_Lang` var instead. - Remove duplicate id `learning-path`. commit 14db838f8b76309597140d9857acb92c76c864f6 Author: Naomi Black <naomitraveller@gmail.com> Date: Sun Nov 13 21:48:52 2016 -0500 news(nov): Some news and a blog post update commit eff32ecbdd5a52d2240afd5ad4e14bdab21c9a8f Author: Naomi Black <naomitraveller@gmail.com> Date: Sun Nov 13 21:48:37 2016 -0500 chore(bios): update some bios for leads commit 3ee36fbba211d115414d322b17a67626ed90d450 Author: koyner <markburrett@gmail.com> Date: Sun Nov 13 22:59:59 2016 +0100 docs(forms): grammar fix (#2764) commit b11438f211ed7009335bc18f5cbf2950fc4014fa Author: Ward Bell <wardbell@hotmail.com> Date: Fri Nov 11 19:44:00 2016 -0800 docs(ts-to-js): add separate template files for some components commit 33b61977b2cd0bc35b257ce526d5dd2fd460cd10 Author: Ward Bell <wardbell@hotmail.com> Date: Thu Nov 3 01:37:55 2016 -0700 docs(ts-to-js): ward's edits (incomplete) commit 12eb19fa3c34bb48b28da8bd33d94d7cc0526cf5 Author: Filipe Silva <filipematossilva@gmail.com> Date: Thu Oct 13 17:59:00 2016 +0100 feat(cb-ts-to-js): add es6 examples update docshredder to shred .es6 optimized focus gulp task convert imports and metadate sections add DI section add host and query metadata section add intro fix capitalization and grammar commit 64a8754386c0aa727e61d140d86bd31b6891ea99 Author: Patrice Chalin <chalin@users.noreply.github.com> Date: Thu Nov 10 20:01:36 2016 -0800 example(template-syntax): follow style-guide and other updates (#2750) commit 7619cdf4a4ac592d74c25a372234c2d3964355dc Author: Jesús Rodríguez <Foxandxss@gmail.com> Date: Thu Nov 10 23:47:30 2016 +0100 chore: ability to open a plunker on a specific file (#2778) commit 0161d9db39b08be6a29e5a00b362c1eff12bf6b9 Author: Filipe Silva <filipematossilva@gmail.com> Date: Thu Nov 10 22:45:22 2016 +0000 chore: ignore debug.log file (#2785) This file is generated when running `gulp e2e` and often enough committed by mistake. /cc @foxandxss commit f92983cc6f7a895b751a6023791a283bb2e41073 Author: Jesús Rodríguez <Foxandxss@gmail.com> Date: Thu Nov 10 23:44:51 2016 +0100 docs(ngmodule): fix plunkers (#2786) commit 03db4bbc4873d8b68d08ef32bfa1b2b43cf46224 Author: Martin Eckardt <m.eckardt@outlook.com> Date: Wed Nov 9 17:43:40 2016 +0100 docs(a1-a2): fix link to Filter/Pipes (#2770) commit 60565a5cf1dfa7e43cb18b448c7d61c5f765f0de Author: Pavol Pitonak <pavol@pitonak.com> Date: Wed Nov 9 17:42:57 2016 +0100 docs(testing): configureTestModule -> configureTestingModule (#2767) commit ec471974a776dc208b2c56115cf1105fa39c8f88 Author: Catalin Zalog <xxxxxcata@yahoo.com> Date: Wed Nov 9 18:41:56 2016 +0200 docs(style-guide): fix missing *.ts (#2763) commit 234e468d5d6a11782e306901f80546d8989f17b3 Author: Patrice Chalin <pchalin@gmail.com> Date: Tue Nov 8 08:21:02 2016 -0800 docs: intra-site links should be relative Contributes to #2772. commit 6b37da78e4901a57b6ebf77720ec4796f2bb5f5f Author: Patrice Chalin <pchalin@gmail.com> Date: Tue Nov 8 09:27:10 2016 -0800 docs(forms/dart): remove mention of FORM_DIRECTIVES Fixes #2752 commit c24dd074a6acbceb87f8e973969c9bd94f769d8f Author: Patrice Chalin <chalin@users.noreply.github.com> Date: Tue Nov 8 14:48:03 2016 -0800 docs(toh-5/dart): use routerLink in dashboard (#2744) * docs(toh-5/dart): use routerLink in dashboard * minor edits to TS jade * remove dart/toh-pt5 from bad-code-excerpt-skip-patterns commit 2808878c36d7429611e4f0584323e99c9b83219e Author: Patrice Chalin <pchalin@gmail.com> Date: Tue Nov 8 07:41:27 2016 -0800 chore(deploy): don't name project in firebase deploy Naming the project would sometimes cause gulp to report `An unexpected error has occurred` with exit code 2. commit 2649647ecb14a28932405d6b0bc22afd1f931089 Author: Jesus Rodriguez <Foxandxss@gmail.com> Date: Sat Nov 5 00:37:47 2016 +0100 chore: add upgrade/static to API reference commit 850814097f9908781ce954d13878d20eed779c87 Merge: 37f93bc b1c2c27 Author: Adrian Irwin <mr.irwin@gmail.com> Date: Thu Nov 3 17:27:43 2016 -0700 Merge branch 'router' of https://github.com/adrianirwin/angular.io into router commit 37f93bc0cbc2a766846b7715b1d8ddeeec43de39 Author: Adrian Irwin <mr.irwin@gmail.com> Date: Thu Nov 3 17:25:55 2016 -0700 docs(router): fixed verbiage and example of how routed views are related to the router outlet commit b1c2c27d365186d4231a470945a0975482df58e9 Author: Adrian Irwin <adrianirwin@kpmg.com> Date: Thu Nov 3 16:57:56 2016 -0700 docs(router): fixed verbiage and example of how routed views are related to the router outlet
1596 lines
55 KiB
JavaScript
1596 lines
55 KiB
JavaScript
var gulp = require('gulp');
|
|
var gutil = require('gulp-util');
|
|
var taskListing = require('gulp-task-listing');
|
|
var path = require('canonical-path');
|
|
var del = require('del');
|
|
var _ = require('lodash');
|
|
var argv = require('yargs').argv;
|
|
var env = require('gulp-env');
|
|
var Q = require("q");
|
|
var Minimatch = require("minimatch").Minimatch;
|
|
var Dgeni = require('dgeni');
|
|
var Package = require('dgeni').Package;
|
|
var fsExtra = require('fs-extra');
|
|
var fs = fsExtra;
|
|
var exec = require('child_process').exec;
|
|
var execPromise = Q.denodeify(exec);
|
|
var execSync = require('child_process').execSync;
|
|
// cross platform version of spawn that also works on windows.
|
|
var xSpawn = require('cross-spawn');
|
|
var prompt = require('prompt');
|
|
var globby = require("globby");
|
|
// Ugh... replacement needed to kill processes on any OS
|
|
// - because childProcess.kill does not work properly on windows
|
|
var treeKill = require("tree-kill");
|
|
var blc = require("broken-link-checker");
|
|
var less = require('gulp-less');
|
|
var tslint = require('gulp-tslint');
|
|
|
|
// TODO:
|
|
// 1. Think about using runSequence
|
|
// 2. Think about using spawn instead of exec in case of long error messages.
|
|
|
|
var TOOLS_PATH = './tools';
|
|
var ANGULAR_IO_PROJECT_PATH = path.resolve('.');
|
|
var ANGULAR_PROJECT_PATH = '../angular';
|
|
var PUBLIC_PATH = './public';
|
|
var TEMP_PATH = './_temp';
|
|
var DOCS_PATH = path.join(PUBLIC_PATH, 'docs');
|
|
|
|
var EXAMPLES_PATH = path.join(DOCS_PATH, '_examples');
|
|
var BOILERPLATE_PATH = path.join(EXAMPLES_PATH, '_boilerplate');
|
|
var EXAMPLES_TESTING_PATH = path.join(EXAMPLES_PATH, 'testing/ts');
|
|
var NOT_API_DOCS_GLOB = path.join(PUBLIC_PATH, './{docs/*/latest/!(api),!(docs)}/**/*.*');
|
|
var RESOURCES_PATH = path.join(PUBLIC_PATH, 'resources');
|
|
var LIVE_EXAMPLES_PATH = path.join(RESOURCES_PATH, 'live-examples');
|
|
var STYLES_SOURCE_PATH = path.join(TOOLS_PATH, 'styles-builder/less');
|
|
|
|
var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder'));
|
|
var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper'));
|
|
var regularPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/regularPlunker'));
|
|
var embeddedPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/embeddedPlunker'));
|
|
var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils'));
|
|
|
|
const WWW = argv.page ? 'www-pages' : 'www'
|
|
|
|
const isSilent = !!argv.silent;
|
|
if (isSilent) gutil.log = gutil.noop;
|
|
const _dgeniLogLevel = argv.dgeniLog || (isSilent ? 'error' : 'info');
|
|
|
|
var _devguideShredOptions = {
|
|
examplesDir: path.join(DOCS_PATH, '_examples'),
|
|
fragmentsDir: path.join(DOCS_PATH, '_fragments'),
|
|
zipDir: path.join(RESOURCES_PATH, 'zips'),
|
|
logLevel: _dgeniLogLevel
|
|
};
|
|
|
|
var _devguideShredJadeOptions = {
|
|
jadeDir: DOCS_PATH,
|
|
logLevel: _dgeniLogLevel
|
|
};
|
|
|
|
var _apiShredOptions = {
|
|
lang: 'ts',
|
|
examplesDir: path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/examples'),
|
|
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
|
|
zipDir: path.join(RESOURCES_PATH, 'zips/api'),
|
|
logLevel: _dgeniLogLevel
|
|
};
|
|
|
|
const relDartDocApiDir = path.join('doc', 'api');
|
|
var _apiShredOptionsForDart = {
|
|
lang: 'dart',
|
|
examplesDir: path.resolve(ANGULAR_PROJECT_PATH + '2_api_examples'),
|
|
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
|
|
zipDir: path.join(RESOURCES_PATH, 'zips/api'),
|
|
logLevel: _dgeniLogLevel
|
|
};
|
|
|
|
var _excludePatterns = ['**/node_modules/**', '**/packages/**'];
|
|
|
|
var _excludeMatchers = _excludePatterns.map(function(excludePattern){
|
|
return new Minimatch(excludePattern)
|
|
});
|
|
|
|
var _exampleBoilerplateFiles = [
|
|
'a2docs.css',
|
|
'package.json',
|
|
'styles.css',
|
|
'systemjs.config.js',
|
|
'tsconfig.json',
|
|
'tslint.json'
|
|
];
|
|
|
|
var _exampleDartWebBoilerPlateFiles = ['a2docs.css', 'styles.css'];
|
|
|
|
var _exampleUnitTestingBoilerplateFiles = [
|
|
'karma-test-shim.js',
|
|
'karma.conf.js'
|
|
];
|
|
|
|
var _exampleConfigFilename = 'example-config.json';
|
|
|
|
var _styleLessName = 'a2docs.less';
|
|
|
|
// Gulp flags:
|
|
//
|
|
// --lang=[all | ts | js | dart | 'ts|js' | 'ts|js|dart' | ...]
|
|
//
|
|
// This affects which language API docs and E2E tests are run. Can be 'all',
|
|
// or a regex pattern to match any one of 'ts', 'js', or 'dart'.
|
|
// Default: 'ts|js' except for the "full site build" tasks (see below),
|
|
// for which it is 'all'.
|
|
|
|
// langs and skipLangs partition ['ts', 'js', 'dart'].
|
|
var lang, langs, skipLangs, buildDartApiDocs = false;
|
|
function configLangs(langOption) {
|
|
const fullSiteBuildTasks = ['build-compile', 'check-deploy', 'harp-compile'];
|
|
const buildAllDocs = argv['_'] &&
|
|
fullSiteBuildTasks.some((task) => argv['_'].indexOf(task) >= 0);
|
|
const langDefault = buildAllDocs ? 'all' : 'ts|js';
|
|
if (langOption === '') {
|
|
lang = '';
|
|
langs = [];
|
|
} else {
|
|
lang = (langOption || langDefault).toLowerCase();
|
|
if (lang === 'all') lang = 'ts|js|dart';
|
|
langs = lang.match(/\w+/g); // the languages in `lang` as an array
|
|
}
|
|
gutil.log(`Building docs for: [${langs}]`);
|
|
if (langs.indexOf('dart') >= 0) {
|
|
buildDartApiDocs = true;
|
|
// For Dart, be proactive about checking for the repo
|
|
checkAngularProjectPath(ngPathFor('dart'));
|
|
} else {
|
|
argv.pub = false;
|
|
}
|
|
skipLangs = [];
|
|
['ts', 'js', 'dart'].forEach(lang => {
|
|
if (langs.indexOf(lang) < 0) skipLangs.push(lang);
|
|
});
|
|
gutil.log(`Skipped languages: [${skipLangs}]`);
|
|
}
|
|
configLangs(argv.lang);
|
|
|
|
function isDartPath(path) {
|
|
// Testing via indexOf() for now. If we need to match only paths with folders
|
|
// named 'dart' vs 'dart*' then try: path.match('/dart(/|$)') != null;
|
|
return path.indexOf('/dart') > -1;
|
|
}
|
|
|
|
function excludeDartPaths(paths) {
|
|
return paths.filter(function (p) { return !isDartPath(p); });
|
|
}
|
|
|
|
/**
|
|
* Run Protractor End-to-End Specs for Doc Samples
|
|
* Alias for 'run-e2e-tests'
|
|
*/
|
|
gulp.task('e2e', runE2e);
|
|
|
|
gulp.task('run-e2e-tests', runE2e);
|
|
|
|
/**
|
|
* Run Protractor End-to-End Tests for Doc Samples
|
|
*
|
|
* Flags
|
|
* --filter to filter/select _example app subdir names
|
|
* e.g. gulp e2e --filter=foo // all example apps with 'foo' in their folder names.
|
|
*
|
|
* --fast by-passes the npm install and webdriver update
|
|
* Use it for repeated test runs (but not the FIRST run)
|
|
* e.g. gulp e2e --fast
|
|
*
|
|
* --lang to filter by code language (see above for details)
|
|
* e.g. gulp e2e --lang=ts // only TypeScript apps
|
|
*/
|
|
function runE2e() {
|
|
var promise;
|
|
if (argv.fast) {
|
|
// fast; skip all setup
|
|
promise = Promise.resolve(true);
|
|
} else {
|
|
/*
|
|
// Not 'fast'; do full setup
|
|
var spawnInfo = spawnExt('npm', ['install'], { cwd: EXAMPLES_PATH});
|
|
promise = spawnInfo.promise.then(function() {
|
|
copyExampleBoilerplate();
|
|
spawnInfo = spawnExt('npm', ['run', 'webdriver:update'], {cwd: EXAMPLES_PATH});
|
|
return spawnInfo.promise;
|
|
});
|
|
*/
|
|
// Not 'fast'; do full setup
|
|
gutil.log('runE2e: install _examples stuff');
|
|
var spawnInfo = spawnExt('npm', ['install'], { cwd: EXAMPLES_PATH});
|
|
promise = spawnInfo.promise
|
|
.then(function() {
|
|
buildStyles(copyExampleBoilerplate, _.noop);
|
|
gutil.log('runE2e: update webdriver');
|
|
spawnInfo = spawnExt('npm', ['run', 'webdriver:update'], {cwd: EXAMPLES_PATH});
|
|
return spawnInfo.promise;
|
|
});
|
|
};
|
|
|
|
var outputFile = path.join(process.cwd(), 'protractor-results.txt');
|
|
|
|
promise.then(function() {
|
|
return findAndRunE2eTests(argv.filter, outputFile);
|
|
}).then(function(status) {
|
|
reportStatus(status, outputFile);
|
|
if (status.failed.length > 0){
|
|
return Promise.reject('Some test suites failed');
|
|
}
|
|
}).catch(function(e) {
|
|
gutil.log(e);
|
|
process.exitCode = 1;
|
|
});
|
|
return promise;
|
|
}
|
|
|
|
// finds all of the *e2e-spec.tests under the _examples folder along
|
|
// with the corresponding apps that they should run under. Then run
|
|
// each app/spec collection sequentially.
|
|
function findAndRunE2eTests(filter, outputFile) {
|
|
// create an output file with header.
|
|
var startTime = new Date().getTime();
|
|
var header = `Doc Sample Protractor Results for ${lang} on ${new Date().toLocaleString()}\n`;
|
|
header += argv.fast ?
|
|
' Fast Mode (--fast): no npm install, webdriver update, or boilerplate copy\n' :
|
|
' Slow Mode: npm install, webdriver update, and boilerplate copy\n';
|
|
header += ` Filter: ${filter ? filter : 'All tests'}\n\n`;
|
|
fs.writeFileSync(outputFile, header);
|
|
|
|
// create an array of combos where each
|
|
// combo consists of { examplePath: ... }
|
|
var examplePaths = [];
|
|
var e2eSpecPaths = getE2eSpecPaths(EXAMPLES_PATH);
|
|
e2eSpecPaths.forEach(function(specPath) {
|
|
// get all of the examples under each dir where a pcFilename is found
|
|
localExamplePaths = getExamplePaths(specPath, true);
|
|
// Filter by example name
|
|
if (filter) {
|
|
localExamplePaths = localExamplePaths.filter(function (fn) {
|
|
return fn.match(filter) != null;
|
|
})
|
|
}
|
|
// Filter by language, also supports variations like js-es6
|
|
localExamplePaths = localExamplePaths.filter(function (fn) {
|
|
return fn.match('/'+lang+'(?:-[^/]*)?$') != null;
|
|
});
|
|
localExamplePaths.forEach(function(examplePath) {
|
|
examplePaths.push(examplePath);
|
|
})
|
|
});
|
|
|
|
// run the tests sequentially
|
|
var status = { passed: [], failed: [] };
|
|
return examplePaths.reduce(function (promise, examplePath) {
|
|
return promise.then(function () {
|
|
var runTests = isDartPath(examplePath) ? runE2eDartTests : runE2eTsTests;
|
|
return runTests(examplePath, outputFile).then(function(ok) {
|
|
var arr = ok ? status.passed : status.failed;
|
|
arr.push(examplePath);
|
|
})
|
|
});
|
|
}, Q.resolve()).then(function() {
|
|
var stopTime = new Date().getTime();
|
|
status.elapsedTime = (stopTime - startTime)/1000;
|
|
return status;
|
|
});
|
|
}
|
|
|
|
// start the example in appDir; then run protractor with the specified
|
|
// fileName; then shut down the example. All protractor output is appended
|
|
// to the outputFile.
|
|
function runE2eTsTests(appDir, outputFile) {
|
|
// Grab protractor configuration or defaults to systemjs config.
|
|
try {
|
|
var exampleConfig = fs.readJsonSync(`${appDir}/${_exampleConfigFilename}`);
|
|
} catch (e) {
|
|
exampleConfig = {};
|
|
}
|
|
|
|
var config = {
|
|
build: exampleConfig.build || 'tsc',
|
|
run: exampleConfig.run || 'http-server:e2e'
|
|
};
|
|
|
|
var appBuildSpawnInfo = spawnExt('npm', ['run', config.build], { cwd: appDir });
|
|
var appRunSpawnInfo = spawnExt('npm', ['run', config.run, '--', '-s'], { cwd: appDir });
|
|
|
|
var run = runProtractor(appBuildSpawnInfo.promise, appDir, appRunSpawnInfo, outputFile);
|
|
|
|
if (fs.existsSync(appDir + '/aot/index.html')) {
|
|
run = run.then(() => runProtractorAoT(appDir, outputFile));
|
|
}
|
|
return run;
|
|
}
|
|
|
|
function runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile) {
|
|
var specFilename = path.resolve(`${appDir}/../e2e-spec.ts`);
|
|
return prepPromise
|
|
.catch(function(){
|
|
var emsg = `Application at ${appDir} failed to transpile.\n\n`;
|
|
gutil.log(emsg);
|
|
fs.appendFileSync(outputFile, emsg);
|
|
return Promise.reject(emsg);
|
|
})
|
|
.then(function (data) {
|
|
var transpileError = false;
|
|
|
|
// start protractor
|
|
|
|
var spawnInfo = spawnExt('npm', [ 'run', 'protractor', '--', 'protractor.config.js',
|
|
`--specs=${specFilename}`, '--params.appDir=' + appDir, '--params.outputFile=' + outputFile], { cwd: EXAMPLES_PATH });
|
|
|
|
spawnInfo.proc.stderr.on('data', function (data) {
|
|
transpileError = transpileError || /npm ERR! Exit status 100/.test(data.toString());
|
|
});
|
|
return spawnInfo.promise.catch(function(err) {
|
|
if (transpileError) {
|
|
var emsg = `${specFilename} failed to transpile.\n\n`;
|
|
gutil.log(emsg);
|
|
fs.appendFileSync(outputFile, emsg);
|
|
}
|
|
return Promise.reject(emsg);
|
|
});
|
|
})
|
|
.then(
|
|
function() { return finish(true);},
|
|
function() { return finish(false);}
|
|
)
|
|
|
|
function finish(ok){
|
|
// Ugh... proc.kill does not work properly on windows with child processes.
|
|
// appRun.proc.kill();
|
|
treeKill(appRunSpawnInfo.proc.pid);
|
|
return ok;
|
|
}
|
|
}
|
|
|
|
function runProtractorAoT(appDir, outputFile) {
|
|
fs.appendFileSync(outputFile, '++ AoT version ++\n');
|
|
var aotBuildSpawnInfo = spawnExt('npm', ['run', 'build:aot'], { cwd: appDir });
|
|
var promise = aotBuildSpawnInfo.promise;
|
|
|
|
var copyFileCmd = 'copy-dist-files.js';
|
|
if (fs.existsSync(appDir + '/' + copyFileCmd)) {
|
|
promise = promise.then(() =>
|
|
spawnExt('node', [copyFileCmd], { cwd: appDir }).promise );
|
|
}
|
|
var aotRunSpawnInfo = spawnExt('npm', ['run', 'http-server:e2e', 'aot', '--', '-s'], { cwd: appDir });
|
|
return runProtractor(promise, appDir, aotRunSpawnInfo, outputFile);
|
|
}
|
|
|
|
// start the server in appDir/build/web; then run protractor with the specified
|
|
// fileName; then shut down the example. All protractor output is appended
|
|
// to the outputFile.
|
|
function runE2eDartTests(appDir, outputFile) {
|
|
// Launch http server out of ts directory because all the config files are there.
|
|
var httpLaunchDir = path.resolve(appDir, '../ts');
|
|
var deployDir = path.resolve(appDir, 'build/web');
|
|
gutil.log('AppDir for Dart e2e: ' + appDir);
|
|
gutil.log('Deploying from: ' + deployDir);
|
|
|
|
var appRunSpawnInfo = spawnExt('npm', ['run', 'http-server:e2e', '--', deployDir, '-s'], { cwd: httpLaunchDir });
|
|
if (!appRunSpawnInfo.proc.pid) {
|
|
gutil.log('http-server failed to launch over ' + deployDir);
|
|
return false;
|
|
}
|
|
if (argv.pub === false) {
|
|
var prepPromise = Promise.resolve(true);
|
|
gutil.log('Skipping pub upgrade and pub build (--no-pub flag present)');
|
|
} else {
|
|
var pubUpgradeSpawnInfo = spawnExt('pub', ['upgrade'], { cwd: appDir });
|
|
var prepPromise = pubUpgradeSpawnInfo.promise.then(function (data) {
|
|
return spawnExt('pub', ['build'], { cwd: appDir }).promise;
|
|
});
|
|
}
|
|
return runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile);
|
|
}
|
|
|
|
function reportStatus(status, outputFile) {
|
|
var log = [''];
|
|
log.push('Suites passed:');
|
|
status.passed.forEach(function(val) {
|
|
log.push(' ' + val);
|
|
});
|
|
|
|
if (status.failed.length == 0) {
|
|
log.push('All tests passed');
|
|
} else {
|
|
log.push('Suites failed:');
|
|
status.failed.forEach(function (val) {
|
|
log.push(' ' + val);
|
|
});
|
|
}
|
|
log.push('\nElapsed time: ' + status.elapsedTime + ' seconds');
|
|
var log = log.join('\n');
|
|
gutil.log(log);
|
|
fs.appendFileSync(outputFile, log);
|
|
}
|
|
|
|
// returns both a promise and the spawned process so that it can be killed if needed.
|
|
function spawnExt(command, args, options) {
|
|
var deferred = Q.defer();
|
|
var descr = command + " " + args.join(' ');
|
|
var proc;
|
|
gutil.log('running: ' + descr);
|
|
try {
|
|
proc = xSpawn.spawn(command, args, options);
|
|
} catch(e) {
|
|
gutil.log(e);
|
|
deferred.reject(e);
|
|
return { proc: null, promise: deferred.promise };
|
|
}
|
|
proc.stdout.on('data', function (data) {
|
|
gutil.log(data.toString());
|
|
});
|
|
proc.stderr.on('data', function (data) {
|
|
gutil.log(data.toString());
|
|
});
|
|
proc.on('close', function (returnCode) {
|
|
gutil.log('completed: ' + descr);
|
|
// Many tasks (e.g., tsc) complete but are actually errors;
|
|
// Confirm return code is zero.
|
|
returnCode === 0 ? deferred.resolve(0) : deferred.reject(returnCode);
|
|
});
|
|
proc.on('error', function (data) {
|
|
gutil.log('completed with error:' + descr);
|
|
gutil.log(data.toString());
|
|
deferred.reject(data);
|
|
});
|
|
return { proc: proc, promise: deferred.promise };
|
|
}
|
|
|
|
// Public tasks
|
|
|
|
gulp.task('default', ['help']);
|
|
|
|
gulp.task('help', taskListing.withFilters(function(taskName) {
|
|
var isSubTask = taskName.substr(0,1) == "_";
|
|
return isSubTask;
|
|
}, function(taskName) {
|
|
var shouldRemove = taskName === 'default';
|
|
return shouldRemove;
|
|
}));
|
|
|
|
// requires admin access because it adds symlinks
|
|
gulp.task('add-example-boilerplate', function(done) {
|
|
var realPath = path.join(EXAMPLES_PATH, '/node_modules');
|
|
var nodeModulesPaths = excludeDartPaths(getNodeModulesPaths(EXAMPLES_PATH));
|
|
|
|
nodeModulesPaths.forEach(function(linkPath) {
|
|
gutil.log("symlinking " + linkPath + ' -> ' + realPath)
|
|
fsUtils.addSymlink(realPath, linkPath);
|
|
});
|
|
|
|
return buildStyles(copyExampleBoilerplate, done);
|
|
});
|
|
|
|
|
|
// copies boilerplate files to locations
|
|
// where an example app is found
|
|
gulp.task('_copy-example-boilerplate', function (done) {
|
|
return argv.fast ? done() : buildStyles(copyExampleBoilerplate, done);
|
|
});
|
|
|
|
//Builds Angular Docs CSS file from Bootstrap npm LESS source
|
|
//and copies the result to the _examples folder to be included as
|
|
//part of the example boilerplate.
|
|
function buildStyles(cb, done){
|
|
gulp.src(path.join(STYLES_SOURCE_PATH, _styleLessName))
|
|
.pipe(less())
|
|
.pipe(gulp.dest(BOILERPLATE_PATH)).on('end', function(){
|
|
cb().then(function() { done(); });
|
|
});
|
|
}
|
|
|
|
// copies boilerplate files to locations
|
|
// where an example app is found
|
|
// also copies certain web files (e.g., styles.css) to ~/_examples/**/dart/**/web
|
|
function copyExampleBoilerplate() {
|
|
gutil.log('Copying example boilerplate files');
|
|
var sourceFiles = _exampleBoilerplateFiles.map(function(fn) {
|
|
return path.join(BOILERPLATE_PATH, fn);
|
|
});
|
|
var examplePaths = excludeDartPaths(getExamplePaths(EXAMPLES_PATH));
|
|
|
|
var dartWebSourceFiles = _exampleDartWebBoilerPlateFiles.map(function(fn){
|
|
return path.join(BOILERPLATE_PATH, fn);
|
|
});
|
|
var dartExampleWebPaths = getDartExampleWebPaths(EXAMPLES_PATH);
|
|
|
|
// Make boilerplate files read-only to avoid that they be edited by mistake.
|
|
var destFileMode = '444';
|
|
return copyFiles(sourceFiles, examplePaths, destFileMode)
|
|
.then(function() {
|
|
return copyFiles(dartWebSourceFiles, dartExampleWebPaths, destFileMode);
|
|
})
|
|
// copy the unit test boilerplate
|
|
.then(function() {
|
|
var unittestSourceFiles =
|
|
_exampleUnitTestingBoilerplateFiles
|
|
.map(function(name) { return path.join(EXAMPLES_TESTING_PATH, name); });
|
|
var unittestPaths = getUnitTestingPaths(EXAMPLES_PATH);
|
|
return copyFiles(unittestSourceFiles, unittestPaths, destFileMode);
|
|
})
|
|
.catch(function(err) {
|
|
gutil.log(err);
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
gulp.task('remove-example-boilerplate', function() {
|
|
var nodeModulesPaths = getNodeModulesPaths(EXAMPLES_PATH);
|
|
nodeModulesPaths.forEach(function(linkPath) {
|
|
fsUtils.removeSymlink(linkPath);
|
|
});
|
|
|
|
deleteExampleBoilerPlate();
|
|
});
|
|
|
|
// Npm install Angular libraries into examples/node_modules,
|
|
// either release or current build packages
|
|
// Examples:
|
|
// gulp install-example-angular --build // use current build packages
|
|
// gulp install-example-angular --build=2.0.0-b43f954 // use tagged packages
|
|
// gulp install-example-angular // restore release packages
|
|
//
|
|
// Find the tags here: https://github.com/angular/core-builds/releases
|
|
gulp.task('install-example-angular', installExampleAngular);
|
|
|
|
function installExampleAngular() {
|
|
var sources;
|
|
var template;
|
|
var libs = [
|
|
'core', 'common', 'compiler', 'compiler-cli',
|
|
'platform-browser', 'platform-browser-dynamic',
|
|
'forms', 'http', 'router', 'upgrade'];
|
|
|
|
var build = argv.build;
|
|
if (build) {
|
|
if (typeof build === 'string') {
|
|
build = (build[0]==='#' ? '' : '#') + build;
|
|
} else {
|
|
build = '';
|
|
}
|
|
} else{
|
|
build = 'npm';
|
|
}
|
|
// Like: "angular/core-builds" or "@angular/core"
|
|
sources = libs.map( lib => {
|
|
return build === 'npm'
|
|
? `@angular/${lib}`
|
|
: `git+https://github.com/angular/${lib}-builds${build}`;
|
|
});
|
|
|
|
if (argv.build) { sources.push('@angular/tsc-wrapped');} // tsc-wrapped needed for builds
|
|
|
|
sources.push('@angular/router-deprecated');
|
|
|
|
gutil.log(`Installing Angular packages from ${build === 'npm' ? 'NPM' : 'BUILD ' + build}`);
|
|
|
|
var spawnInfo = spawnExt('rm', ['-rf', 'node_modules/@angular'], { cwd: EXAMPLES_PATH});
|
|
return spawnInfo.promise
|
|
.then(() => {
|
|
spawnInfo = spawnExt('npm', ['install', ...sources], {cwd: EXAMPLES_PATH});
|
|
return spawnInfo.promise
|
|
});
|
|
}
|
|
|
|
// deletes boilerplate files that were added by copyExampleBoilerplate
|
|
// from locations where an example app is found
|
|
gulp.task('_delete-example-boilerplate', deleteExampleBoilerPlate);
|
|
|
|
function deleteExampleBoilerPlate() {
|
|
gutil.log('Deleting example boilerplate files');
|
|
var examplePaths = getExamplePaths(EXAMPLES_PATH);
|
|
var dartExampleWebPaths = getDartExampleWebPaths(EXAMPLES_PATH);
|
|
|
|
return deleteFiles(_exampleBoilerplateFiles, examplePaths)
|
|
.then(function() {
|
|
return deleteFiles(_exampleDartWebBoilerPlateFiles, dartExampleWebPaths);
|
|
});
|
|
}
|
|
|
|
gulp.task('serve-and-sync', ['build-docs'], function (cb) {
|
|
// watchAndSync({devGuide: true, apiDocs: true, apiExamples: true, localFiles: true}, cb);
|
|
watchAndSync({devGuide: true, devGuideJade: true, apiDocs: true, apiExamples: true, localFiles: true}, cb);
|
|
});
|
|
|
|
gulp.task('serve-and-sync-api', ['build-docs'], function (cb) {
|
|
watchAndSync({apiDocs: true, apiExamples: true}, cb);
|
|
});
|
|
|
|
gulp.task('serve-and-sync-devguide', ['build-devguide-docs', 'build-plunkers' ], function (cb) {
|
|
watchAndSync({devGuide: true, devGuideJade: true, localFiles: true}, cb);
|
|
});
|
|
|
|
gulp.task('_serve-and-sync-jade', function (cb) {
|
|
watchAndSync({devGuideJade: true, localFiles: true}, cb);
|
|
});
|
|
|
|
gulp.task('build-and-serve', ['build-docs'], function (cb) {
|
|
watchAndSync({localFiles: true}, cb);
|
|
});
|
|
|
|
gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers']);
|
|
// Stop zipping examples Feb 28, 2016
|
|
//gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']);
|
|
|
|
gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs']
|
|
.concat(buildDartApiDocs ? ['build-dart-api-docs', 'build-dart-cheatsheet'] : []));
|
|
|
|
gulp.task('build-devguide-docs', ['_shred-devguide-examples', '_shred-devguide-shared-jade'], function() {
|
|
return buildShredMaps(true);
|
|
});
|
|
|
|
gulp.task('build-ts-api-docs', ['_shred-api-examples'], function() {
|
|
return buildApiDocs('ts');
|
|
});
|
|
|
|
gulp.task('build-js-api-docs', ['_shred-api-examples'], function() {
|
|
return buildApiDocs('js');
|
|
});
|
|
|
|
gulp.task('build-dart-api-docs', ['_shred-api-examples', 'dartdoc'], function() {
|
|
return buildApiDocsForDart();
|
|
});
|
|
|
|
// Using the --build flag will use systemjs.config.web.build.js (for preview builds)
|
|
gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() {
|
|
regularPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build });
|
|
return embeddedPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build, targetSelf: argv.targetSelf });
|
|
});
|
|
|
|
gulp.task('build-dart-cheatsheet', [], function() {
|
|
return buildDartCheatsheet();
|
|
});
|
|
|
|
gulp.task('dartdoc', ['pub upgrade'], function() {
|
|
const ngRepoPath = ngPathFor('dart');
|
|
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, relDartDocApiDir))) {
|
|
gutil.log(`Skipping dartdoc: --fast flag enabled and api dir exists (${relDartDocApiDir})`);
|
|
return true;
|
|
}
|
|
checkAngularProjectPath(ngRepoPath);
|
|
const topLevelLibFilePath = path.resolve(ngRepoPath, 'lib', 'angular2.dart');
|
|
const tmpPath = topLevelLibFilePath + '.disabled';
|
|
renameIfExistsSync(topLevelLibFilePath, tmpPath);
|
|
gutil.log(`Hiding top-level angular2 library: ${topLevelLibFilePath}`);
|
|
// Remove dartdoc '--add-crossdart' flag while we are fixing links to API pages.
|
|
const dartdoc = spawnExt('dartdoc', ['--output', relDartDocApiDir], { cwd: ngRepoPath});
|
|
return dartdoc.promise.finally(() => {
|
|
gutil.log(`Restoring top-level angular2 library: ${topLevelLibFilePath}`);
|
|
renameIfExistsSync(tmpPath, topLevelLibFilePath);
|
|
})
|
|
});
|
|
|
|
gulp.task('pub upgrade', [], function() {
|
|
const ngRepoPath = ngPathFor('dart');
|
|
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'packages'))) {
|
|
gutil.log('Skipping pub upgrade: --fast flag enabled and "packages" dir exists');
|
|
return true;
|
|
}
|
|
checkAngularProjectPath(ngRepoPath);
|
|
const pubUpgrade = spawnExt('pub', ['upgrade'], { cwd: ngRepoPath});
|
|
return pubUpgrade.promise;
|
|
});
|
|
|
|
gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
|
|
var after, sha, messageSuffix;
|
|
if (argv.after) {
|
|
try {
|
|
after = new Date(argv.after);
|
|
messageSuffix = ' after: ' + argv.after;
|
|
} catch (e) {
|
|
throw argv.after + " is not a valid date.";
|
|
}
|
|
} else if (argv.sha) {
|
|
sha = argv.sha;
|
|
messageSuffix = ' on commit: ' + (argv.sha.length ? argv.sha : '[last commit]');
|
|
} else {
|
|
gutil.log('git-changed-examples may be called with either an "--sha" argument like this:');
|
|
gutil.log(' gulp git-changed-examples --sha=4d2ac96fa247306ddd2d4c4e0c8dee2223502eb2');
|
|
gutil.log('or with an "--after" argument like this')
|
|
gutil.log(' gulp git-changed-examples --after="August 1, 2015"');
|
|
return;
|
|
}
|
|
var jadeShredMap;
|
|
return buildShredMaps(false).then(function(docs) {
|
|
jadeShredMap = docs[0];
|
|
if (after) {
|
|
return getChangedExamplesAfter(after);
|
|
} else if (sha) {
|
|
return getChangedExamples(sha);
|
|
} else {
|
|
gutil.log('git-changed-examples may be called with either an "--sha" argument like this:');
|
|
gutil.log(' gulp git-changed-examples --sha=4d2ac96fa247306ddd2d4c4e0c8dee2223502eb2');
|
|
gutil.log('or with an "--after" argument like this')
|
|
gutil.log(' gulp git-changed-examples --after="August 1, 2015"');
|
|
}
|
|
}).then(function(examplePaths) {
|
|
examplePaths = filterOutExcludedPatterns(examplePaths, _excludeMatchers);
|
|
gutil.log('\nExamples changed ' + messageSuffix);
|
|
gutil.log(examplePaths)
|
|
gutil.log("\nJade files affected by changed example files " + messageSuffix);
|
|
var jadeExampleMap = jadeShredMapToJadeExampleMap(jadeShredMap, examplePaths);
|
|
gutil.log(JSON.stringify(jadeExampleMap, null, " "));
|
|
gutil.log("-----");
|
|
}).catch(function(err) {
|
|
gutil.log(err);
|
|
throw err;
|
|
});
|
|
});
|
|
|
|
gulp.task('harp-compile', () => {
|
|
return harpCompile()
|
|
});
|
|
|
|
gulp.task('harp-serve', () => {
|
|
// Harp will watch and serve workspace files.
|
|
const cmd = 'npm run harp -- server .';
|
|
gutil.log('Launching harp server (over project files)');
|
|
gutil.log(` > ${cmd}`);
|
|
gutil.log('Note: issuing this command directly from the command line will show harp comiple warnings.');
|
|
return execPromise(cmd);
|
|
});
|
|
|
|
gulp.task('serve-www', () => {
|
|
// Serve generated site.
|
|
return execPromise(`npm run live-server ${WWW}`);
|
|
});
|
|
|
|
gulp.task('build-compile', ['build-docs'], function() {
|
|
return harpCompile();
|
|
});
|
|
|
|
gulp.task('check-deploy', ['firebase-use-proj-check', 'build-docs'], () => {
|
|
return harpCompile().then(function() {
|
|
gutil.log('compile ok');
|
|
gutil.log('running live server ...');
|
|
execPromise(`npm run live-server ${WWW}`);
|
|
return askDeploy();
|
|
}).then(function(shouldDeploy) {
|
|
if (shouldDeploy) {
|
|
gutil.log('deploying...');
|
|
return execPromise('firebase deploy');
|
|
} else {
|
|
return ['Not deploying'];
|
|
}
|
|
}).then(function(s) {
|
|
gutil.log(s.join(''));
|
|
}).catch(function(e) {
|
|
gutil.log(e);
|
|
});
|
|
});
|
|
|
|
gulp.task('firebase-use-proj-check', cb => {
|
|
try {
|
|
execSync('firebase use');
|
|
} catch (e) {
|
|
// Rerun command so user gets project + alias info
|
|
execSync('firebase use', {stdio:[0,1,2]});
|
|
throw `\nAborting: no firebase project selected. Run:\n\n firebase use <project-or-alias-name>\n\n`;
|
|
}
|
|
return cb();
|
|
});
|
|
|
|
gulp.task('test-api-builder', function (cb) {
|
|
execCommands(['npm run test-api-builder'], {}, cb);
|
|
});
|
|
|
|
// Usage:
|
|
// angular.io: gulp link-checker
|
|
// local site: gulp link-checker --url=http://localhost:3000
|
|
gulp.task('link-checker', function(done) {
|
|
var method = 'get'; // the default 'head' fails for some sites
|
|
var exclude = [
|
|
// Dart API docs aren't working yet; ignore them
|
|
'*/dart/latest/api/*',
|
|
// Somehow the link checker sees ng1 {{...}} in the resource page; ignore it
|
|
'resources/%7B%7Bresource.url%7D%7D',
|
|
// API docs have links directly into GitHub repo sources; these can
|
|
// quickly become invalid, so ignore them for now:
|
|
'*/angular/tree/*'
|
|
];
|
|
var blcOptions = { requestMethod: method, excludedKeywords: exclude};
|
|
return linkChecker({ blcOptions: blcOptions });
|
|
});
|
|
|
|
|
|
// Internal tasks
|
|
gulp.task('set-prod-env', function () {
|
|
// Supposedly running in production makes harp faster
|
|
// and less likely to drown in node_modules.
|
|
env({
|
|
vars: { NODE_ENV: "production" }
|
|
});
|
|
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
|
|
});
|
|
|
|
// used to test just harpCompile without a build step
|
|
gulp.task('_harp-compile', function() {
|
|
return harpCompile().then(function() {
|
|
gutil.log('compile ok');
|
|
}).catch(function(e) {
|
|
gutil.log('compile failed');
|
|
});
|
|
});
|
|
|
|
gulp.task('_shred-devguide-examples', ['_shred-clean-devguide', '_copy-example-boilerplate'], function() {
|
|
// Split big shredding task into partials 2016-06-14
|
|
var examplePaths = globby.sync(EXAMPLES_PATH+'/*/', {ignore: ['**/node_modules', '**/_boilerplate']});
|
|
var promise = Promise.resolve(true);
|
|
examplePaths.forEach(function (examplePath) {
|
|
promise = promise.then(() => docShredder.shredSingleExampleDir(_devguideShredOptions, examplePath));
|
|
});
|
|
return promise;
|
|
});
|
|
|
|
gulp.task('_shred-devguide-shared-jade', ['_shred-clean-devguide-shared-jade', '_copy-example-boilerplate'], function() {
|
|
return docShredder.shred(_devguideShredJadeOptions);
|
|
});
|
|
|
|
gulp.task('_shred-clean-devguide-shared-jade', function(cb) {
|
|
// oldCleanPath is only needed to cleanup any jade fragments still sitting in the old location
|
|
var oldCleanPath = path.join(DOCS_PATH, '**/_.*.jade');
|
|
// jade fragments now all go into _fragments subdirs under their source.
|
|
var newCleanPath = path.join(DOCS_PATH, '**/_fragments/*.jade');
|
|
// Much slower 8-9x then using globby first ... ???
|
|
// return del([ newCleanPath, oldCleanPath]);
|
|
var files = globby.sync( [newCleanPath, oldCleanPath]);
|
|
return del(files);
|
|
});
|
|
|
|
gulp.task('_shred-clean-devguide', function(cb) {
|
|
var cleanPath = path.join(_devguideShredOptions.fragmentsDir, '**/*.*')
|
|
return del([ cleanPath, '!**/*.ovr.*', '!**/_api/**']);
|
|
});
|
|
|
|
gulp.task('_shred-api-examples', ['_shred-clean-api'], function() {
|
|
const promises = [];
|
|
gutil.log('Shredding API examples for languages: ' + langs.join(', '));
|
|
langs.forEach(lang => {
|
|
if (lang === 'js') return; // JS is handled via TS.
|
|
checkAngularProjectPath(ngPathFor(lang));
|
|
const options = lang == 'dart' ? _apiShredOptionsForDart : _apiShredOptions;
|
|
promises.push(docShredder.shred(options));
|
|
});
|
|
return Q.all(promises);
|
|
});
|
|
|
|
gulp.task('_shred-clean-api', function(cb) {
|
|
var cleanPath = path.join(_apiShredOptions.fragmentsDir, '**/*.*')
|
|
return del([ cleanPath, '!**/*.ovr.*' ]);
|
|
});
|
|
|
|
gulp.task('_zip-examples', function() {
|
|
exampleZipper.zipExamples(_devguideShredOptions.examplesDir, _devguideShredOptions.zipDir);
|
|
exampleZipper.zipExamples(_apiShredOptions.examplesDir, _apiShredOptions.zipDir);
|
|
});
|
|
|
|
|
|
// Linting
|
|
|
|
gulp.task('lint', function() {
|
|
return gulp.src([
|
|
'./public/docs/_examples/**/*.ts',
|
|
'!./public/docs/_examples/**/ts-snippets/*.ts',
|
|
'!./public/docs/_examples/style-guide/ts/**/*.avoid.ts',
|
|
'!./public/docs/_examples/**/node_modules/**/*',
|
|
'!./public/docs/_examples/**/build/**/*',
|
|
// temporary until codelyzer is fixed mgechev/codelyzer#60
|
|
'!./public/docs/_examples/animations/ts/app/hero.service.ts'
|
|
])
|
|
.pipe(tslint({
|
|
rulesDirectory: ['node_modules/codelyzer'],
|
|
configuration: require('./tslint.json')
|
|
}))
|
|
.pipe(tslint.report('prose', {
|
|
summarizeFailureOutput: true
|
|
}));
|
|
});
|
|
|
|
|
|
// Helper functions
|
|
|
|
function harpCompile() {
|
|
// Supposedly running in production makes harp faster
|
|
// and less likely to drown in node_modules.
|
|
env({ vars: { NODE_ENV: "production" } });
|
|
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
|
|
|
|
if(argv.page) harpJsonSetJade2NgTo(true);
|
|
|
|
if(skipLangs && fs.existsSync(WWW) && backupApiHtmlFilesExist(WWW)) {
|
|
gutil.log(`Harp site recompile: skipping recompilation of API docs for [${skipLangs}]`);
|
|
gutil.log(`API docs will be copied from existing ${WWW} folder.`)
|
|
del.sync(`${WWW}-backup`); // remove existing backup if it exists
|
|
renameIfExistsSync(WWW, `${WWW}-backup`);
|
|
} else {
|
|
gutil.log(`Harp full site compile, including API docs for all languages.`);
|
|
if (skipLangs)
|
|
gutil.log(`Ignoring API docs skip set (${skipLangs}) because full ` +
|
|
`site has not been built yet or some API HTML files are missing.`);
|
|
}
|
|
|
|
var deferred = Q.defer();
|
|
gutil.log('running harp compile...');
|
|
showHideExampleNodeModules('hide');
|
|
showHideApiDir('hide');
|
|
var spawnInfo = spawnExt('npm',['run','harp', '--', 'compile', '.', WWW ]);
|
|
spawnInfo.promise.then(function(x) {
|
|
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
|
|
showHideExampleNodeModules('show');
|
|
showHideApiDir('show');
|
|
harpJsonSetJade2NgTo(false);
|
|
if (x !== 0) {
|
|
deferred.reject(x)
|
|
} else {
|
|
restoreApiHtml();
|
|
deferred.resolve(x);
|
|
}
|
|
}).catch(function(e) {
|
|
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
|
|
showHideExampleNodeModules('show');
|
|
showHideApiDir('show');
|
|
harpJsonSetJade2NgTo(false);
|
|
deferred.reject(e);
|
|
});
|
|
return deferred.promise;
|
|
}
|
|
|
|
function linkChecker(options) {
|
|
var deferred = Q.defer();
|
|
var options = options || {};
|
|
|
|
var blcOptions = options.blcOptions || {};
|
|
var customData = options.customData || {};
|
|
|
|
// don't bother reporting bad links matching this RegExp
|
|
var excludeBad = argv.excludeBad ? new RegExp(argv.excludeBad) : (options.excludeBad || '');
|
|
|
|
var previousPage;
|
|
var siteUrl = argv.url || options.url || 'https://angular.io/';
|
|
|
|
// See https://github.com/stevenvachon/broken-link-checker#blcsitecheckeroptions-handlers
|
|
var handlers = {
|
|
robots: function(robots, customData){},
|
|
html: function(tree, robots, response, pageUrl, customData){
|
|
// gutil.log('Scanning ' + pageUrl);
|
|
},
|
|
junk: function(result, customData){},
|
|
|
|
// Analyze links
|
|
link: function(result, customData){
|
|
if (!result.broken) { return; }
|
|
if (excludeBad && excludeBad.test(result.url.resolved)) { return; }
|
|
|
|
var currentPage = result.base.resolved
|
|
if (previousPage !== currentPage) {
|
|
previousPage = currentPage;
|
|
fs.appendFileSync(outputFile, '\n' + currentPage);
|
|
gutil.log('broken: ' + currentPage);
|
|
}
|
|
var msg = '\n [' + result.html.location.line + ', ' + result.brokenReason + '] ' + result.url.resolved;
|
|
fs.appendFileSync(outputFile, msg);
|
|
// gutil.log(msg);
|
|
// gutil.log(result);
|
|
},
|
|
|
|
page: function(error, pageUrl, customData){},
|
|
site: function(error, siteUrl, customData){},
|
|
|
|
end: function(){
|
|
var stopTime = new Date().getTime();
|
|
var elapsed = 'Elapsed link-checking time: ' + ((stopTime - startTime)/1000) + ' seconds';
|
|
gutil.log(elapsed);
|
|
fs.appendFileSync(outputFile, '\n'+elapsed);
|
|
gutil.log('Output in file: ' + outputFile);
|
|
deferred.resolve(true);
|
|
}
|
|
};
|
|
|
|
// create an output file with header.
|
|
var outputFile = path.join(process.cwd(), 'link-checker-results.txt');
|
|
var header = 'Link checker results for: ' + siteUrl +
|
|
'\nStarted: ' + (new Date()).toLocaleString() +
|
|
'\nExcluded links (blc file globs): ' + blcOptions.excludedKeywords +
|
|
'\nExcluded links (custom --exclude-bad regex): ' + excludeBad.toString() + '\n\n';
|
|
gutil.log(header);
|
|
fs.writeFileSync(outputFile, header);
|
|
|
|
var siteChecker = new blc.SiteChecker(blcOptions, handlers);
|
|
var startTime = new Date().getTime();
|
|
|
|
try {
|
|
gutil.log('link checker started');
|
|
siteChecker.enqueue(siteUrl, customData);
|
|
} catch (err) {
|
|
gutil.log('link checker died');
|
|
console.error('link checker died', err);
|
|
deferred.reject(err);
|
|
}
|
|
return deferred.promise;
|
|
}
|
|
|
|
// harp has issues with node_modules under the public dir
|
|
// but we need them there for example testing and development
|
|
// this method allows the node modules folder under '_examples'
|
|
// to be temporarily moved out from under 'public' while harp
|
|
// compilation is occurring.
|
|
function showHideExampleNodeModules(showOrHide) {
|
|
var nmPath = path.join(EXAMPLES_PATH, "/node_modules");
|
|
var nmHiddenPath = path.join(TEMP_PATH, "/node_modules");
|
|
if (showOrHide == 'hide' && fs.existsSync(nmPath)) {
|
|
if (!fs.existsSync(TEMP_PATH)) {
|
|
fs.mkdirSync(TEMP_PATH);
|
|
}
|
|
fs.renameSync(nmPath, nmHiddenPath);
|
|
} else if (showOrHide == 'show' && fs.existsSync(nmHiddenPath)) {
|
|
fs.renameSync(nmHiddenPath, nmPath);
|
|
fs.rmdirSync(TEMP_PATH);
|
|
}
|
|
}
|
|
|
|
// Show/hide the API docs harp source folder for every lang in skipLangs.
|
|
function showHideApiDir(showOrHide) {
|
|
skipLangs.forEach(lang => {
|
|
_showHideApiDir(lang, showOrHide);
|
|
});
|
|
}
|
|
|
|
// Rename the API docs harp source folder for lang to/from 'api' to '_api-tmp-foo'.
|
|
function _showHideApiDir(lang, showOrHide) {
|
|
const vers = 'latest';
|
|
const basePath = path.join(DOCS_PATH, lang, vers);
|
|
const apiDirPath = path.join(basePath, 'api');
|
|
const disabledApiDirPath = path.join(basePath, '_api-tmp-hide-from-jade');
|
|
const args = showOrHide == 'hide'
|
|
? [apiDirPath, disabledApiDirPath]
|
|
: [disabledApiDirPath, apiDirPath];
|
|
renameIfExistsSync(...args);
|
|
}
|
|
|
|
// For each lang in skipLangs, copy the API dir from ${WWW}-backup to WWW.
|
|
function restoreApiHtml() {
|
|
const vers = 'latest';
|
|
skipLangs.forEach(lang => {
|
|
const relApiDir = path.join('docs', lang, vers, 'api');
|
|
const apiSubdir = path.join(WWW, relApiDir);
|
|
const backupApiSubdir = path.join(`${WWW}-backup`, relApiDir);
|
|
if (fs.existsSync(backupApiSubdir) || argv.forceSkipApi !== true) {
|
|
gutil.log(`cp ${backupApiSubdir} ${apiSubdir}`)
|
|
fs.copySync(backupApiSubdir, apiSubdir);
|
|
}
|
|
});
|
|
}
|
|
|
|
// For each lang in skipLangs, ensure API dir exists in folderName
|
|
function backupApiHtmlFilesExist(folderName) {
|
|
const vers = 'latest';
|
|
var result = 1;
|
|
skipLangs.forEach(lang => {
|
|
const relApiDir = path.join('docs', lang, vers, 'api');
|
|
const backupApiSubdir = path.join(folderName, relApiDir);
|
|
if (!fs.existsSync(backupApiSubdir)) {
|
|
gutil.log(`WARNING: API docs HTML folder doesn't exist: ${backupApiSubdir}`);
|
|
result = 0;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
function harpJsonSetJade2NgTo(v) {
|
|
const harpJsonPath = path.join(ANGULAR_IO_PROJECT_PATH, 'harp.json');
|
|
execSync(`perl -pi -e 's/("jade2ng": *)\\w+/$1${v}/' ${harpJsonPath}`);
|
|
const harpJson = require(harpJsonPath);
|
|
gutil.log(`jade2ng: ${harpJson.globals.jade2ng}`);
|
|
}
|
|
|
|
// Copies fileNames into destPaths, setting the mode of the
|
|
// files at the destination as optional_destFileMode if given.
|
|
// returns a promise
|
|
function copyFiles(fileNames, destPaths, optional_destFileMode) {
|
|
var copy = Q.denodeify(fsExtra.copy);
|
|
var chmod = Q.denodeify(fsExtra.chmod);
|
|
var copyPromises = [];
|
|
destPaths.forEach(function(destPath) {
|
|
fileNames.forEach(function(fileName) {
|
|
var baseName = path.basename(fileName);
|
|
var destName = path.join(destPath, baseName);
|
|
var p = copy(fileName, destName, { clobber: true});
|
|
if(optional_destFileMode !== undefined) {
|
|
p = p.then(function () {
|
|
return chmod(destName, optional_destFileMode);
|
|
});
|
|
}
|
|
copyPromises.push(p);
|
|
});
|
|
});
|
|
return Q.all(copyPromises);
|
|
}
|
|
|
|
function deleteFiles(baseFileNames, destPaths) {
|
|
var remove = Q.denodeify(fsExtra.remove);
|
|
var delPromises = [];
|
|
destPaths.forEach(function(destPath) {
|
|
baseFileNames.forEach(function(baseFileName) {
|
|
var destFileName = path.join(destPath, baseFileName);
|
|
var p = remove(destFileName);
|
|
delPromises.push(p);
|
|
});
|
|
});
|
|
return Q.all(delPromises);
|
|
}
|
|
|
|
// TODO: filter out all paths that are subdirs of another
|
|
// path in the result.
|
|
function getE2eSpecPaths(basePath) {
|
|
var paths = getPaths(basePath, '*e2e-spec.+(js|ts)', true);
|
|
return _.uniq(paths);
|
|
}
|
|
|
|
function getNodeModulesPaths(basePath) {
|
|
var paths = getExamplePaths(basePath).map(function(examplePath) {
|
|
return path.join(examplePath, "/node_modules");
|
|
});
|
|
return paths;
|
|
}
|
|
|
|
function getExamplePaths(basePath, includeBase) {
|
|
// includeBase defaults to false
|
|
return getPaths(basePath, _exampleConfigFilename, includeBase);
|
|
}
|
|
|
|
function getDartExampleWebPaths(basePath) {
|
|
var paths = globby.sync([path.join(basePath,"**/dart/**/web")])
|
|
return paths;
|
|
}
|
|
|
|
function getUnitTestingPaths(basePath) {
|
|
var examples = getPaths(basePath, _exampleConfigFilename, true);
|
|
return examples.filter((example) => {
|
|
var exampleConfig = fs.readJsonSync(`${example}/${_exampleConfigFilename}`, {throws: false});
|
|
return exampleConfig && !!exampleConfig.unittesting;
|
|
});
|
|
}
|
|
|
|
function getPaths(basePath, filename, includeBase) {
|
|
var filenames = getFilenames(basePath, filename, includeBase);
|
|
var paths = filenames.map(function(fileName) {
|
|
return path.dirname(fileName);
|
|
});
|
|
return paths;
|
|
}
|
|
|
|
function getFilenames(basePath, filename, includeBase) {
|
|
// includeBase defaults to false
|
|
var includePatterns = [path.join(basePath, "**/" + filename)];
|
|
if (!includeBase) {
|
|
// ignore (skip) the top level version.
|
|
includePatterns.push("!" + path.join(basePath, "/" + filename));
|
|
}
|
|
// ignore (skip) the files in BOILERPLATE_PATH.
|
|
includePatterns.push("!" + path.join(BOILERPLATE_PATH, "/" + filename));
|
|
var nmPattern = path.join(basePath, "**/node_modules/**");
|
|
var filenames = globby.sync(includePatterns, {ignore: [nmPattern]});
|
|
return filenames;
|
|
}
|
|
|
|
function watchAndSync(options, cb) {
|
|
// Supposedly running in production makes harp faster
|
|
// and less likely to drown in node_modules.
|
|
env({
|
|
vars: { NODE_ENV: "production" }
|
|
});
|
|
|
|
execCommands(['npm run harp -- server .'], {}, cb);
|
|
|
|
var browserSync = require('browser-sync').create();
|
|
browserSync.init({proxy: 'localhost:9000'});
|
|
|
|
// When using the --focus=name flag, only **/name/**/*.* example files and
|
|
// **/name.jade files are watched. This is useful for performance reasons.
|
|
// Example: gulp serve-and-sync --focus=architecture
|
|
var focus = argv.focus;
|
|
|
|
if (options.devGuide) {
|
|
devGuideExamplesWatch(_devguideShredOptions, browserSync.reload, focus);
|
|
}
|
|
if (options.devGuideJade) {
|
|
devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload, focus);
|
|
}
|
|
if (options.apiDocs) {
|
|
apiSourceWatch(browserSync.reload);
|
|
}
|
|
if (options.apiExamples) {
|
|
apiExamplesWatch(browserSync.reload);
|
|
}
|
|
if (options.localFiles) {
|
|
gulp.watch(NOT_API_DOCS_GLOB, browserSync.reload);
|
|
}
|
|
}
|
|
|
|
// returns a promise;
|
|
function askDeploy() {
|
|
// Show user what the currently active firebase project is:
|
|
execSync('firebase use', {stdio:[0,1,2]});
|
|
prompt.start();
|
|
var schema = {
|
|
name: 'shouldDeploy',
|
|
description: `Deploy ${WWW} to firebase? (y/n)`,
|
|
type: 'string',
|
|
pattern: /Y|N|y|n/,
|
|
message: "Respond with either a 'y' or 'n'",
|
|
required: true
|
|
}
|
|
var getPromise = Q.denodeify(prompt.get);
|
|
return getPromise([schema]).then(function(result) {
|
|
return result.shouldDeploy.toLowerCase() === 'y';
|
|
});
|
|
}
|
|
|
|
|
|
function filterOutExcludedPatterns(fileNames, excludeMatchers) {
|
|
return fileNames.filter(function(fileName) {
|
|
return !excludeMatchers.some(function(excludeMatcher) {
|
|
return excludeMatcher.match(fileName);
|
|
});
|
|
});
|
|
}
|
|
|
|
function apiSourceWatch(postBuildAction) {
|
|
var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/**/*.*')];
|
|
gulp.watch(srcPattern, {readDelay: 500}, function (event, done) {
|
|
gutil.log('API source changed');
|
|
gutil.log('Event type: ' + event.event); // added, changed, or deleted
|
|
gutil.log('Event path: ' + event.path); // The path of the modified file
|
|
|
|
return Q.all([buildApiDocs('ts'), buildApiDocs('js')]).then(postBuildAction);
|
|
});
|
|
}
|
|
|
|
function apiExamplesWatch(postShredAction) {
|
|
var examplesPath = path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/examples/**');
|
|
var includePattern = path.join(examplesPath, '**/*.*');
|
|
var excludePattern = '!' + path.join(examplesPath, '**/node_modules/**/*.*');
|
|
var cleanPath = [path.join(_apiShredOptions.fragmentsDir, '**/*.*'), '!**/*.ovr.*'];
|
|
|
|
gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
|
|
gutil.log('API example changed');
|
|
gutil.log('Event type: ' + event.type); // added, changed, or deleted
|
|
gutil.log('Event path: ' + event.path); // The path of the modified file
|
|
|
|
return del(cleanPath).then(function() {
|
|
return docShredder.shred(_apiShredOptions);
|
|
}).then(postShredAction);
|
|
});
|
|
}
|
|
|
|
function devGuideExamplesWatch(shredOptions, postShredAction, focus) {
|
|
var watchPattern = focus ? '{' + focus + ',cb-' + focus+ '}/**/*.*' : '**/*.*';
|
|
var includePattern = path.join(shredOptions.examplesDir, watchPattern);
|
|
// removed this version because gulp.watch has the same glob issue that dgeni has.
|
|
// var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*');
|
|
// gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
|
|
var ignoreThese = [ '**/node_modules/**', '**/_fragments/**', '**/dist/**',
|
|
'**/dart/.pub/**', '**/dart/build/**', '**/dart/packages/**'];
|
|
ignoreThese = ignoreThese.concat(_exampleBoilerplateFiles.map((file) => `public/docs/_examples/*/*/${file}`));
|
|
var files = globby.sync( [includePattern], { ignore: ignoreThese });
|
|
gulp.watch([files], {readDelay: 500}, function (event, done) {
|
|
gutil.log('Dev Guide example changed')
|
|
gutil.log('Event type: ' + event.type); // added, changed, or deleted
|
|
gutil.log('Event path: ' + event.path); // The path of the modified file
|
|
return docShredder.shredSingleDir(shredOptions, event.path).then(postShredAction);
|
|
});
|
|
}
|
|
|
|
function devGuideSharedJadeWatch(shredOptions, postShredAction, focus) {
|
|
var watchPattern = focus ? '**/' + focus + '.jade' : '**/*.jade';
|
|
var includePattern = path.join(DOCS_PATH, watchPattern);
|
|
// removed this version because gulp.watch has the same glob issue that dgeni has.
|
|
// var excludePattern = '!' + path.join(shredOptions.jadeDir, '**/node_modules/**/*.*');
|
|
// gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
|
|
var ignoreThese = [ '**/node_modules/**', '**/_examples/**', '**/_fragments/**', '**/latest/api/**' ];
|
|
var files = globby.sync( [includePattern], { ignore: ignoreThese});
|
|
gulp.watch([files], {readDelay: 500}, function (event, done) {
|
|
gutil.log('Dev Guide jade file changed')
|
|
gutil.log('Event type: ' + event.type); // added, changed, or deleted
|
|
gutil.log('Event path: ' + event.path); // The path of the modified file
|
|
return docShredder.shredSingleJadeDir(shredOptions, event.path).then(postShredAction);
|
|
});
|
|
}
|
|
|
|
|
|
// Generate the API docs for the specified language, if not specified then it defaults to ts
|
|
function buildApiDocs(targetLanguage) {
|
|
var ALLOWED_LANGUAGES = ['ts', 'js', 'dart'];
|
|
var GENERATE_API_LANGUAGES = ['ts', 'js'];
|
|
checkAngularProjectPath();
|
|
try {
|
|
// Build a specialized package to generate different versions of the API docs
|
|
var package = new Package('apiDocs', [require(path.resolve(TOOLS_PATH, 'api-builder/angular.io-package'))]);
|
|
package.config(function(log, targetEnvironments, writeFilesProcessor, readTypeScriptModules, linkDocsInlineTagDef) {
|
|
log.level = _dgeniLogLevel;
|
|
ALLOWED_LANGUAGES.forEach(function(target) { targetEnvironments.addAllowed(target); });
|
|
if (targetLanguage) {
|
|
targetEnvironments.activate(targetLanguage);
|
|
|
|
if (GENERATE_API_LANGUAGES.indexOf(targetLanguage) === -1) {
|
|
// Don't read TypeScript modules if we are not generating API docs - Dart I am looking at you!
|
|
readTypeScriptModules.$enabled = false;
|
|
}
|
|
linkDocsInlineTagDef.lang = targetLanguage;
|
|
linkDocsInlineTagDef.vers = 'latest';
|
|
writeFilesProcessor.outputFolder = path.join(targetLanguage, linkDocsInlineTagDef.vers, 'api');
|
|
}
|
|
});
|
|
|
|
var dgeni = new Dgeni([package]);
|
|
return dgeni.generate();
|
|
} catch(err) {
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
|
|
function buildDartCheatsheet() {
|
|
'use strict';
|
|
const ALLOWED_LANGUAGES = ['ts', 'js', 'dart'];
|
|
const lang = 'dart';
|
|
const vers = 'latest';
|
|
checkAngularProjectPath(ngPathFor(lang));
|
|
try {
|
|
const pkg = new Package('dartApiDocs', [require(path.resolve(TOOLS_PATH, 'dart-api-builder'))]);
|
|
pkg.config(function(log, targetEnvironments, writeFilesProcessor) {
|
|
log.level = _dgeniLogLevel;
|
|
ALLOWED_LANGUAGES.forEach(function(target) { targetEnvironments.addAllowed(target); });
|
|
targetEnvironments.activate(lang);
|
|
const outputPath = path.join(lang, vers, 'can-be-any-name-read-comment-below');
|
|
// Note: cheatsheet data gets written to: outputPath + '/../guide';
|
|
writeFilesProcessor.outputFolder = outputPath;
|
|
});
|
|
var dgeni = new Dgeni([pkg]);
|
|
return dgeni.generate();
|
|
} catch(err) {
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
|
|
function buildApiDocsForDart() {
|
|
const vers = 'latest';
|
|
const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH);
|
|
const log = dab.log;
|
|
|
|
log.level = _dgeniLogLevel;
|
|
const dabInfo = dab.dartPkgConfigInfo;
|
|
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, 'api');
|
|
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), relDartDocApiDir);
|
|
// Exclude API entries for developer/internal libraries. Also exclude entries for
|
|
// the top-level catch all "angular2" library (otherwise every entry appears twice).
|
|
dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|testing|_|codegen|^angular2$/);
|
|
|
|
try {
|
|
checkAngularProjectPath(ngPathFor('dart'));
|
|
var destPath = dabInfo.ngIoDartApiDocPath;
|
|
var sourceDirs = fs.readdirSync(dabInfo.ngDartDocPath)
|
|
.filter(name => !name.match(/^index|^(?!angular2)|testing|codegen/))
|
|
.map(name => path.join(dabInfo.ngDartDocPath, name));
|
|
log.info(`Building Dart API pages for ${sourceDirs.length} libraries`);
|
|
|
|
return copyFiles(sourceDirs, [destPath]).then(() => {
|
|
log.debug('Finished copying', sourceDirs.length, 'directories from', dabInfo.ngDartDocPath, 'to', destPath);
|
|
|
|
const apiEntries = dab.loadApiDataAndSaveToApiListFile();
|
|
const tmpDocsPath = path.resolve(path.join(process.env.HOME, 'tmp/docs.json'));
|
|
if (argv.dumpDocsJson) fs.writeFileSync(tmpDocsPath, JSON.stringify(apiEntries, null, 2));
|
|
dab.createApiDataAndJadeFiles(apiEntries);
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
});
|
|
|
|
} catch(err) {
|
|
console.error(err);
|
|
console.error(err.stack);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
function buildShredMaps(shouldWrite) {
|
|
var options = {
|
|
devguideExamplesDir: _devguideShredOptions.examplesDir,
|
|
apiExamplesDir: _apiShredOptions.examplesDir,
|
|
fragmentsDir: _devguideShredOptions.fragmentsDir,
|
|
jadeDir: './public/docs',
|
|
outputDir: './public/docs',
|
|
writeFilesEnabled: shouldWrite,
|
|
logLevel: _dgeniLogLevel
|
|
};
|
|
return docShredder.buildShredMap(options).then(function(docs) {
|
|
return docs;
|
|
});
|
|
}
|
|
|
|
// returns a promise containing filePaths with any changed or added examples;
|
|
function getChangedExamples(sha) {
|
|
var Git = require("nodegit");
|
|
var examplesPath = _devguideShredOptions.examplesDir;
|
|
var relativePath = path.relative(process.cwd(), examplesPath);
|
|
return Git.Repository.open(".").then(function(repo) {
|
|
if (sha.length) {
|
|
return repo.getCommit(sha);
|
|
} else {
|
|
return repo.getHeadCommit();
|
|
}
|
|
}).then(function(commit) {
|
|
return getChangedExamplesForCommit(commit, relativePath);
|
|
}).catch(function(err) {
|
|
|
|
});
|
|
}
|
|
|
|
function getChangedExamplesAfter(date, relativePath) {
|
|
var Git = require("nodegit");
|
|
var examplesPath = _devguideShredOptions.examplesDir;
|
|
var relativePath = path.relative(process.cwd(), examplesPath);
|
|
return Git.Repository.open(".").then(function(repo) {
|
|
return repo.getHeadCommit();
|
|
}).then(function(commit) {
|
|
var repo = commit.owner();
|
|
var revWalker = repo.createRevWalk();
|
|
revWalker.sorting(Git.Revwalk.SORT.TIME);
|
|
revWalker.push(commit.id());
|
|
return revWalker.getCommitsUntil(function (commit) {
|
|
return commit.date().getTime() > date.getTime();
|
|
});
|
|
}).then(function(commits) {
|
|
return Q.all(commits.map(function(commit) {
|
|
return getChangedExamplesForCommit(commit, relativePath);
|
|
}));
|
|
}).then(function(arrayOfPaths) {
|
|
var pathMap = {};
|
|
arrayOfPaths.forEach(function(paths) {
|
|
paths.forEach(function(path) {
|
|
pathMap[path] = true;
|
|
});
|
|
});
|
|
var uniqPaths = _.keys(pathMap);
|
|
return uniqPaths;
|
|
}).catch(function(err) {
|
|
var x = err;
|
|
});
|
|
|
|
}
|
|
|
|
function getChangedExamplesForCommit(commit, relativePath) {
|
|
return commit.getDiff().then(function(diffList) {
|
|
var filePaths = [];
|
|
diffList.forEach(function (diff) {
|
|
diff.patches().then(function (patch) {
|
|
if (patch.isAdded() || patch.isModified) {
|
|
var filePath = path.normalize(patch.newFile().path());
|
|
var isExample = filePath.indexOf(relativePath) >= 0;
|
|
// gutil.log(filePath + " isExample: " + isExample);
|
|
if (isExample) {
|
|
filePaths.push(filePath);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
return filePaths;
|
|
});
|
|
}
|
|
|
|
|
|
|
|
function jadeShredMapToJadeExampleMap(jadeShredMap, examplePaths) {
|
|
// remove dups in examplePaths
|
|
var exampleSet = {};
|
|
examplePaths.forEach(function(examplePath) {
|
|
exampleSet[examplePath] = examplePath;
|
|
});
|
|
var basePath = path.resolve(".");
|
|
var jadeToFragMap = jadeShredMap.jadeToFragMap;
|
|
var jadeExampleMap = {};
|
|
for (var jadePath in jadeToFragMap) {
|
|
var relativeJadePath = path.relative(basePath, jadePath);
|
|
var vals = jadeToFragMap[jadePath];
|
|
vals.forEach(function(val) {
|
|
var relativeExamplePath = path.relative(basePath, val.examplePath);
|
|
if (exampleSet[relativeExamplePath] != null) {
|
|
addKeyValue(jadeExampleMap, relativeJadePath, relativeExamplePath);
|
|
}
|
|
});
|
|
}
|
|
return jadeExampleMap;
|
|
}
|
|
|
|
function jadeShredMapToExampleJadeMap(jadeShredMap) {
|
|
|
|
var jadeToFragMap = jadeShredMap.jadeToFragMap;
|
|
var exampleJadeMap = {};
|
|
for (var jadePath in jadeToFragMap) {
|
|
var vals = jadeToFragMap[jadePath];
|
|
vals.forEach(function(val) {
|
|
var examplePath = val.examplePath;
|
|
addKeyValue(exampleJadeMap, examplePath, jadePath);
|
|
});
|
|
}
|
|
return exampleJadeMap;
|
|
}
|
|
|
|
function addKeyValue(map, key, value) {
|
|
var vals = map[key];
|
|
if (vals) {
|
|
if (vals.indexOf(value) == -1) {
|
|
vals.push(value);
|
|
}
|
|
} else {
|
|
map[key] = [value];
|
|
}
|
|
}
|
|
|
|
|
|
// Synchronously execute a chain of commands.
|
|
// cmds: an array of commands
|
|
// options: { shouldLog: true, shouldThrow: true }
|
|
// cb: function(err, stdout, stderr)
|
|
function execCommands(cmds, options, cb) {
|
|
options = options || {};
|
|
options.shouldThrow = options.shouldThrow == null ? true : options.shouldThrow;
|
|
options.shouldLog = options.shouldLog == null ? true : options.shouldLog;
|
|
if (!cmds || cmds.length == 0) cb(null, null, null);
|
|
var exec = require('child_process').exec; // just to make it more portable.
|
|
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
|
|
|
|
exec(cmds[0], options, function(err, stdout, stderr) {
|
|
if (err == null) {
|
|
if (options.shouldLog) {
|
|
gutil.log('cmd: ' + cmds[0]);
|
|
gutil.log('stdout: ' + stdout);
|
|
}
|
|
if (cmds.length == 1) {
|
|
cb(err, stdout, stderr);
|
|
} else {
|
|
execCommands(cmds.slice(1), options, cb);
|
|
}
|
|
} else {
|
|
if (options.shouldLog) {
|
|
gutil.log('exec error on cmd: ' + cmds[0]);
|
|
gutil.log('exec error: ' + err);
|
|
if (stdout) gutil.log('stdout: ' + stdout);
|
|
if (stderr) gutil.log('stderr: ' + stderr);
|
|
}
|
|
if (err && options.shouldThrow) throw err;
|
|
cb(err, stdout, stderr);
|
|
}
|
|
});
|
|
}
|
|
|
|
function ngPathFor(lang) {
|
|
return ANGULAR_PROJECT_PATH + (lang === 'dart' ? '-dart' : '');
|
|
}
|
|
|
|
function checkAngularProjectPath(_ngPath) {
|
|
var ngPath = path.resolve(_ngPath || ngPathFor('ts'));
|
|
if (fs.existsSync(ngPath)) return;
|
|
throw new Error('API related tasks require the angular2 repo to be at ' + ngPath);
|
|
}
|
|
|
|
function renameIfExistsSync(oldPath, newPath) {
|
|
if (fs.existsSync(oldPath)) {
|
|
gutil.log(`Rename: mv ${oldPath} ${newPath}`);
|
|
fs.renameSync(oldPath, newPath);
|
|
} else {
|
|
gutil.log(`renameIfExistsSync cannot rename, path not found: ${oldPath}`);
|
|
}
|
|
}
|