|
'use strict'; |
|
|
|
/** |
|
* Look up the name and query mode of a query by its unique ID. |
|
* |
|
* @param {string} - the unique identifier of a query buffer |
|
* @return {object|undefined} - an object with `name` and `mode` keys |
|
or `undefined` if no query matches the ID |
|
*/ |
|
function lookupQuery(queryID) { |
|
const db = require('/MarkLogic/jsearch'); |
|
const docs = db.documents(); |
|
const ns = { qc: 'http://marklogic.com/appservices/qconsole' }; |
|
const query = cts.andQuery([ |
|
cts.directoryQuery('/workspaces/'), |
|
//cts.elementQuery(fn.QName(ns.qc, 'query'), |
|
cts.elementValueQuery(fn.QName(ns.qc, 'id'), queryID, ['exact']) |
|
//) |
|
]); |
|
|
|
const results = docs.where(query).filter(true).result().results; |
|
|
|
if (results && results.length) { |
|
const doc = results[0].document; |
|
const queryEl = fn.head(doc.xpath(`//qc:query[qc:id = '${queryID}']`, ns)); |
|
return { |
|
name: queryEl.xpath(`./qc:name/string(.)`, ns), |
|
mode: queryEl.xpath(`./qc:mode/string(.)`, ns), |
|
workspace: { |
|
name: doc.xpath(`/qc:workspace/qc:name/string(.)`, ns), |
|
id: doc.xpath(`/qc:workspace/qc:id/string(.)`, ns) |
|
} |
|
}; |
|
} |
|
//throw new Error(String(queryID)); |
|
} |
|
|
|
/** |
|
* Highlight exact matches of a phrase in a query buffer. |
|
* |
|
* @param {string} buffer - the entire buffer of code |
|
* @param {string} phrase - the exact text to match |
|
* @param {number} [num=3] - the number of lines before an after the match to inlcude |
|
* @yield {object} - `location` object with `line` and `column` properties |
|
and `context` array with the matched lines and surrounding context |
|
*/ |
|
function* highlight(buffer, phrase, num = 3, maxMatches = 50) { |
|
if (num < 1) { |
|
throw new TypeError('num must be greater than zero'); |
|
} |
|
num = Math.floor(num); |
|
if (maxMatches < 1) { |
|
throw new TypeError('maxMatches must be greater than zero'); |
|
} |
|
|
|
const re = new RegExp(phrase, 'g'); |
|
//console.dir(re); |
|
|
|
const lineNumbers = (lines, start) => |
|
lines.map(line => ({ number: start++, text: line })); |
|
|
|
const lines = buffer.split('\n'); // TODO: Pass in a Iterable<string> of lines |
|
const lower = x => Math.max(x, 0); |
|
const upper = x => Math.min(x, lines.length - 1); |
|
let i = 0; |
|
for (const line of lines) { |
|
if (re.test(line)) { |
|
console.log(line); |
|
yield { |
|
location: { line: i + 1, column: line.indexOf(phrase) + 1 }, |
|
context: lineNumbers( |
|
[].concat( |
|
lines.slice(lower(i - num), i), // context before |
|
lines[i].replace(re, `<highlight>${phrase}</highlight>`), // TODO: Is there a better way to do this? |
|
lines.slice(upper(i + 1), upper(i + 1 + num)) // context after |
|
), |
|
lower(i - num) + 1 |
|
) |
|
}; |
|
if (i >= maxMatches - 2) { |
|
//break; |
|
} |
|
} |
|
i++; |
|
} |
|
} |
|
|
|
/** |
|
* Emit search hits on Query Console queries using an |
|
* exact match on the `queryString`. |
|
* |
|
* @param {string} queryString - the exact phrase to search for |
|
* @yield {object} - a document and its match context |
|
*/ |
|
function* findBuffers(queryString) { |
|
const db = require('/MarkLogic/jsearch'); |
|
const docs = db.documents(); |
|
const query = cts.andQuery([ |
|
cts.directoryQuery('/queries/'), |
|
cts.wordQuery(queryString, ['exact']) |
|
]); |
|
|
|
const results = docs.where(query).filter(true).slice(0, 10).result('iterator') |
|
.results; |
|
|
|
for (const hit of results) { |
|
const uri = hit.uri /* xs.anyURI */.toString(); |
|
const qID = uri.split('/')[2].split('.')[0]; |
|
yield Object.assign(lookupQuery(qID) || {}, { |
|
uri: uri, |
|
matches: Array.from(highlight(hit.document.toObject(), queryString)) |
|
}); |
|
} |
|
} |
|
|
|
Array.from(findBuffers('Error.captureStackTrace')); |
|
|