UNPKG

ipsos-components

Version:

Material Design components for Angular

212 lines (184 loc) 7.41 kB
import {task, src, dest} from 'gulp'; import {Dgeni} from 'dgeni'; import * as path from 'path'; import {buildConfig} from 'material2-build-tools'; import {apiDocsPackage} from '../../dgeni/index'; // There are no type definitions available for these imports. 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'); // Our docs contain comments of the form `<!-- example(...) -->` which serve as placeholders where // example code should be inserted. We replace these comments with divs that have a // `material-docs-example` attribute which can be used to locate the divs and initialize the example // viewer. const EXAMPLE_PATTERN = /<!--\W*example\(([^)]+)\)\W*-->/g; // Markdown files can contain links to other markdown files. // Most of those links don't work in the Material docs, because the paths are invalid in the // documentation page. Using a RegExp to rewrite links in HTML files to work in the docs. const LINK_PATTERN = /(<a[^>]*) href="([^"]*)"/g; // HTML tags in the markdown generated files that should receive a .docs-markdown-${tagName} class // for styling purposes. const MARKDOWN_TAGS_TO_CLASS_ALIAS = [ 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'li', 'ol', 'p', 'table', 'tbody', 'td', 'th', 'tr', 'ul', 'pre', 'code', ]; // Options for the html-minifier that minifies the generated HTML files. const htmlMinifierOptions = { collapseWhitespace: true, removeComments: true, caseSensitive: true, removeAttributeQuotes: false }; const markdownOptions = { // Add syntax highlight using highlight.js highlight: (code: string, language: string): string => { if (language) { // highlight.js expects "typescript" written out, while Github supports "ts". let lang = language.toLowerCase() === 'ts' ? 'typescript' : language; return hljs.highlight(lang, code).value; } return code; } }; /** Generate all docs content. */ task('docs', [ 'markdown-docs', 'markdown-docs-cdk', 'highlight-examples', 'api-docs', 'minified-api-docs', 'build-examples-module', 'stackblitz-example-assets', ]); /** Generates html files from the markdown overviews and guides for material. */ task('markdown-docs', () => { // Extend the renderer for custom heading anchor rendering markdown.marked.Renderer.prototype.heading = (text: string, level: number): 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')); }); // TODO(jelbourn): figure out how to avoid duplicating this task w/ material while still // disambiguating the output. /** 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('highlight-examples', () => { // rename files to fit format: [filename]-[filetype].html const renameFile = (filePath: any) => { 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(); }); /** Generates minified html api docs. */ task('minified-api-docs', ['api-docs'], () => { return src('dist/docs/api/*.html') .pipe(htmlmin(htmlMinifierOptions)) .pipe(dest('dist/docs/api/')); }); /** Copies example sources to be used as stackblitz assets for the docs site. */ task('stackblitz-example-assets', () => { 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: Buffer, file: any): string { let content = buffer.toString('utf-8'); // Replace <!-- example(..) --> comments with HTML elements. content = content.replace(EXAMPLE_PATTERN, (_match: string, name: string) => `<div material-docs-example="${name}"></div>` ); // Replace the URL in anchor elements inside of compiled markdown files. content = content.replace(LINK_PATTERN, (_match: string, head: string, link: string) => // The head is the first match of the RegExp and is necessary to ensure that the RegExp matches // an anchor element. The head will be then used to re-create the existing anchor element. // If the head is not prepended to the replaced value, then the first match will be lost. `${head} href="${fixMarkdownDocLinks(link, file.path)}"` ); // Finally, wrap the entire generated in a doc in a div with a specific class. return `<div class="docs-markdown">${content}</div>`; } /** Fixes paths in the markdown files to work in the material-docs-io. */ function fixMarkdownDocLinks(link: string, filePath: string): string { // As for now, only markdown links that are relative and inside of the guides/ directory // will be rewritten. if (!filePath.includes(path.normalize('guides/')) || link.startsWith('http')) { return link; } let baseName = path.basename(link, path.extname(link)); // Temporary link the file to the /guide URL because that's the route where the // guides can be loaded in the Material docs. return `guide/${baseName}`; } /** * Returns a function to be called with an HTML document as its context that aliases HTML tags by * adding a class consisting of a prefix + the tag name. * @param classPrefix The prefix to use for the alias class. */ function createTagNameAliaser(classPrefix: string) { return function() { MARKDOWN_TAGS_TO_CLASS_ALIAS.forEach(tag => { for (let el of this.querySelectorAll(tag)) { el.classList.add(`${classPrefix}-${tag}`); } }); return this; }; }