Source: core/find_in_cpp_source.js

/*
 * This file is part of PKM (Persistent Knowledge Monitor).
 * Copyright (c) 2020 Capgemini Group, Commissariat à l'énergie atomique et aux énergies alternatives,
 *                    OW2, Sysgo AG, Technikon, Tree Technology, Universitat Politècnica de València.
 * 
 * PKM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation.
 * 
 * PKM is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with PKM.  If not, see <https://www.gnu.org/licenses/>.
 */

/**
 * find artefacts in C++ source
 * 
 * @memberof PKM
 * @instance
 * @param {string} dbName - database name
 * @param {object} [query] - query { kind : ('string'|'/regex/'), path : ('string'|'/regex/'), id : number, name : ('string'|'/regex/') })
 * @param {object} [options] - options
 * 
 * @return {Promise<Array.<Object>>} a promise that passes the result (an array) to resolve callback
 */
function find_in_cpp_source(dbName, query = {}, options = {})
{
	return new Promise(function(resolve, reject)
	{
		const debug = this.debug;
		
		const query_is_empty = Object.keys(query).length == 0;
		
		function search_element(document, id)
		{
			if(document.hasOwnProperty('id') && (document.id === id))
			{
				return document;
			}
			
			if(document.hasOwnProperty('inner'))
			{
				for(let i = 0; i < document.inner.length; ++i)
				{
					const inner_element = document.inner[i];
					const found = search_element(inner_element, id)
					if(found) return found;
				}
			}
			
			return undefined;
		}
			
		function search(document, query)
		{
			let result = [];
			
			if(document.hasOwnProperty('manifest'))
			{
				document.manifest.forEach((manifest_item) =>
				{
					if(((query.id === undefined) || (query.id === manifest_item.id)) &&
					    ((query.kind === undefined) || ((typeof query.kind === 'string') && (query.kind === manifest_item.kind)) || ((query.kind instanceof RegExp) && query.kind.test(manifest_item.kind))) &&
					    ((query.name === undefined) || ((typeof query.name === 'string') && (query.name === manifest_item.name)) || ((query.name instanceof RegExp) && query.name.test(manifest_item.name))) &&
					    ((query.path === undefined) || ((typeof query.path === 'string') && (query.path === manifest_item.path)) || ((query.path instanceof RegExp) && query.path.test(manifest_item.path))))
					{
						document.inner.forEach((inner_element) =>
						{
							const found = search_element(inner_element, manifest_item.id);
							if(found !== undefined)
							{
								result.push(found);
							}
						});
					}
				});
			}
			
			return result;
		}
		
		let get_doc_query = {};
		let search_query = {};
		if(query !== undefined)
		{
			if(query.id !== undefined)
			{
				get_doc_query['manifest.id'] = query.id;
				search_query.id = query.id;
			}
			[ 'kind', 'path', 'name' ].forEach((key) =>
			{
				if(query[key] !== undefined)
				{
					if(query[key].startsWith('/') && query[key].endsWith('/'))
					{
						get_doc_query['manifest.' + key] = { $regex : query[key].slice(1, query[key].length - 1) };
						search_query[key] = new RegExp(query[key].slice(1, query[key].length - 1));
					}
					else
					{
						get_doc_query['manifest.' + key] = query[key];
						search_query[key] = query[key];
					}
				}
			});
		}
		
		this.get_documents(dbName, 'sourcecodeCPP', get_doc_query).then((documents) =>
		{
			let search_promises = [];
			documents.forEach((document) =>
			{
				search_promises.push(new Promise((resolve, reject) =>
				{
					let result = search(document, search_query);
					resolve(result);
				}));
			});
			
			Promise.all(search_promises).then((results) =>
			{
				let result = results.reduce((acc, val) => acc.concat(val), []);
				
				if(result.length || query_is_empty)
				{
					if((options.skip !== undefined) || (options.limit !== undefined))
					{
						let start = options.skip || 0;
						let end = start + (options.limit ? options.limit : result.length);
						resolve(result.slice(start, end));
					}
					else
					{
						resolve(result);
					}
				}
				else
				{
					reject(this.NotFound());
				}
			}).catch((err) =>
			{
				reject(this.Error(err));
			});
		}).catch((err) =>
		{
			reject(this.Error(err));
		});
	}.bind(this));
}

exports.find_in_cpp_source = find_in_cpp_source;