diff --git a/.gitignore b/.gitignore index c69d33ad83..cc4dc77b6e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,4 @@ plnkr.html *plnkr.no-link.html public/docs/*/latest/guide/cheatsheet.json protractor-results.txt - - - +link-checker-results.txt diff --git a/gulpfile.js b/gulpfile.js index 82162b7610..a005d1c5b8 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -23,6 +23,7 @@ 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"); // TODO: // 1. Think about using runSequence @@ -424,6 +425,13 @@ 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) { + return linkChecker(); +}); + // Internal tasks gulp.task('set-prod-env', function () { @@ -514,6 +522,80 @@ function harpCompile() { return deferred.promise; } +function linkChecker(options) { + var deferred = Q.defer(); + var options = options || {}; + + var blcOptions = options.blcOptions || {}; + var customData = options.customData || {}; + + var excludeBad; // don't bother reporting bad links matching this RegExp + if (argv.excludeBad) { + excludeBad = new RegExp(argv.excludeBad); + } else { + excludeBad = options.excludeBad === undefined ? /docs\/dart\/latest\/api/ : ''; + } + + 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);docs/ts/latest/api/core/ + }, + 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() + + '\nSkipping bad links matching 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 { + siteChecker.enqueue(siteUrl, customData); + } catch (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' diff --git a/package.json b/package.json index 2fd87fa130..a870ecd786 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "devDependencies": { "archiver": "^0.16.0", "assert-plus": "^0.1.5", + "broken-link-checker":"0.7.0", "browser-sync": "^2.9.3", "canonical-path": "0.0.2", "cross-spawn": "^2.1.0", diff --git a/public/docs/dart/latest/tutorial/testing/_data.json b/public/docs/dart/latest/testing/_data.json similarity index 100% rename from public/docs/dart/latest/tutorial/testing/_data.json rename to public/docs/dart/latest/testing/_data.json diff --git a/public/docs/dart/latest/tutorial/testing/application-under-test.jade b/public/docs/dart/latest/testing/application-under-test.jade similarity index 100% rename from public/docs/dart/latest/tutorial/testing/application-under-test.jade rename to public/docs/dart/latest/testing/application-under-test.jade diff --git a/public/docs/dart/latest/tutorial/testing/first-app-tests.jade b/public/docs/dart/latest/testing/first-app-tests.jade similarity index 100% rename from public/docs/dart/latest/tutorial/testing/first-app-tests.jade rename to public/docs/dart/latest/testing/first-app-tests.jade diff --git a/public/docs/dart/latest/tutorial/testing/index.jade b/public/docs/dart/latest/testing/index.jade similarity index 100% rename from public/docs/dart/latest/tutorial/testing/index.jade rename to public/docs/dart/latest/testing/index.jade diff --git a/public/docs/dart/latest/tutorial/testing/jasmine-testing-101.jade b/public/docs/dart/latest/testing/jasmine-testing-101.jade similarity index 100% rename from public/docs/dart/latest/tutorial/testing/jasmine-testing-101.jade rename to public/docs/dart/latest/testing/jasmine-testing-101.jade diff --git a/public/docs/dart/latest/tutorial/testing/testing-an-angular-pipe.jade b/public/docs/dart/latest/testing/testing-an-angular-pipe.jade similarity index 100% rename from public/docs/dart/latest/tutorial/testing/testing-an-angular-pipe.jade rename to public/docs/dart/latest/testing/testing-an-angular-pipe.jade diff --git a/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade b/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade index 8f9f4c1ee8..5ce28ad2d3 100644 --- a/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade +++ b/public/docs/ts/latest/cookbook/a1-a2-quick-reference.jade @@ -295,7 +295,7 @@ table(width="100%") In this example, the `table` element is removed from the DOM unless the `movies` array has a length. The (*) before `ngIf` is required in this example. - For more information see [Structural Directives](../guide/structural-directives). + For more information see [Structural Directives](../guide/structural-directives.html). tr(style=top) td :marked @@ -342,7 +342,7 @@ table(width="100%") the (#) identifies `movie` as a local variable; the list preposition is `of`, not `in`. - For more information see [Structural Directives](../guide/structural-directives). + For more information see [Structural Directives](../guide/structural-directives.html). tr(style=top) td :marked diff --git a/public/docs/ts/latest/cookbook/component-communication.jade b/public/docs/ts/latest/cookbook/component-communication.jade index 02f040b4c2..83103e623d 100644 --- a/public/docs/ts/latest/cookbook/component-communication.jade +++ b/public/docs/ts/latest/cookbook/component-communication.jade @@ -38,7 +38,7 @@ include ../_util-fns ## Pass data from parent to child with input binding `HeroChildComponent` has two ***input properties***, - typically adorned with [@Input decorations](docs/ts/latest/guide/template-syntax.html#inputs-outputs). + typically adorned with [@Input decorations](/docs/ts/latest/guide/template-syntax.html#inputs-outputs). +makeExample('cb-component-communication/ts/app/hero-child.component.ts') :marked @@ -142,7 +142,7 @@ figure.image-display The parent binds to that event property and reacts to those events. The child's `EventEmitter` property is an ***output property***, - typically adorned with an [@Output decoration](docs/ts/latest/guide/template-syntax.html#inputs-outputs) + typically adorned with an [@Output decoration](/docs/ts/latest/guide/template-syntax.html#inputs-outputs) as seen in this `VoterComponent`: +makeExample('cb-component-communication/ts/app/voter.component.ts') diff --git a/public/docs/ts/latest/guide/architecture.jade b/public/docs/ts/latest/guide/architecture.jade index 9cdc0e6b6d..5b47344b7a 100644 --- a/public/docs/ts/latest/guide/architecture.jade +++ b/public/docs/ts/latest/guide/architecture.jade @@ -403,7 +403,7 @@ figure Here's an example of a service class that logs to the browser console +makeExample('architecture/ts/app/logger.service.ts', 'class', 'app/logger.service.ts (class only)')(format=".") :marked - Here's a `HeroService` that fetches heroes and returns them in a resolved [promise](http://www.html5rocks.com/en/tutorials/es6/promises/). + Here's a `HeroService` that fetches heroes and returns them in a resolved [promise](http://www.2ality.com/2014/10/es6-promises-api.html). The `HeroService` depends on the `LoggerService` and another `BackendService` that handles the server communication grunt work. +makeExample('architecture/ts/app/hero.service.ts', 'class', 'app/hero.service.ts (class only)')(format=".") :marked diff --git a/public/docs/ts/latest/guide/forms.jade b/public/docs/ts/latest/guide/forms.jade index f6f43cc633..51caf087d3 100644 --- a/public/docs/ts/latest/guide/forms.jade +++ b/public/docs/ts/latest/guide/forms.jade @@ -581,7 +581,7 @@ figure.image-display .l-sub-section :marked ### The NgForm directive - What `NgForm` directive? We didn't add an [NgForm](../api/core/NgForm-class.html) directive! + What `NgForm` directive? We didn't add an [NgForm](../api/common/NgForm-directive.html) directive! Angular did. Angular creates and attaches an `NgForm` directive to the `
` tag automatically. diff --git a/public/docs/ts/latest/guide/pipes.jade b/public/docs/ts/latest/guide/pipes.jade index bf81de9b22..256b557695 100644 --- a/public/docs/ts/latest/guide/pipes.jade +++ b/public/docs/ts/latest/guide/pipes.jade @@ -85,7 +85,7 @@ figure.image-display .l-sub-section :marked - Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html). + Learn more about the `DatePipes` format options in the [API Docs](../api/common/DatePipe-class.html). :marked ## Chaining pipes We can chain pipes together in potentially useful combinations. diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade index 9bd9d1a70a..1b80d9c909 100644 --- a/public/docs/ts/latest/guide/router.jade +++ b/public/docs/ts/latest/guide/router.jade @@ -895,7 +895,7 @@ code-example(format=""). ### Router Lifecycle Hooks Angular components have [lifecycle hooks](lifecycle-hooks.html). For example, Angular calls the hook methods of the - [OnInit](../api/core/OnInit-interface.html) and [OnDestroy]((../api/core/OnDestroy-interface.html) + [OnInit](../api/core/OnInit-interface.html) and [OnDestroy](../api/core/OnDestroy-interface.html) interfaces when it creates and destroys components. The router calls similar hook methods, @@ -954,7 +954,7 @@ code-example(format=""). :marked The `DialogService` (injected in the `AppComponent` for app-wide use) does the asking. - It returns a [promise](http://www.html5rocks.com/en/tutorials/es6/promises/) that + It returns a [promise](http://www.2ality.com/2014/10/es6-promises-api.html) that *resolves* when the user eventually decides what to do: either to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`). diff --git a/public/license b/public/license new file mode 100644 index 0000000000..51b127e827 --- /dev/null +++ b/public/license @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2014-2016 Google, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.