You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
8.3 KiB
188 lines
8.3 KiB
"use strict"; |
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |
|
}) : (function(o, m, k, k2) { |
|
if (k2 === undefined) k2 = k; |
|
o[k2] = m[k]; |
|
})); |
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
|
Object.defineProperty(o, "default", { enumerable: true, value: v }); |
|
}) : function(o, v) { |
|
o["default"] = v; |
|
}); |
|
var __importStar = (this && this.__importStar) || function (mod) { |
|
if (mod && mod.__esModule) return mod; |
|
var result = {}; |
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
|
__setModuleDefault(result, mod); |
|
return result; |
|
}; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports._testMethods = exports.hasWordCheck = exports.isWordValid = exports.calcTextInclusionRanges = exports.validateText = exports.minWordSplitLen = exports.defaultMinWordLength = exports.defaultMaxDuplicateProblems = exports.defaultMaxNumberOfProblems = void 0; |
|
const Text = __importStar(require("./util/text")); |
|
const TextRange = __importStar(require("./util/TextRange")); |
|
const RxPat = __importStar(require("./Settings/RegExpPatterns")); |
|
exports.defaultMaxNumberOfProblems = 200; |
|
exports.defaultMaxDuplicateProblems = 5; |
|
exports.defaultMinWordLength = 4; |
|
exports.minWordSplitLen = 3; |
|
function validateText(text, dict, options) { |
|
const { maxNumberOfProblems = exports.defaultMaxNumberOfProblems, maxDuplicateProblems = exports.defaultMaxDuplicateProblems, } = options; |
|
const mapOfProblems = new Map(); |
|
const includeRanges = calcTextInclusionRanges(text, options); |
|
const validator = lineValidator(dict, options); |
|
return Text.extractLinesOfText(text) |
|
.concatMap(mapTextOffsetsAgainstRanges(includeRanges)) |
|
.concatMap(validator) |
|
.filter((wo) => { |
|
const word = wo.text; |
|
// Keep track of the number of times we have seen the same problem |
|
mapOfProblems.set(word, (mapOfProblems.get(word) || 0) + 1); |
|
// Filter out if there is too many |
|
return mapOfProblems.get(word) < maxDuplicateProblems; |
|
}) |
|
.take(maxNumberOfProblems); |
|
} |
|
exports.validateText = validateText; |
|
function calcTextInclusionRanges(text, options) { |
|
const { ignoreRegExpList = [], includeRegExpList = [] } = options; |
|
const filteredIncludeList = includeRegExpList.filter((a) => !!a); |
|
const finalIncludeList = filteredIncludeList.length ? filteredIncludeList : ['.*']; |
|
const includeRanges = TextRange.excludeRanges(TextRange.findMatchingRangesForPatterns(finalIncludeList, text), TextRange.findMatchingRangesForPatterns(ignoreRegExpList, text)); |
|
return includeRanges; |
|
} |
|
exports.calcTextInclusionRanges = calcTextInclusionRanges; |
|
function lineValidator(dict, options) { |
|
const { minWordLength = exports.defaultMinWordLength, flagWords = [], ignoreWords = [], allowCompoundWords = false, ignoreCase = true, caseSensitive = false, } = options; |
|
const checkOptions = { |
|
...options, |
|
allowCompoundWords, |
|
ignoreCase, |
|
caseSensitive, |
|
}; |
|
const setOfFlagWords = new Set(flagWords); |
|
const mappedIgnoreWords = options.caseSensitive |
|
? ignoreWords |
|
: ignoreWords.concat(ignoreWords.map((a) => a.toLowerCase())); |
|
const ignoreWordsSet = new Set(mappedIgnoreWords); |
|
const setOfKnownSuccessfulWords = new Set(); |
|
const rememberFilter = (fn) => (v) => { |
|
const keep = fn(v); |
|
if (!keep) { |
|
setOfKnownSuccessfulWords.add(v.text); |
|
} |
|
return keep; |
|
}; |
|
const filterAlreadyChecked = (wo) => { |
|
return !setOfKnownSuccessfulWords.has(wo.text); |
|
}; |
|
function testForFlaggedWord(wo) { |
|
return setOfFlagWords.has(wo.text) || setOfFlagWords.has(wo.text.toLowerCase()); |
|
} |
|
function checkFlagWords(word) { |
|
const isFlagged = testForFlaggedWord(word); |
|
word.isFlagged = isFlagged; |
|
return word; |
|
} |
|
function checkWord(word, options) { |
|
const isFlagged = testForFlaggedWord(word); |
|
const isFound = isFlagged ? undefined : isWordValid(dict, word, word.line, options); |
|
return { ...word, isFlagged, isFound }; |
|
} |
|
const fn = (lineSegment) => { |
|
function checkFullWord(vr) { |
|
if (vr.isFlagged) { |
|
return [vr]; |
|
} |
|
const codeWordResults = Text.extractWordsFromCodeTextOffset(vr) |
|
.filter(filterAlreadyChecked) |
|
.filter(rememberFilter((wo) => wo.text.length >= minWordLength)) |
|
.map((t) => ({ ...t, line: vr.line })) |
|
.map((wo) => { |
|
const vr = { ...wo, text: wo.text.toLowerCase() }; |
|
return vr; |
|
}) |
|
.map((wo) => (wo.isFlagged ? wo : checkWord(wo, checkOptions))) |
|
.filter(rememberFilter((wo) => wo.isFlagged || !wo.isFound)) |
|
.filter(rememberFilter((wo) => !ignoreWordsSet.has(wo.text))) |
|
.filter(rememberFilter((wo) => !RxPat.regExHexDigits.test(wo.text))) // Filter out any hex numbers |
|
.filter(rememberFilter((wo) => !RxPat.regExRepeatedChar.test(wo.text))) // Filter out any repeated characters like xxxxxxxxxx |
|
// get back the original text. |
|
.map((wo) => ({ ...wo, text: Text.extractText(lineSegment, wo.offset, wo.offset + wo.text.length) })) |
|
.toArray(); |
|
if (!codeWordResults.length || ignoreWordsSet.has(vr.text) || checkWord(vr, checkOptions).isFound) { |
|
rememberFilter((_) => false)(vr); |
|
return []; |
|
} |
|
return codeWordResults; |
|
} |
|
// Check the whole words, not yet split |
|
const checkedWords = Text.extractWordsFromTextOffset(lineSegment) |
|
.filter(filterAlreadyChecked) |
|
.filter(rememberFilter((wo) => wo.text.length >= minWordLength)) |
|
.map((wo) => ({ ...wo, line: lineSegment })) |
|
.map(checkFlagWords) |
|
.concatMap(checkFullWord); |
|
return checkedWords; |
|
}; |
|
return fn; |
|
} |
|
function isWordValid(dict, wo, line, options) { |
|
const firstTry = hasWordCheck(dict, wo.text, options); |
|
return (firstTry || |
|
// Drop the first letter if it is preceded by a '\'. |
|
(line.text[wo.offset - line.offset - 1] === '\\' && hasWordCheck(dict, wo.text.slice(1), options))); |
|
} |
|
exports.isWordValid = isWordValid; |
|
function hasWordCheck(dict, word, options) { |
|
word = word.replace(/\\/g, ''); |
|
// Do not pass allowCompounds down if it is false, that allows for the dictionary to override the value based upon its own settings. |
|
return dict.has(word, convertCheckOptionsToHasOptions(options)); |
|
} |
|
exports.hasWordCheck = hasWordCheck; |
|
function convertCheckOptionsToHasOptions(opt) { |
|
const { ignoreCase, allowCompoundWords } = opt; |
|
return { |
|
ignoreCase, |
|
useCompounds: allowCompoundWords || undefined, |
|
}; |
|
} |
|
/** |
|
* Returns a mapper function that will |
|
* @param includeRanges Allowed ranges for words. |
|
*/ |
|
function mapTextOffsetsAgainstRanges(includeRanges) { |
|
let rangePos = 0; |
|
const mapper = (textOffset) => { |
|
if (!includeRanges.length) { |
|
return []; |
|
} |
|
const parts = []; |
|
const { text, offset } = textOffset; |
|
const wordEndPos = offset + text.length; |
|
let wordStartPos = offset; |
|
while (rangePos && (rangePos >= includeRanges.length || includeRanges[rangePos].startPos > wordStartPos)) { |
|
rangePos -= 1; |
|
} |
|
while (wordStartPos < wordEndPos) { |
|
while (includeRanges[rangePos] && includeRanges[rangePos].endPos <= wordStartPos) { |
|
rangePos += 1; |
|
} |
|
if (!includeRanges[rangePos] || wordEndPos < includeRanges[rangePos].startPos) { |
|
break; |
|
} |
|
const { startPos, endPos } = includeRanges[rangePos]; |
|
const a = Math.max(wordStartPos, startPos); |
|
const b = Math.min(wordEndPos, endPos); |
|
parts.push({ offset: a, text: text.slice(a - offset, b - offset) }); |
|
wordStartPos = b; |
|
} |
|
return parts.filter((wo) => !!wo.text); |
|
}; |
|
return mapper; |
|
} |
|
exports._testMethods = { |
|
mapWordsAgainstRanges: mapTextOffsetsAgainstRanges, |
|
}; |
|
//# sourceMappingURL=textValidator.js.map
|