'use strict'; var fs = require('fs'); var path = require('canonical-path'); /** * @dgProcessor generateKeywordsProcessor * @description * This processor extracts all the keywords from each document and creates * a new document that will be rendered as a JavaScript file containing all * this data. */ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) { return { ignoreWordsFile: undefined, propertiesToIgnore: [], docTypesToIgnore: [], outputFolder: '', $validate: { ignoreWordsFile: {}, docTypesToIgnore: {}, propertiesToIgnore: {}, outputFolder: {presence: true} }, $runAfter: ['postProcessHtml'], $runBefore: ['writing-files'], $process: function(docs) { // Keywords to ignore var wordsToIgnore = []; var propertiesToIgnore; var docTypesToIgnore; // Keywords start with "ng:" or one of $, _ or a letter var KEYWORD_REGEX = /^((ng:|[$_a-z])[\w\-_]+)/; // Load up the keywords to ignore, if specified in the config if (this.ignoreWordsFile) { var ignoreWordsPath = path.resolve(readFilesProcessor.basePath, this.ignoreWordsFile); wordsToIgnore = fs.readFileSync(ignoreWordsPath, 'utf8').toString().split(/[,\s\n\r]+/gm); log.debug('Loaded ignore words from "' + ignoreWordsPath + '"'); log.silly(wordsToIgnore); } propertiesToIgnore = convertToMap(this.propertiesToIgnore); log.debug('Properties to ignore', propertiesToIgnore); docTypesToIgnore = convertToMap(this.docTypesToIgnore); log.debug('Doc types to ignore', docTypesToIgnore); var ignoreWordsMap = convertToMap(wordsToIgnore); // If the title contains a name starting with ng, e.g. "ngController", then add the module // name // without the ng to the title text, e.g. "controller". function extractTitleWords(title) { var match = /ng([A-Z]\w*)/.exec(title); if (match) { title = title + ' ' + match[1].toLowerCase(); } return title; } function extractWords(text, words, keywordMap) { var tokens = text.toLowerCase().split(/[.\s,`'"#]+/mg); tokens.forEach(function(token) { var match = token.match(KEYWORD_REGEX); if (match) { var key = match[1]; if (!keywordMap[key]) { keywordMap[key] = true; words.push(key); } } }); } const filteredDocs = docs // We are not interested in some docTypes .filter(function(doc) { return !docTypesToIgnore[doc.docType]; }) // Ignore internals and private exports (indicated by the ɵ prefix) .filter(function(doc) { return !doc.internal && !doc.privateExport; }); filteredDocs.forEach(function(doc) { var words = []; var keywordMap = Object.assign({}, ignoreWordsMap); var members = []; var membersMap = {}; // Search each top level property of the document for search terms Object.keys(doc).forEach(function(key) { const value = doc[key]; if (isString(value) && !propertiesToIgnore[key]) { extractWords(value, words, keywordMap); } if (key === 'methods' || key === 'properties' || key === 'events') { value.forEach(function(member) { extractWords(member.name, members, membersMap); }); } }); doc.searchTitle = doc.searchTitle || doc.title || doc.vFile && doc.vFile.title || doc.name; doc.searchTerms = { titleWords: extractTitleWords(doc.searchTitle), keywords: words.sort().join(' '), members: members.sort().join(' ') }; }); var searchData = filteredDocs.filter(function(page) { return page.searchTerms; }).map(function(page) { return Object.assign( {path: page.path, title: page.searchTitle, type: page.docType}, page.searchTerms); }); docs.push({ docType: 'json-doc', id: 'search-data-json', path: this.outputFolder + '/search-data.json', outputPath: this.outputFolder + '/search-data.json', data: searchData, renderedContent: JSON.stringify(searchData) }); } }; }; function isString(value) { return typeof value == 'string'; } function convertToMap(collection) { const obj = {}; collection.forEach(key => { obj[key] = true; }); return obj; }