// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes var path = require('canonical-path'); var Q = require('q'); var del = require('del'); // delPromise is a 'promise' version of del var delPromise = Q.denodeify(del); var Dgeni = require('dgeni'); var _ = require('lodash'); var globby = require('globby'); var shred = function(shredOptions) { try { var pkg; if (shredOptions.jadeDir) { pkg = createShredJadePackage(shredOptions); } else { pkg = createShredExamplePackage(shredOptions); } var dgeni = new Dgeni([ pkg]); return dgeni.generate(); } catch(err) { console.log(err); console.log(err.stack); throw err; } } var shredSingleDir = function(shredOptions, filePath) { shredOptions = resolveShredOptions(shredOptions); var fileDir = path.dirname(filePath); var relativePath = path.relative(shredOptions.examplesDir, fileDir); var examplesDir = path.join(shredOptions.examplesDir, relativePath); var fragmentsDir = path.join(shredOptions.fragmentsDir, relativePath); var options = { includeSubdirs: false, examplesDir: examplesDir, fragmentsDir: fragmentsDir } var cleanPath = path.join(fragmentsDir, '*.*') return delPromise([ cleanPath, '!**/*.ovr.*']).then(function(paths) { // console.log('Deleted files/folders:\n', paths.join('\n')); return shred(options); }); } var shredSingleJadeDir = function(shredOptions, filePath) { shredOptions = resolveShredOptions(shredOptions); var fileDir = path.dirname(filePath); var relativePath = path.relative(shredOptions.jadeDir, fileDir); var jadeDir = path.join(shredOptions.jadeDir, relativePath); var options = { includeSubdirs: false, jadeDir: jadeDir } // var cleanPath = path.join(jadeDir, '_.*.jade') //return delPromise([ cleanPath]).then(function(paths) { // console.log('Deleted files/folders:\n', paths.join('\n')); // return shred(options); //}); return shred(options); } var buildShredMap = function(shredMapOptions) { try { var pkg = createShredMapPackage(shredMapOptions); var dgeni = new Dgeni([ pkg]); return dgeni.generate(); } catch(err) { console.log(err); console.log(err.stack); throw err; } } module.exports = { shred: shred, shredSingleDir: shredSingleDir, shredSingleJadeDir: shredSingleJadeDir, buildShredMap: buildShredMap }; function createShredExamplePackage(shredOptions) { var pkg = new Dgeni.Package('doc-shredder', [ // require('dgeni-packages/base') - doesn't work ]); var options = resolveShredOptions(shredOptions); initializePackage(pkg) .factory(require('./fileReaders/regionFileReader')) .processor(require('./processors/renderAsMarkdownProcessor')) .config(function(readFilesProcessor, regionFileReader) { readFilesProcessor.fileReaders = [regionFileReader]; }) // default configs - may be overridden .config(function(readFilesProcessor) { // Specify the base path used when resolving relative paths to source and output files readFilesProcessor.basePath = "/"; // Specify collections of source files that should contain the documentation to extract var extns = ['*.ts', '*.html', '*.js', '*.css', '*.json', '*.dart', '*.yaml' ]; var includeFiles = extns.map(function(extn) { if (options.includeSubdirs) { return path.join(options.examplesDir, '**', extn); } else { return path.join(options.examplesDir, extn); } }); // HACK ( next two lines) because the glob function that dgeni uses internally isn't good at removing 'node_modules' early // this just uses globby to 'preglob' the include files ( and exclude the node_modules). var nmPattern = '**/node_modules/**'; var includeFiles = globby.sync( includeFiles, { ignore: [nmPattern] } ); readFilesProcessor.sourceFiles = [ { // Process all candidate files in `src` and its subfolders ... include: includeFiles , exclude: [ '**/node_modules/**', '**/typings/**', '**/packages/**', '**/build/**'], // When calculating the relative path to these files use this as the base path. // So `src/foo/bar.js` will have relative path of `foo/bar.js` basePath: options.examplesDir } ]; }) .config(function(writeFilesProcessor) { // Specify where the writeFilesProcessor will write our generated doc files writeFilesProcessor.outputFolder = path.resolve(options.fragmentsDir); }); return pkg; } function createShredJadePackage(shredOptions) { var pkg = new Dgeni.Package('jade-doc-shredder', [ // require('dgeni-packages/base') - doesn't work ]); var options = shredOptions; options.jadeDir = path.resolve(options.jadeDir); options.includeSubdirs = options.includeSubdirs == null ? true : options.includeSubdirs; initializePackage(pkg) .factory(require('./fileReaders/regionFileReader')) .processor(require('./processors/renderAsJadeProcessor')) .config(function(readFilesProcessor, regionFileReader) { readFilesProcessor.fileReaders = [regionFileReader]; }) // default configs - may be overridden .config(function(readFilesProcessor) { // Specify the base path used when resolving relative paths to source and output files readFilesProcessor.basePath = "/"; // Specify collections of source files that should contain the documentation to extract var extns = ['*.jade' ]; var includeFiles = extns.map(function(extn) { if (options.includeSubdirs) { return path.join(options.jadeDir, '**', extn); } else { return path.join(options.jadeDir, extn); } }); // HACK ( next two lines) because the glob function that dgeni uses internally isn't good at removing 'node_modules' early // this just uses globby to 'preglob' the include files ( and exclude the node_modules). var nmPattern = '**/node_modules/**'; var includeFiles = globby.sync( includeFiles, { ignore: [nmPattern] } ); readFilesProcessor.sourceFiles = [ { // Process all candidate files in `src` and its subfolders ... include: includeFiles , exclude: [ '**/node_modules/**', '**/typings/**', '**/packages/**', '**/build/**', '**/_code-examples.jade'], // When calculating the relative path to these files use this as the base path. // So `src/foo/bar.js` will have relative path of `foo/bar.js` basePath: options.jadeDir } ]; }) .config(function(writeFilesProcessor) { // Specify where the writeFilesProcessor will write our generated doc files writeFilesProcessor.outputFolder = '.'; }); return pkg; } var createShredMapPackage = function(mapOptions) { var pkg = new Dgeni.Package('doc-shred-mapper', [ require('dgeni-packages/base'), require('dgeni-packages/nunjucks') ]); var options = resolveMapOptions(mapOptions); initializePackage(pkg) .factory(require('./fileReaders/extractPathsReader')) .processor(require('./processors/shredMapProcessor')) .config(function(shredMapProcessor) { shredMapProcessor.options = options; }) .config(function(readFilesProcessor, extractPathsReader ) { readFilesProcessor.fileReaders = [ extractPathsReader]; }) // default configs - may be overriden .config(function(readFilesProcessor) { // Specify the base path used when resolving relative paths to source and output files readFilesProcessor.basePath = '/'; // Specify collections of source files that should contain the documentation to extract var extns = ['*.jade' ]; var includeFiles = extns.map(function(extn) { if (options.includeSubdirs) { return path.join(options.jadeDir, '**', extn); } else { return path.join(options.jadeDir, extn); } }); // HACK ( next two lines) because the glob function that dgeni uses internally isn't good at removing 'node_modules' early // this just uses globby to 'preglob' the include files ( and exclude the node_modules). var nmPattern = '**/node_modules/**'; var includeFiles = globby.sync( includeFiles, { ignore: [nmPattern] } ); readFilesProcessor.sourceFiles = [ { // Process all candidate files in `src` and its subfolders ... include: includeFiles, exclude: ['**/node_modules/**', '**/typings/**', '**/packages/**', '**/build/**'], // When calculating the relative path to these files use this as the base path. // So `src/foo/bar.js` will have relative path of `foo/bar.js` basePath: options.jadeDir } ]; }) .config(function(writeFilesProcessor, renderDocsProcessor, unescapeCommentsProcessor) { if (!mapOptions.writeFilesEnabled) { // dgeni hack to allow a geni task to simply return the results of the shredMapProcessor directly renderDocsProcessor.$enabled = false; writeFilesProcessor.$enabled = false; unescapeCommentsProcessor.$enabled = false; } else { // Specify where the writeFilesProcessor will write our generated doc files writeFilesProcessor.outputFolder = path.resolve(options.outputDir); } }) .config(function(templateFinder) { // look for templates in this folder templateFinder.templateFolders = [ path.resolve(__dirname) ]; // Specify how to match docs to templates. // In this case we just use the same static template for all docs templateFinder.templatePatterns = [ '${ doc.docType }.template' ]; }) .config(function(computePathsProcessor, computeIdsProcessor) { computePathsProcessor.$enabled = false; computeIdsProcessor.$enabled = false; // Unused for now. //computePathsProcessor.pathTemplates.push({ // docTypes: ['foo'], // pathTemplate: '', // getOutputPath: function () { // }, //}); // //computeIdsProcessor.idTemplates.push({ // docTypes: ['foo'], // getAliases: function (doc) { // return [doc.id]; // } //}); }); return pkg; } function resolveShredOptions(shredOptions) { var DOCS_FOLDER = '../../public/docs'; var so = _.defaults({}, shredOptions, { // read files from any subdir under here examplesDir: path.join(DOCS_FOLDER, "_examples"), // shredded files get copied here with same subdir structure. fragmentsDir: path.join(DOCS_FOLDER, "_fragments"), // whether to include subdirectories when shredding. includeSubdirs: true }); so.examplesDir = path.resolve(so.examplesDir); so.fragmentsDir = path.resolve(so.fragmentsDir); return so; } function resolveMapOptions(mapOptions) { var so = _.defaults({}, mapOptions, { includeSubdirs: true }); so.jadeDir = path.resolve(so.jadeDir); so.devguideExamplesDir = path.resolve(so.devguideExamplesDir); so.apiExamplesDir = path.resolve(so.apiExamplesDir); so.fragmentsDir = path.resolve(so.fragmentsDir); return so; } function initializePackage(pkg) { return pkg .processor(require('dgeni-packages/base/processors/read-files')) .processor(require('dgeni-packages/base/processors/write-files')) .factory(require('dgeni-packages/base/services/writeFile')) // Ugh... Boilerplate that dgeni needs to sequence operations .processor({ name: 'reading-files' }) .processor({ name: 'files-read', $runAfter: ['reading-files'] }) .processor({ name: 'processing-docs', $runAfter: ['files-read'] }) .processor({ name: 'docs-processed', $runAfter: ['processing-docs'] }) .processor({ name: 'adding-extra-docs', $runAfter: ['docs-processed'] }) .processor({ name: 'extra-docs-added', $runAfter: ['adding-extra-docs'] }) .processor({ name: 'computing-ids', $runAfter: ['extra-docs-added'] }) .processor({ name: 'ids-computed', $runAfter: ['computing-ids'] }) .processor({ name: 'computing-paths', $runAfter: ['ids-computed'] }) .processor({ name: 'paths-computed', $runAfter: ['computing-paths'] }) .processor({ name: 'rendering-docs', $runAfter: ['paths-computed'] }) .processor({ name: 'docs-rendered', $runAfter: ['rendering-docs'] }) .processor({ name: 'writing-files', $runAfter: ['docs-rendered'] }) .processor({ name: 'files-written', $runAfter: ['writing-files'] }) .config(function(log) { // Set logging level log.level = 'info'; }) }