renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
198 lines • 7.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.trimAtKey = trimAtKey;
exports.expandDepName = expandDepName;
exports.extractFromVectors = extractFromVectors;
exports.extractVariables = extractVariables;
exports.extractPackageFile = extractPackageFile;
const array_1 = require("../../../util/array");
const regex_1 = require("../../../util/regex");
const clojure_1 = require("../../datasource/clojure");
function trimAtKey(str, kwName) {
const regex = new RegExp(`:${kwName}(?=\\s)`); // TODO #12872 lookahead
const keyOffset = str.search(regex);
if (keyOffset < 0) {
return null;
}
const withSpaces = str.slice(keyOffset + kwName.length + 1);
const valueOffset = withSpaces.search((0, regex_1.regEx)(/[^\s]/));
if (valueOffset < 0) {
return null;
}
return withSpaces.slice(valueOffset);
}
function expandDepName(name) {
return name.includes('/') ? name.replace('/', ':') : `${name}:${name}`;
}
function extractFromVectors(str, ctx = {}, vars = {}, dimensions = 2) {
if (!str.startsWith('[')) {
return [];
}
let balance = 0;
const result = [];
let idx = 0;
let vecPos = 0;
let artifactId = '';
let version = '';
// Are we currently parsing a comment? If so, at what depth?
let commentLevel = null;
const isSpace = (ch) => !!ch && (0, regex_1.regEx)(/[\s,]/).test(ch);
const cleanStrLiteral = (s) => s.replace((0, regex_1.regEx)(/^"/), '').replace((0, regex_1.regEx)(/"$/), '');
const yieldDep = () => {
if (!commentLevel && artifactId && version) {
const depName = expandDepName(cleanStrLiteral(artifactId));
if (version.startsWith('~')) {
const varName = version.replace((0, regex_1.regEx)(/^~\s*/), '');
const currentValue = vars[varName];
if (currentValue) {
result.push({
...ctx,
datasource: clojure_1.ClojureDatasource.id,
depName,
currentValue,
sharedVariableName: varName,
});
}
}
else {
result.push({
...ctx,
datasource: clojure_1.ClojureDatasource.id,
depName,
currentValue: cleanStrLiteral(version),
});
}
}
artifactId = '';
version = '';
};
let prevChar = null;
while (idx < str.length) {
const char = str.charAt(idx);
if (str.substring(idx).startsWith('#_[')) {
commentLevel = balance;
}
if (char === '[') {
balance += 1;
if (balance === dimensions) {
vecPos = 0;
}
}
else if (char === ']') {
balance -= 1;
if (commentLevel === balance) {
artifactId = '';
version = '';
commentLevel = null;
}
if (balance === dimensions - 1) {
yieldDep();
}
if (balance === 0) {
break;
}
}
else if (balance === dimensions) {
if (isSpace(char)) {
if (!isSpace(prevChar)) {
vecPos += 1;
}
}
else if (vecPos === 0) {
artifactId += char;
}
else if (vecPos === 1) {
version += char;
}
}
prevChar = char;
idx += 1;
}
return result;
}
function extractLeinRepos(content) {
const result = [];
const repoContent = trimAtKey(content.replace(/;;.*(?=[\r\n])/g, ''), // get rid of comments // TODO #12872 lookahead
'repositories');
if (repoContent) {
let balance = 0;
let endIdx = 0;
for (let idx = 0; idx < repoContent.length; idx += 1) {
const char = repoContent.charAt(idx);
if (char === '[') {
balance += 1;
}
else if (char === ']') {
balance -= 1;
if (balance <= 0) {
endIdx = idx;
break;
}
}
}
const repoSectionContent = repoContent.slice(0, endIdx);
const matches = (0, array_1.coerceArray)(repoSectionContent.match((0, regex_1.regEx)(/"https?:\/\/[^"]*"/g)));
const urls = matches.map((x) => x.replace((0, regex_1.regEx)(/^"/), '').replace((0, regex_1.regEx)(/"$/), ''));
urls.forEach((url) => result.push(url));
}
return result;
}
const defRegex = (0, regex_1.regEx)(/^[\s,]*\([\s,]*def[\s,]+(?<varName>[-+*=<>.!?#$%&_|a-zA-Z][-+*=<>.!?#$%&_|a-zA-Z0-9']+)[\s,]*"(?<stringValue>[^"]*)"[\s,]*\)[\s,]*$/);
function extractVariables(content) {
const result = {};
const lines = content.split(regex_1.newlineRegex);
for (const line of lines) {
const match = defRegex.exec(line);
if (match?.groups) {
const { varName: key, stringValue: val } = match.groups;
result[key] = val;
}
}
return result;
}
function collectDeps(content, key, registryUrls, vars, options = {
nested: true,
}) {
const ctx = {
depType: options.depType ?? key,
registryUrls,
};
// A vector like [["dep-1" "1.0.0"] ["dep-2" "0.0.0"]] is nested
// A vector like ["dep-1" "1.0.0"] is not
const dimensions = options.nested ? 2 : 1;
let result = [];
let restContent = trimAtKey(content, key);
while (restContent) {
result = [
...result,
...extractFromVectors(restContent, ctx, vars, dimensions),
];
restContent = trimAtKey(restContent, key);
}
return result;
}
function extractPackageFile(content) {
const registryUrls = extractLeinRepos(content);
const vars = extractVariables(content);
const deps = [
...collectDeps(content, 'dependencies', registryUrls, vars),
...collectDeps(content, 'managed-dependencies', registryUrls, vars),
...collectDeps(content, 'plugins', registryUrls, vars),
...collectDeps(content, 'pom-plugins', registryUrls, vars),
// 'coords' is used in lein parent, and specifies zero or one
// dependencies. These are not wrapped in a vector in the way other
// dependencies are. The project.clj fragment looks like
//
// :parent-project {... :coords ["parent" "version"] ...}
//
// - https://github.com/achin/lein-parent
...collectDeps(content, 'coords', registryUrls, vars, {
nested: false,
// The top-level key is 'parent-project', but we skip directly to 'coords'.
// So fix the dep type label
depType: 'parent-project',
}),
];
return { deps };
}
//# sourceMappingURL=extract.js.map