import { task , src , dest } from 'gulp' ; import { Dgeni } from 'dgeni' ; import * as path from 'path' ; import { buildConfig , sequenceTask } from 'material2-build-tools' ; import { apiDocsPackage } from '../../dgeni/index' ; const markdown = require ( 'gulp-markdown' ) ; const transform = require ( 'gulp-transform' ) ; const highlight = require ( 'gulp-highlight-files' ) ; const rename = require ( 'gulp-rename' ) ; const flatten = require ( 'gulp-flatten' ) ; const htmlmin = require ( 'gulp-htmlmin' ) ; const hljs = require ( 'highlight.js' ) ; const dom = require ( 'gulp-dom' ) ; const { outputDir , packagesDir } = buildConfig ; const DIST_DOCS = path . join ( outputDir , 'docs' ) ; const EXAMPLE_PATTERN = /<!--\W*example\(([^)]+)\)\W*-->/g ; const LINK_PATTERN = /(<a[^>]*) href="([^"]*)"/g ; const MARKDOWN_TAGS_TO_CLASS_ALIAS = [ 'a' , 'h1' , 'h2' , 'h3' , 'h4' , 'h5' , 'li' , 'ol' , 'p' , 'table' , 'tbody' , 'td' , 'th' , 'tr' , 'ul' , 'pre' , 'code' , ] ; const htmlMinifierOptions = { collapseWhitespace : true , removeComments : true , caseSensitive : true , removeAttributeQuotes : false } ; const markdownOptions = { highlight : ( code , language ) : string => { if ( language ) { let lang = language . toLowerCase ( ) === 'ts' ? 'typescript' : language ; return hljs . highlight ( lang , code ) . value ; } return code ; } } ; /** Generate all docs content. */ task ( 'docs' , sequenceTask ( [ 'markdown-docs-material' , 'markdown-docs-cdk' , 'build-highlighted-examples' , 'build-examples-module' , 'api-docs' , 'copy-stackblitz-examples' ] , 'minify-html-files' ) ) ; /** Generates html files from the markdown overviews and guides for material. */ task ( 'markdown-docs-material' , ( ) => { markdown . marked . Renderer . prototype . heading = ( text , level ) : string => { if ( level === 3 || level === 4 ) { const escapedText = text . toLowerCase ( ) . replace ( /[^\w]+/g , '-' ) ; return `
        <h${ level } id="${ escapedText }" class="docs-header-link">
          <span header-link="${ escapedText }"></span>
          ${ text }
        </h${ level }>
      ` ; } else { return `<h${ level }>${ text }</h${ level }>` ; } } ; return src ( [ 'src/lib/**/!(README).md' , 'guides/*.md' ] ) . pipe ( rename ( { prefix : 'material-' } ) ) . pipe ( markdown ( markdownOptions ) ) . pipe ( transform ( transformMarkdownFiles ) ) . pipe ( dom ( createTagNameAliaser ( 'docs-markdown' ) ) ) . pipe ( dest ( 'dist/docs/markdown' ) ) ; } ) ; /** Generates html files from the markdown overviews and guides for the cdk. */ task ( 'markdown-docs-cdk' , ( ) => { return src ( [ 'src/cdk/**/!(README).md' ] ) . pipe ( rename ( { prefix : 'cdk-' } ) ) . pipe ( markdown ( markdownOptions ) ) . pipe ( transform ( transformMarkdownFiles ) ) . pipe ( dom ( createTagNameAliaser ( 'docs-markdown' ) ) ) . pipe ( dest ( 'dist/docs/markdown' ) ) ; } ) ; /**
 * Creates syntax-highlighted html files from the examples to be used for the source view of
 * live examples on the docs site.
 */ task ( 'build-highlighted-examples' , ( ) => { const renameFile = ( filePath ) => { const extension = filePath . extname . slice ( 1 ) ; filePath . basename = `${ filePath . basename }-${ extension }` ; } ; return src ( 'src/material-examples/**/*.+(html|css|ts)' ) . pipe ( flatten ( ) ) . pipe ( rename ( renameFile ) ) . pipe ( highlight ( ) ) . pipe ( dest ( 'dist/docs/examples' ) ) ; } ) ; /** Generates API docs from the source JsDoc using dgeni. */ task ( 'api-docs' , ( ) => { const docs = new Dgeni ( [ apiDocsPackage ] ) ; return docs . generate ( ) ; } ) ; /**
 * Minifies all HTML files that have been generated. The HTML files for the
 * highlighted examples can be skipped, because it won't have any effect.
 */ task ( 'minify-html-files' , ( ) => { return src ( 'dist/docs/+(api|markdown)/**/*.html' ) . pipe ( htmlmin ( htmlMinifierOptions ) ) . pipe ( dest ( 'dist/docs' ) ) ; } ) ; /** Copies example sources to be used as stackblitz assets for the docs site. */ task ( 'copy-stackblitz-examples' , ( ) => { src ( path . join ( packagesDir , 'material-examples' , '**/*' ) ) . pipe ( dest ( path . join ( DIST_DOCS , 'stackblitz' , 'examples' ) ) ) ; } ) ; /** Updates the markdown file's content to work inside of the docs app. */ function transformMarkdownFiles ( buffer , file ) { let content = buffer . toString ( 'utf-8' ) ; content = content . replace ( EXAMPLE_PATTERN , ( _match , name ) => `<div material-docs-example="${ name }"></div>` ) ; content = content . replace ( LINK_PATTERN , ( _match , head , link ) => `${ head } href="${ fixMarkdownDocLinks ( link , file . path ) }"` ) ; return `<div class="docs-markdown">${ content }</div>` ; } /** Fixes paths in the markdown files to work in the material-docs-io. */ function fixMarkdownDocLinks ( link , filePath ) { if ( ! filePath . includes ( path . normalize ( 'guides/' ) ) || link . startsWith ( 'http' ) ) { return link ; } let baseName = path . basename ( link , path . extname ( link ) ) ; return `guide/${ baseName }` ; } param classPrefix function createTagNameAliaser ( classPrefix ) { return function ( this ) { MARKDOWN_TAGS_TO_CLASS_ALIAS . forEach ( tag => { Array . from ( this . querySelectorAll ( tag ) ) . forEach ( el => { el . classList . add ( `${ classPrefix }-${ tag }` ) ; } ) ; } ) ; return this ; } ; }