js-solr-highlighter
Advanced tools
Comparing version 0.7.3 to 0.7.4
@@ -24,2 +24,3 @@ "use strict"; | ||
function highlightByQuery(query, content, options = {}) { | ||
// can allow more options of text-annotator*** | ||
const { | ||
@@ -30,3 +31,4 @@ validFields, | ||
highlightedFields, | ||
highlightIdPattern | ||
highlightIdPattern, | ||
caseSensitive | ||
} = options; | ||
@@ -36,3 +38,3 @@ const searchFunc = highlightAll === undefined || highlightAll ? 'searchAll' : 'search'; | ||
const lucene = require('lucene'); // possible: [\+\-\!\(\)\{\}\[\]\^\"\?\:\\\&\|\'\/\s\*\~] | ||
const lucene = require('lucene'); // [\+\-\!\(\)\{\}\[\]\^\"\?\:\\\&\|\'\/\s\*\~] | ||
@@ -52,3 +54,3 @@ | ||
}); | ||
}; // escape invalid fields and char | ||
}; // escape invalid fields | ||
@@ -58,4 +60,4 @@ | ||
const fieldVals = []; | ||
const fieldVals2 = []; // possible: /([^:\s]+):([^:\s]+)/g | ||
// xxx:xxx, xxx: xxx | ||
const fieldVals2 = []; // /([^:\s]+):([^:\s]+)/g | ||
// deal with cases like xxx:xxx, xxx: xxx | ||
@@ -69,14 +71,7 @@ let regex = /([^(\s]+):\s?([^\s)"]+)/g; | ||
if (validFields === undefined || validFields.includes(field)) { | ||
// remove invalid " | ||
if (res[2].startsWith('"') && !res[2].endsWith('"')) { | ||
fieldVals.push([fieldVal, res[1] + ':' + res[2].substring(1)]); | ||
} else if (!res[2].startsWith('"') && res[2].endsWith('"')) { | ||
fieldVals.push(fieldVal, res[1] + ':' + res[2].substring(0, res[2].length - 1)); | ||
} | ||
} else { | ||
if (validFields !== undefined && !validFields.includes(field)) { | ||
fieldVals2.push(fieldVal); | ||
} | ||
} // possible: , /([a-zA-Z]+)(\s+):(\s+)([a-zA-Z]+)/g | ||
// xxx:"xxx" xxx:"xxx | ||
} // /([a-zA-Z]+)(\s+):(\s+)([a-zA-Z]+)/g | ||
// deal with cases like xxx:"xxx", xxx:"xxx | ||
@@ -110,3 +105,4 @@ | ||
const ast = lucene.parse(q); | ||
const ast = lucene.parse(q); // add terms to be highlighted | ||
const { | ||
@@ -117,3 +113,3 @@ start, | ||
operator | ||
} = ast; // add terms to be highlighted | ||
} = ast; | ||
@@ -135,3 +131,3 @@ const addTerm = (words, term, quoted) => { | ||
const allOperators = astString.match(/"operator":"([^(,)]+)"/g); | ||
const allFields = astString.match(/"field":"([^(,)]+)"/g); // the !left.quoted condition is not elegant | ||
const allFields = astString.match(/"field":"([^(,)]+)"/g); // the !left.quoted condition is not elegant*** | ||
@@ -147,3 +143,3 @@ if (allOperators && allOperators.every(operator => operator === '"operator":"<implicit>"') && allFields && allFields.every(field => field === '"field":"<implicit>"') && !left.quoted) { | ||
const canHighlight = field => highlightedFields === undefined ? field : highlightedFields.includes(field); // not an elegant solution | ||
const canHighlight = field => highlightedFields === undefined ? field : highlightedFields.includes(field); // not an elegant solution*** | ||
@@ -177,3 +173,3 @@ | ||
} // highlight one word by another | ||
// some filters may be moved above | ||
// some filters may be moved up*** | ||
@@ -191,3 +187,3 @@ | ||
directSearchOptions: { | ||
caseSensitive: false | ||
caseSensitive: caseSensitive !== undefined && caseSensitive | ||
} | ||
@@ -203,3 +199,4 @@ }); | ||
return !c.match(letters); | ||
}; // make sure we do not highlight part of a word; can be moved up | ||
}; // make sure we do not highlight part of a word | ||
// this logic may be moved up*** | ||
@@ -211,3 +208,2 @@ | ||
if (prevCharValid && nextCharValid) { | ||
// highlight options can be made customised | ||
newContent = highlighter.highlight(highlightIndex, { | ||
@@ -214,0 +210,0 @@ content: newContent, |
46
index.js
@@ -48,2 +48,3 @@ import TextAnnotator from 'text-annotator' | ||
function highlightByQuery(query, content, options = {}) { | ||
// can allow more options of text-annotator*** | ||
const { | ||
@@ -54,3 +55,4 @@ validFields, | ||
highlightedFields, | ||
highlightIdPattern | ||
highlightIdPattern, | ||
caseSensitive | ||
} = options | ||
@@ -63,3 +65,3 @@ const searchFunc = | ||
const lucene = require('lucene') | ||
// possible: [\+\-\!\(\)\{\}\[\]\^\"\?\:\\\&\|\'\/\s\*\~] | ||
// [\+\-\!\(\)\{\}\[\]\^\"\?\:\\\&\|\'\/\s\*\~] | ||
const esc = (s, c) => { | ||
@@ -78,9 +80,8 @@ const regex = new RegExp(c, 'g') | ||
// escape invalid fields and char | ||
// escape invalid fields | ||
let q = query | ||
const fieldVals = [] | ||
const fieldVals2 = [] | ||
// possible: /([^:\s]+):([^:\s]+)/g | ||
// xxx:xxx, xxx: xxx | ||
// /([^:\s]+):([^:\s]+)/g | ||
// deal with cases like xxx:xxx, xxx: xxx | ||
let regex = /([^(\s]+):\s?([^\s)"]+)/g | ||
@@ -91,19 +92,8 @@ let res | ||
const fieldVal = res[0] | ||
if (validFields === undefined || validFields.includes(field)) { | ||
// remove invalid " | ||
if (res[2].startsWith('"') && !res[2].endsWith('"')) { | ||
fieldVals.push([fieldVal, res[1] + ':' + res[2].substring(1)]) | ||
} else if (!res[2].startsWith('"') && res[2].endsWith('"')) { | ||
fieldVals.push( | ||
fieldVal, | ||
res[1] + ':' + res[2].substring(0, res[2].length - 1) | ||
) | ||
} | ||
} else { | ||
if (validFields !== undefined && !validFields.includes(field)) { | ||
fieldVals2.push(fieldVal) | ||
} | ||
} | ||
// possible: , /([a-zA-Z]+)(\s+):(\s+)([a-zA-Z]+)/g | ||
// xxx:"xxx" xxx:"xxx | ||
// /([a-zA-Z]+)(\s+):(\s+)([a-zA-Z]+)/g | ||
// deal with cases like xxx:"xxx", xxx:"xxx | ||
const regex2 = /([^\s(]+):\s?("[^"]+"?[^)])/g | ||
@@ -127,3 +117,2 @@ while ((res = regex2.exec(q)) !== null) { | ||
} | ||
fieldVals.forEach(fv => { | ||
@@ -139,5 +128,5 @@ q = q.replace(fv[0], fv[1]) | ||
const ast = lucene.parse(q) | ||
const { start, left, right, operator } = ast | ||
// add terms to be highlighted | ||
const { start, left, right, operator } = ast | ||
const addTerm = (words, term, quoted) => { | ||
@@ -157,7 +146,6 @@ term = unesc(term, ':') | ||
} | ||
const astString = JSON.stringify(ast) | ||
const allOperators = astString.match(/"operator":"([^(,)]+)"/g) | ||
const allFields = astString.match(/"field":"([^(,)]+)"/g) | ||
// the !left.quoted condition is not elegant | ||
// the !left.quoted condition is not elegant*** | ||
if ( | ||
@@ -184,3 +172,3 @@ allOperators && | ||
// not an elegant solution | ||
// not an elegant solution*** | ||
if ( | ||
@@ -226,3 +214,3 @@ !canHighlight(left.field) && | ||
// highlight one word by another | ||
// some filters may be moved above | ||
// some filters may be moved up*** | ||
words = words.filter( | ||
@@ -240,3 +228,3 @@ word => | ||
directSearchOptions: { | ||
caseSensitive: false | ||
caseSensitive: caseSensitive !== undefined && caseSensitive | ||
} | ||
@@ -253,3 +241,4 @@ }) | ||
} | ||
// make sure we do not highlight part of a word; can be moved up | ||
// make sure we do not highlight part of a word | ||
// this logic may be moved up*** | ||
const prevCharValid = loc[0] === 0 || fixVaild(text.charAt(loc[0] - 1)) | ||
@@ -259,3 +248,2 @@ const nextCharValid = | ||
if (prevCharValid && nextCharValid) { | ||
// highlight options can be made customised | ||
newContent = highlighter.highlight(highlightIndex, { | ||
@@ -262,0 +250,0 @@ content: newContent, |
import { isStopWord, highlightByQuery } from './index.js' | ||
describe('tests for function highlightByQuery derived by faults found in Europe PMC', () => { | ||
describe("tests with Europe PMC's standard query set", () => { | ||
const options = { | ||
@@ -337,3 +337,3 @@ validFields: [ | ||
// throw errors but work; improve later | ||
// throw errors but work; improve later*** | ||
// test('PUBLISHER:"[Institute for Quality and Efficiency in Health Care (IQWiG)][Cologne (Germany)]"', () => { | ||
@@ -497,4 +497,4 @@ // const query = 'PUBLISHER:"[Institute for Quality and Efficiency in Health Care (IQWiG)][Cologne (Germany)]"' | ||
describe('other tests for function highlightByQuery', () => { | ||
test('TITLE:blood AND CONTENT:cell', () => { | ||
describe('tests for the options argument', () => { | ||
test('test the validFields option', () => { | ||
const query = 'TITLE:blood AND CONTENT:cell' | ||
@@ -511,3 +511,15 @@ const content = | ||
test('TITLE:blood OR CONTENT:cell', () => { | ||
// test('test the validFields option', () => { | ||
// const query = 'TITLE:blood OR cell' | ||
// const content = | ||
// 'A molecular map of lymph node blood vascular endothelium at single cell resolution' | ||
// const received = highlightByQuery(query, content, { | ||
// validFields: ['TITLE'] | ||
// }) | ||
// const expected = | ||
// 'A molecular map of lymph node <span id="highlight-0" class="highlight">blood</span> vascular endothelium at single <span id="highlight-1" class="highlight">cell</span> resolution' | ||
// expect(received).toBe(expected) | ||
// }) | ||
test('test the highlightedFields option', () => { | ||
const query = 'TITLE:blood OR CONTENT:cell' | ||
@@ -525,18 +537,6 @@ const content = | ||
test('TITLE:blood OR cell', () => { | ||
const query = 'TITLE:blood OR cell' | ||
const content = | ||
'A molecular map of lymph node blood vascular endothelium at single cell resolution' | ||
const received = highlightByQuery(query, content, { | ||
validFields: ['TITLE'] | ||
}) | ||
const expected = | ||
'A molecular map of lymph node <span id="highlight-0" class="highlight">blood</span> vascular endothelium at single <span id="highlight-1" class="highlight">cell</span> resolution' | ||
expect(received).toBe(expected) | ||
}) | ||
test('blood', () => { | ||
test('test the highlightAll option', () => { | ||
const query = 'blood' | ||
const content = | ||
'Pediatric non-red cell blood product transfusion practices: what\'s the evidence to guide transfusion of the \'yellow\' blood products?' | ||
"Pediatric non-red cell blood product transfusion practices: what's the evidence to guide transfusion of the 'yellow' blood products?" | ||
const received = highlightByQuery(query, content, { | ||
@@ -550,3 +550,3 @@ highlightAll: false | ||
test('breast cancer', () => { | ||
test('test the highlightIdPattern option', () => { | ||
const query = 'breast cancer' | ||
@@ -559,7 +559,7 @@ const content = | ||
const expected = | ||
'Editorial: The Role of <span id=\"new-highlight-0\" class=\"highlight\">Breast</span> <span id=\"new-highlight-1\" class=\"highlight\">Cancer</span> Stem Cells in Clinical Outcomes.' | ||
'Editorial: The Role of <span id="new-highlight-0" class="highlight">Breast</span> <span id="new-highlight-1" class="highlight">Cancer</span> Stem Cells in Clinical Outcomes.' | ||
expect(received).toBe(expected) | ||
}) | ||
test('breast cancer', () => { | ||
test('test the highlightClass option', () => { | ||
const query = 'breast cancer' | ||
@@ -572,13 +572,23 @@ const content = | ||
const expected = | ||
'Editorial: The Role of <span id=\"highlight-0\" class=\"new-highlight\">Breast</span> <span id=\"highlight-1\" class=\"new-highlight\">Cancer</span> Stem Cells in Clinical Outcomes.' | ||
'Editorial: The Role of <span id="highlight-0" class="new-highlight">Breast</span> <span id="highlight-1" class="new-highlight">Cancer</span> Stem Cells in Clinical Outcomes.' | ||
expect(received).toBe(expected) | ||
}) | ||
test('test the caseSensitive option', () => { | ||
const query = 'covid-19' | ||
const content = 'Clinical observation and management of COVID-19 patients.' | ||
const received = highlightByQuery(query, content, { | ||
caseSensitive: true | ||
}) | ||
const expected = 'Clinical observation and management of COVID-19 patients.' | ||
expect(received).toBe(expected) | ||
}) | ||
}) | ||
describe('tests for function isStopWord', () => { | ||
test('return true', () => { | ||
describe('tests for the isStopWord function', () => { | ||
test('is a stop word', () => { | ||
const received = isStopWord('of') | ||
expect(received).toBeTruthy() | ||
}) | ||
test('return false', () => { | ||
test('is not a stop word', () => { | ||
const received = isStopWord('I') | ||
@@ -585,0 +595,0 @@ expect(received).toBeFalsy() |
{ | ||
"name": "js-solr-highlighter", | ||
"version": "0.7.3", | ||
"version": "0.7.4", | ||
"description": "A JavaScript library for highlighting HTML text based on the query in the lucene/solr query syntax", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
@@ -9,4 +9,4 @@ # js-solr-highlighter | ||
## An example from [Europe PMC](https://europepmc.org "Europe PMC") | ||
js-solr-highlighter has been used to highlight the article titles in the search results of Europe PMC. An example is https://europepmc.org/search?query=blood%20AND%20TITLE%3Acancer | ||
## An example from Europe PMC | ||
js-solr-highlighter has been used to highlight the article titles in the search results of [Europe PMC](https://europepmc.org "Europe PMC"). An example is https://europepmc.org/search?query=blood%20AND%20TITLE%3Acancer | ||
!["an example from Europe PMC" "an example from Europe PMC"](example.JPG) | ||
@@ -49,2 +49,3 @@ | ||
| highlightClass | string | highlightClass is the classname of every highlight in the HTML.<br />If undefined, it is "highlight". | | ||
| caseSensitive | boolean | caseSensitive indicates whether to ignore case when highlighting.<br />If undefined, it is false (ignore). | ||
@@ -51,0 +52,0 @@ ## Highlighting rules |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
652959
54
950