renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
194 lines • 6.37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.countPackageNameLength = countPackageNameLength;
exports.findExtents = findExtents;
exports.countPrecedingIndentation = countPrecedingIndentation;
exports.findDepends = findDepends;
exports.splitSingleDependency = splitSingleDependency;
exports.extractNamesAndRanges = extractNamesAndRanges;
const regex_1 = require("../../../util/regex");
const buildDependsRegex = (0, regex_1.regEx)(/(?<buildDependsFieldName>build-depends[ \t]*:)/i);
const commentRegex = (0, regex_1.regEx)(/^[ \t]*--/);
function isNonASCII(str) {
for (let i = 0; i < str.length; i++) {
if (str.charCodeAt(i) > 127) {
return true;
}
}
return false;
}
function countPackageNameLength(input) {
if (input.length < 1 || isNonASCII(input)) {
return null;
}
if (!(0, regex_1.regEx)(/^[A-Za-z0-9]/).test(input[0])) {
// Must start with letter or number
return null;
}
let idx = 1;
while (idx < input.length) {
if ((0, regex_1.regEx)(/[A-Za-z0-9-]/).test(input[idx])) {
idx++;
}
else {
break;
}
}
if (!(0, regex_1.regEx)(/[A-Za-z]/).test(input.slice(0, idx))) {
// Must contain a letter
return null;
}
if (idx - 1 < input.length && input[idx - 1] === '-') {
// Can't end in a hyphen
return null;
}
return idx;
}
/**
* Find extents of field contents
*
* @param {number} indent -
* Indention level maintained within the block.
* Any indention lower than this means it's outside the field.
* Lines with this level or more are included in the field.
* @returns {number}
* Index just after the end of the block.
* Note that it may be after the end of the string.
*/
function findExtents(indent, content) {
let blockIdx = 0;
let mode = 'finding-newline';
for (;;) {
if (mode === 'finding-newline') {
while (content[blockIdx++] !== '\n') {
if (blockIdx >= content.length) {
break;
}
}
if (blockIdx >= content.length) {
return content.length;
}
mode = 'finding-indention';
}
else {
let thisIndent = 0;
for (;;) {
if ([' ', '\t'].includes(content[blockIdx])) {
thisIndent += 1;
blockIdx++;
if (blockIdx >= content.length) {
return content.length;
}
continue;
}
mode = 'finding-newline';
blockIdx++;
break;
}
if (thisIndent < indent) {
if (content.slice(blockIdx - 1, blockIdx + 1) === '--') {
// not enough indention, but the line is a comment, so include it
mode = 'finding-newline';
continue;
}
// go back to before the newline
for (;;) {
if (content[blockIdx--] === '\n') {
break;
}
}
return blockIdx + 1;
}
mode = 'finding-newline';
}
}
}
/**
* Find indention level of build-depends
*
* @param {number} match -
* Search starts at this index, and proceeds backwards.
* @returns {number}
* Number of indention levels found before 'match'.
*/
function countPrecedingIndentation(content, match) {
let whitespaceIdx = match - 1;
let indent = 0;
while (whitespaceIdx >= 0 && [' ', '\t'].includes(content[whitespaceIdx])) {
indent += 1;
whitespaceIdx--;
}
return indent;
}
/**
* Find one 'build-depends' field name usage and its field value
*
* @returns {{buildDependsContent: string, lengthProcessed: number}}
* buildDependsContent:
* the contents of the field, excluding the field name and the colon,
* and any comments within
*
* lengthProcessed:
* points to after the end of the field. Note that the field does _not_
* necessarily start at `content.length - lengthProcessed`.
*
* Returns null if no 'build-depends' field is found.
*/
function findDepends(content) {
const matchObj = buildDependsRegex.exec(content);
if (!matchObj?.groups) {
return null;
}
const indent = countPrecedingIndentation(content, matchObj.index);
const ourIdx = matchObj.index + matchObj.groups.buildDependsFieldName.length;
const extentLength = findExtents(indent + 1, content.slice(ourIdx));
const extent = content.slice(ourIdx, ourIdx + extentLength);
const lines = [];
// Windows-style line breaks are fine because
// carriage returns are before the line feed.
for (const maybeCommentLine of extent.split('\n')) {
if (!commentRegex.test(maybeCommentLine)) {
lines.push(maybeCommentLine);
}
}
return {
buildDependsContent: lines.join('\n'),
lengthProcessed: ourIdx + extentLength,
};
}
/**
* Split a cabal single dependency into its constituent parts.
* The first part is the package name, an optional second part contains
* the version constraint.
*
* For example 'base == 3.2' would be split into 'base' and ' == 3.2'.
*
* @returns {{name: string, range: string}}
* Null if the trimmed string doesn't begin with a package name.
*/
function splitSingleDependency(input) {
const match = countPackageNameLength(input);
if (match === null) {
return null;
}
const name = input.slice(0, match);
const range = input.slice(match).trim();
return { name, range };
}
function extractNamesAndRanges(content) {
const list = content.split(',');
const deps = [];
for (const untrimmedReplaceString of list) {
const replaceString = untrimmedReplaceString.trim();
const maybeNameRange = splitSingleDependency(replaceString);
if (maybeNameRange !== null) {
deps.push({
currentValue: maybeNameRange.range,
packageName: maybeNameRange.name,
replaceString,
});
}
}
return deps;
}
//# sourceMappingURL=extract.js.map