NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Collect EBA Reporting Modules
// @namespace https://work.swindle.net/
// @version v1.6.2
// @license MIT
// @description Extract and transform EBA regulatory module metadata.
// @author Gregory Swindle <greg@work.swindle.net>
// @match https://www.eba.europa.eu/reporting-time-traveller
// @match https://www.eba.europa.eu/reporting-time-traveller/reporting-by-name*
// @grant none
// @require https://raw.githubusercontent.com/lodash/lodash/4.17.15-npm/lodash.js
// ==/UserScript==
/** <script src="semver.browser.js"> **/
;(function (exports) {
// export the class if we are in a Node-like system.
if (typeof module === 'object' && module.exports === exports)
exports = module.exports = SemVer
// The debug function is excluded entirely from the minified version.
// Note: this is the semver.org version of the spec that it implements
// Not necessarily the package version of this code.
exports.SEMVER_SPEC_VERSION = '2.0.0'
var MAX_LENGTH = 256
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991
// The actual regexps go on exports.re
var re = (exports.re = [])
var src = (exports.src = [])
var R = 0
// The following Regular Expressions can be used for tokenizing,
// validating, and parsing SemVer version strings.
// ## Numeric Identifier
// A single `0`, or a non-zero digit followed by zero or more digits.
var NUMERICIDENTIFIER = R++
src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'
var NUMERICIDENTIFIERLOOSE = R++
src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'
// ## Non-numeric Identifier
// Zero or more digits, followed by a letter or hyphen, and then zero or
// more letters, digits, or hyphens.
var NONNUMERICIDENTIFIER = R++
src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'
// ## Main Version
// Three dot-separated numeric identifiers.
var MAINVERSION = R++
src[MAINVERSION] =
'(' +
src[NUMERICIDENTIFIER] +
')\\.' +
'(' +
src[NUMERICIDENTIFIER] +
')\\.' +
'(' +
src[NUMERICIDENTIFIER] +
')'
var MAINVERSIONLOOSE = R++
src[MAINVERSIONLOOSE] =
'(' +
src[NUMERICIDENTIFIERLOOSE] +
')\\.' +
'(' +
src[NUMERICIDENTIFIERLOOSE] +
')\\.' +
'(' +
src[NUMERICIDENTIFIERLOOSE] +
')'
// ## Pre-release Version Identifier
// A numeric identifier, or a non-numeric identifier.
var PRERELEASEIDENTIFIER = R++
src[PRERELEASEIDENTIFIER] =
'(?:' + src[NUMERICIDENTIFIER] + '|' + src[NONNUMERICIDENTIFIER] + ')'
var PRERELEASEIDENTIFIERLOOSE = R++
src[PRERELEASEIDENTIFIERLOOSE] =
'(?:' + src[NUMERICIDENTIFIERLOOSE] + '|' + src[NONNUMERICIDENTIFIER] + ')'
// ## Pre-release Version
// Hyphen, followed by one or more dot-separated pre-release version
// identifiers.
var PRERELEASE = R++
src[PRERELEASE] =
'(?:-(' +
src[PRERELEASEIDENTIFIER] +
'(?:\\.' +
src[PRERELEASEIDENTIFIER] +
')*))'
var PRERELEASELOOSE = R++
src[PRERELEASELOOSE] =
'(?:-?(' +
src[PRERELEASEIDENTIFIERLOOSE] +
'(?:\\.' +
src[PRERELEASEIDENTIFIERLOOSE] +
')*))'
// ## Build Metadata Identifier
// Any combination of digits, letters, or hyphens.
var BUILDIDENTIFIER = R++
src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'
// ## Build Metadata
// Plus sign, followed by one or more period-separated build metadata
// identifiers.
var BUILD = R++
src[BUILD] =
'(?:\\+(' + src[BUILDIDENTIFIER] + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'
// ## Full Version String
// A main version, followed optionally by a pre-release version and
// build metadata.
// Note that the only major, minor, patch, and pre-release sections of
// the version string are capturing groups. The build metadata is not a
// capturing group, because it should not ever be used in version
// comparison.
var FULL = R++
var FULLPLAIN =
'v?' + src[MAINVERSION] + src[PRERELEASE] + '?' + src[BUILD] + '?'
src[FULL] = '^' + FULLPLAIN + '$'
// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
// common in the npm registry.
var LOOSEPLAIN =
'[v=\\s]*' +
src[MAINVERSIONLOOSE] +
src[PRERELEASELOOSE] +
'?' +
src[BUILD] +
'?'
var LOOSE = R++
src[LOOSE] = '^' + LOOSEPLAIN + '$'
var GTLT = R++
src[GTLT] = '((?:<|>)?=?)'
// Something like "2.*" or "1.2.x".
// Note that "x.x" is a valid xRange identifer, meaning "any version"
// Only the first item is strictly required.
var XRANGEIDENTIFIERLOOSE = R++
src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'
var XRANGEIDENTIFIER = R++
src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'
var XRANGEPLAIN = R++
src[XRANGEPLAIN] =
'[v=\\s]*(' +
src[XRANGEIDENTIFIER] +
')' +
'(?:\\.(' +
src[XRANGEIDENTIFIER] +
')' +
'(?:\\.(' +
src[XRANGEIDENTIFIER] +
')' +
'(?:' +
src[PRERELEASE] +
')?' +
src[BUILD] +
'?' +
')?)?'
var XRANGEPLAINLOOSE = R++
src[XRANGEPLAINLOOSE] =
'[v=\\s]*(' +
src[XRANGEIDENTIFIERLOOSE] +
')' +
'(?:\\.(' +
src[XRANGEIDENTIFIERLOOSE] +
')' +
'(?:\\.(' +
src[XRANGEIDENTIFIERLOOSE] +
')' +
'(?:' +
src[PRERELEASELOOSE] +
')?' +
src[BUILD] +
'?' +
')?)?'
var XRANGE = R++
src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'
var XRANGELOOSE = R++
src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'
// Tilde ranges.
// Meaning is "reasonably at or greater than"
var LONETILDE = R++
src[LONETILDE] = '(?:~>?)'
var TILDETRIM = R++
src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'
re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g')
var tildeTrimReplace = '$1~'
var TILDE = R++
src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'
var TILDELOOSE = R++
src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'
// Caret ranges.
// Meaning is "at least and backwards compatible with"
var LONECARET = R++
src[LONECARET] = '(?:\\^)'
var CARETTRIM = R++
src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'
re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g')
var caretTrimReplace = '$1^'
var CARET = R++
src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'
var CARETLOOSE = R++
src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'
// A simple gt/lt/eq thing, or just "" to indicate "any version"
var COMPARATORLOOSE = R++
src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'
var COMPARATOR = R++
src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'
// An expression to strip any whitespace between the gtlt and the thing
// it modifies, so that `> 1.2.3` ==> `>1.2.3`
var COMPARATORTRIM = R++
src[COMPARATORTRIM] =
'(\\s*)' + src[GTLT] + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'
// this one has to use the /g flag
re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g')
var comparatorTrimReplace = '$1$2$3'
// Something like `1.2.3 - 1.2.4`
// Note that these all use the loose form, because they'll be
// checked against either the strict or loose comparator form
// later.
var HYPHENRANGE = R++
src[HYPHENRANGE] =
'^\\s*(' +
src[XRANGEPLAIN] +
')' +
'\\s+-\\s+' +
'(' +
src[XRANGEPLAIN] +
')' +
'\\s*$'
var HYPHENRANGELOOSE = R++
src[HYPHENRANGELOOSE] =
'^\\s*(' +
src[XRANGEPLAINLOOSE] +
')' +
'\\s+-\\s+' +
'(' +
src[XRANGEPLAINLOOSE] +
')' +
'\\s*$'
// Star ranges basically just allow anything at all.
var STAR = R++
src[STAR] = '(<|>)?=?\\s*\\*'
// Compile to actual regexp objects.
// All are flag-free, unless they were created above with a flag.
for (var i = 0; i < R; i++) {
if (!re[i]) re[i] = new RegExp(src[i])
}
exports.parse = parse
function parse(version, loose) {
if (version instanceof SemVer) return version
if (typeof version !== 'string') return null
if (version.length > MAX_LENGTH) return null
var r = loose ? re[LOOSE] : re[FULL]
if (!r.test(version)) return null
try {
return new SemVer(version, loose)
} catch (er) {
return null
}
}
exports.valid = valid
function valid(version, loose) {
var v = parse(version, loose)
return v ? v.version : null
}
exports.clean = clean
function clean(version, loose) {
var s = parse(version.trim().replace(/^[=v]+/, ''), loose)
return s ? s.version : null
}
exports.SemVer = SemVer
function SemVer(version, loose) {
if (version instanceof SemVer) {
if (version.loose === loose) return version
else version = version.version
} else if (typeof version !== 'string') {
throw new TypeError('Invalid Version: ' + version)
}
if (version.length > MAX_LENGTH)
throw new TypeError(
'version is longer than ' + MAX_LENGTH + ' characters',
)
if (!(this instanceof SemVer)) return new SemVer(version, loose)
this.loose = loose
var m = version.trim().match(loose ? re[LOOSE] : re[FULL])
if (!m) throw new TypeError('Invalid Version: ' + version)
this.raw = version
// these are actually numbers
this.major = +m[1]
this.minor = +m[2]
this.patch = +m[3]
if (this.major > MAX_SAFE_INTEGER || this.major < 0)
throw new TypeError('Invalid major version')
if (this.minor > MAX_SAFE_INTEGER || this.minor < 0)
throw new TypeError('Invalid minor version')
if (this.patch > MAX_SAFE_INTEGER || this.patch < 0)
throw new TypeError('Invalid patch version')
// numberify any prerelease numeric ids
if (!m[4]) this.prerelease = []
else
this.prerelease = m[4].split('.').map(function (id) {
if (/^[0-9]+$/.test(id)) {
var num = +id
if (num >= 0 && num < MAX_SAFE_INTEGER) return num
}
return id
})
this.build = m[5] ? m[5].split('.') : []
this.format()
}
SemVer.prototype.format = function () {
this.version = this.major + '.' + this.minor + '.' + this.patch
if (this.prerelease.length) this.version += '-' + this.prerelease.join('.')
return this.version
}
SemVer.prototype.inspect = function () {
return '<SemVer "' + this + '">'
}
SemVer.prototype.toString = function () {
return this.version
}
SemVer.prototype.compare = function (other) {
if (!(other instanceof SemVer)) other = new SemVer(other, this.loose)
return this.compareMain(other) || this.comparePre(other)
}
SemVer.prototype.compareMain = function (other) {
if (!(other instanceof SemVer)) other = new SemVer(other, this.loose)
return (
compareIdentifiers(this.major, other.major) ||
compareIdentifiers(this.minor, other.minor) ||
compareIdentifiers(this.patch, other.patch)
)
}
SemVer.prototype.comparePre = function (other) {
if (!(other instanceof SemVer)) other = new SemVer(other, this.loose)
// NOT having a prerelease is > having one
if (this.prerelease.length && !other.prerelease.length) return -1
else if (!this.prerelease.length && other.prerelease.length) return 1
else if (!this.prerelease.length && !other.prerelease.length) return 0
var i = 0
do {
var a = this.prerelease[i]
var b = other.prerelease[i]
if (a === undefined && b === undefined) return 0
else if (b === undefined) return 1
else if (a === undefined) return -1
else if (a === b) continue
else return compareIdentifiers(a, b)
} while (++i)
}
// preminor will bump the version up to the next minor release, and immediately
// down to pre-release. premajor and prepatch work the same way.
SemVer.prototype.inc = function (release, identifier) {
switch (release) {
case 'premajor':
this.prerelease.length = 0
this.patch = 0
this.minor = 0
this.major++
this.inc('pre', identifier)
break
case 'preminor':
this.prerelease.length = 0
this.patch = 0
this.minor++
this.inc('pre', identifier)
break
case 'prepatch':
// If this is already a prerelease, it will bump to the next version
// drop any prereleases that might already exist, since they are not
// relevant at this point.
this.prerelease.length = 0
this.inc('patch', identifier)
this.inc('pre', identifier)
break
// If the input is a non-prerelease version, this acts the same as
// prepatch.
case 'prerelease':
if (this.prerelease.length === 0) this.inc('patch', identifier)
this.inc('pre', identifier)
break
case 'major':
// If this is a pre-major version, bump up to the same major version.
// Otherwise increment major.
// 1.0.0-5 bumps to 1.0.0
// 1.1.0 bumps to 2.0.0
if (
this.minor !== 0 ||
this.patch !== 0 ||
this.prerelease.length === 0
)
this.major++
this.minor = 0
this.patch = 0
this.prerelease = []
break
case 'minor':
// If this is a pre-minor version, bump up to the same minor version.
// Otherwise increment minor.
// 1.2.0-5 bumps to 1.2.0
// 1.2.1 bumps to 1.3.0
if (this.patch !== 0 || this.prerelease.length === 0) this.minor++
this.patch = 0
this.prerelease = []
break
case 'patch':
// If this is not a pre-release version, it will increment the patch.
// If it is a pre-release it will bump up to the same patch version.
// 1.2.0-5 patches to 1.2.0
// 1.2.0 patches to 1.2.1
if (this.prerelease.length === 0) this.patch++
this.prerelease = []
break
// This probably shouldn't be used publicly.
// 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
case 'pre':
if (this.prerelease.length === 0) this.prerelease = [0]
else {
var i = this.prerelease.length
while (--i >= 0) {
if (typeof this.prerelease[i] === 'number') {
this.prerelease[i]++
i = -2
}
}
if (i === -1)
// didn't increment anything
this.prerelease.push(0)
}
if (identifier) {
// 1.2.0-beta.1 bumps to 1.2.0-beta.2,
// 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
if (this.prerelease[0] === identifier) {
if (isNaN(this.prerelease[1])) this.prerelease = [identifier, 0]
} else this.prerelease = [identifier, 0]
}
break
default:
throw new Error('invalid increment argument: ' + release)
}
this.format()
return this
}
exports.inc = inc
function inc(version, release, loose, identifier) {
if (typeof loose === 'string') {
identifier = loose
loose = undefined
}
try {
return new SemVer(version, loose).inc(release, identifier).version
} catch (er) {
return null
}
}
exports.diff = diff
function diff(version1, version2) {
if (eq(version1, version2)) {
return null
} else {
var v1 = parse(version1)
var v2 = parse(version2)
if (v1.prerelease.length || v2.prerelease.length) {
for (var key in v1) {
if (key === 'major' || key === 'minor' || key === 'patch') {
if (v1[key] !== v2[key]) {
return 'pre' + key
}
}
}
return 'prerelease'
}
for (var key in v1) {
if (key === 'major' || key === 'minor' || key === 'patch') {
if (v1[key] !== v2[key]) {
return key
}
}
}
}
}
exports.compareIdentifiers = compareIdentifiers
var numeric = /^[0-9]+$/
function compareIdentifiers(a, b) {
var anum = numeric.test(a)
var bnum = numeric.test(b)
if (anum && bnum) {
a = +a
b = +b
}
return anum && !bnum ? -1 : bnum && !anum ? 1 : a < b ? -1 : a > b ? 1 : 0
}
exports.rcompareIdentifiers = rcompareIdentifiers
function rcompareIdentifiers(a, b) {
return compareIdentifiers(b, a)
}
exports.major = major
function major(a, loose) {
return new SemVer(a, loose).major
}
exports.minor = minor
function minor(a, loose) {
return new SemVer(a, loose).minor
}
exports.patch = patch
function patch(a, loose) {
return new SemVer(a, loose).patch
}
exports.compare = compare
function compare(a, b, loose) {
return new SemVer(a, loose).compare(b)
}
exports.compareLoose = compareLoose
function compareLoose(a, b) {
return compare(a, b, true)
}
exports.rcompare = rcompare
function rcompare(a, b, loose) {
return compare(b, a, loose)
}
exports.sort = sort
function sort(list, loose) {
return list.sort(function (a, b) {
return exports.compare(a, b, loose)
})
}
exports.rsort = rsort
function rsort(list, loose) {
return list.sort(function (a, b) {
return exports.rcompare(a, b, loose)
})
}
exports.gt = gt
function gt(a, b, loose) {
return compare(a, b, loose) > 0
}
exports.lt = lt
function lt(a, b, loose) {
return compare(a, b, loose) < 0
}
exports.eq = eq
function eq(a, b, loose) {
return compare(a, b, loose) === 0
}
exports.neq = neq
function neq(a, b, loose) {
return compare(a, b, loose) !== 0
}
exports.gte = gte
function gte(a, b, loose) {
return compare(a, b, loose) >= 0
}
exports.lte = lte
function lte(a, b, loose) {
return compare(a, b, loose) <= 0
}
exports.cmp = cmp
function cmp(a, op, b, loose) {
var ret
switch (op) {
case '===':
if (typeof a === 'object') a = a.version
if (typeof b === 'object') b = b.version
ret = a === b
break
case '!==':
if (typeof a === 'object') a = a.version
if (typeof b === 'object') b = b.version
ret = a !== b
break
case '':
case '=':
case '==':
ret = eq(a, b, loose)
break
case '!=':
ret = neq(a, b, loose)
break
case '>':
ret = gt(a, b, loose)
break
case '>=':
ret = gte(a, b, loose)
break
case '<':
ret = lt(a, b, loose)
break
case '<=':
ret = lte(a, b, loose)
break
default:
throw new TypeError('Invalid operator: ' + op)
}
return ret
}
exports.Comparator = Comparator
function Comparator(comp, loose) {
if (comp instanceof Comparator) {
if (comp.loose === loose) return comp
else comp = comp.value
}
if (!(this instanceof Comparator)) return new Comparator(comp, loose)
this.loose = loose
this.parse(comp)
if (this.semver === ANY) this.value = ''
else this.value = this.operator + this.semver.version
}
var ANY = {}
Comparator.prototype.parse = function (comp) {
var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
var m = comp.match(r)
if (!m) throw new TypeError('Invalid comparator: ' + comp)
this.operator = m[1]
if (this.operator === '=') this.operator = ''
// if it literally is just '>' or '' then allow anything.
if (!m[2]) this.semver = ANY
else this.semver = new SemVer(m[2], this.loose)
}
Comparator.prototype.inspect = function () {
return '<SemVer Comparator "' + this + '">'
}
Comparator.prototype.toString = function () {
return this.value
}
Comparator.prototype.test = function (version) {
if (this.semver === ANY) return true
if (typeof version === 'string') version = new SemVer(version, this.loose)
return cmp(version, this.operator, this.semver, this.loose)
}
exports.Range = Range
function Range(range, loose) {
if (range instanceof Range && range.loose === loose) return range
if (!(this instanceof Range)) return new Range(range, loose)
this.loose = loose
// First, split based on boolean or ||
this.raw = range
this.set = range
.split(/\s*\|\|\s*/)
.map(function (range) {
return this.parseRange(range.trim())
}, this)
.filter(function (c) {
// throw out any that are not relevant for whatever reason
return c.length
})
if (!this.set.length) {
throw new TypeError('Invalid SemVer Range: ' + range)
}
this.format()
}
Range.prototype.inspect = function () {
return '<SemVer Range "' + this.range + '">'
}
Range.prototype.format = function () {
this.range = this.set
.map(function (comps) {
return comps.join(' ').trim()
})
.join('||')
.trim()
return this.range
}
Range.prototype.toString = function () {
return this.range
}
Range.prototype.parseRange = function (range) {
var loose = this.loose
range = range.trim()
// `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]
range = range.replace(hr, hyphenReplace)
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace)
// `~ 1.2.3` => `~1.2.3`
range = range.replace(re[TILDETRIM], tildeTrimReplace)
// `^ 1.2.3` => `^1.2.3`
range = range.replace(re[CARETTRIM], caretTrimReplace)
// normalize spaces
range = range.split(/\s+/).join(' ')
// At this point, the range is completely trimmed and
// ready to be split into comparators.
var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]
var set = range
.split(' ')
.map(function (comp) {
return parseComparator(comp, loose)
})
.join(' ')
.split(/\s+/)
if (this.loose) {
// in loose mode, throw out any that are not valid comparators
set = set.filter(function (comp) {
return !!comp.match(compRe)
})
}
set = set.map(function (comp) {
return new Comparator(comp, loose)
})
return set
}
// Mostly just for testing and legacy API reasons
exports.toComparators = toComparators
function toComparators(range, loose) {
return new Range(range, loose).set.map(function (comp) {
return comp
.map(function (c) {
return c.value
})
.join(' ')
.trim()
.split(' ')
})
}
// comprised of xranges, tildes, stars, and gtlt's at this point.
// already replaced the hyphen ranges
// turn into a set of JUST comparators.
function parseComparator(comp, loose) {
comp = replaceCarets(comp, loose)
comp = replaceTildes(comp, loose)
comp = replaceXRanges(comp, loose)
comp = replaceStars(comp, loose)
return comp
}
function isX(id) {
return !id || id.toLowerCase() === 'x' || id === '*'
}
// ~, ~> --> * (any, kinda silly)
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
function replaceTildes(comp, loose) {
return comp
.trim()
.split(/\s+/)
.map(function (comp) {
return replaceTilde(comp, loose)
})
.join(' ')
}
function replaceTilde(comp, loose) {
var r = loose ? re[TILDELOOSE] : re[TILDE]
return comp.replace(r, function (_, M, m, p, pr) {
var ret
if (isX(M)) ret = ''
else if (isX(m)) ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
else if (isX(p))
// ~1.2 == >=1.2.0- <1.3.0-
ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
else if (pr) {
if (pr.charAt(0) !== '-') pr = '-' + pr
ret =
'>=' + M + '.' + m + '.' + p + pr + ' <' + M + '.' + (+m + 1) + '.0'
} else
// ~1.2.3 == >=1.2.3 <1.3.0
ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + (+m + 1) + '.0'
return ret
})
}
// ^ --> * (any, kinda silly)
// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
// ^1.2.3 --> >=1.2.3 <2.0.0
// ^1.2.0 --> >=1.2.0 <2.0.0
function replaceCarets(comp, loose) {
return comp
.trim()
.split(/\s+/)
.map(function (comp) {
return replaceCaret(comp, loose)
})
.join(' ')
}
function replaceCaret(comp, loose) {
var r = loose ? re[CARETLOOSE] : re[CARET]
return comp.replace(r, function (_, M, m, p, pr) {
var ret
if (isX(M)) ret = ''
else if (isX(m)) ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
else if (isX(p)) {
if (M === '0')
ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
else ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'
} else if (pr) {
if (pr.charAt(0) !== '-') pr = '-' + pr
if (M === '0') {
if (m === '0')
ret =
'>=' +
M +
'.' +
m +
'.' +
p +
pr +
' <' +
M +
'.' +
m +
'.' +
(+p + 1)
else
ret =
'>=' +
M +
'.' +
m +
'.' +
p +
pr +
' <' +
M +
'.' +
(+m + 1) +
'.0'
} else
ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + (+M + 1) + '.0.0'
} else {
if (M === '0') {
if (m === '0')
ret =
'>=' + M + '.' + m + '.' + p + ' <' + M + '.' + m + '.' + (+p + 1)
else
ret =
'>=' + M + '.' + m + '.' + p + ' <' + M + '.' + (+m + 1) + '.0'
} else ret = '>=' + M + '.' + m + '.' + p + ' <' + (+M + 1) + '.0.0'
}
return ret
})
}
function replaceXRanges(comp, loose) {
return comp
.split(/\s+/)
.map(function (comp) {
return replaceXRange(comp, loose)
})
.join(' ')
}
function replaceXRange(comp, loose) {
comp = comp.trim()
var r = loose ? re[XRANGELOOSE] : re[XRANGE]
return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
var xM = isX(M)
var xm = xM || isX(m)
var xp = xm || isX(p)
var anyX = xp
if (gtlt === '=' && anyX) gtlt = ''
if (xM) {
if (gtlt === '>' || gtlt === '<') {
// nothing is allowed
ret = '<0.0.0'
} else {
// nothing is forbidden
ret = '*'
}
} else if (gtlt && anyX) {
// replace X with 0
if (xm) m = 0
if (xp) p = 0
if (gtlt === '>') {
// >1 => >=2.0.0
// >1.2 => >=1.3.0
// >1.2.3 => >= 1.2.4
gtlt = '>='
if (xm) {
M = +M + 1
m = 0
p = 0
} else if (xp) {
m = +m + 1
p = 0
}
} else if (gtlt === '<=') {
// <=0.7.x is actually <0.8.0, since any 0.7.x should
// pass. Similarly, <=7.x is actually <8.0.0, etc.
gtlt = '<'
if (xm) M = +M + 1
else m = +m + 1
}
ret = gtlt + M + '.' + m + '.' + p
} else if (xm) {
ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'
} else if (xp) {
ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'
}
return ret
})
}
// Because * is AND-ed with everything else in the comparator,
// and '' means "any version", just remove the *s entirely.
function replaceStars(comp, loose) {
// Looseness is ignored here. star is always as loose as it gets!
return comp.trim().replace(re[STAR], '')
}
// This function is passed to string.replace(re[HYPHENRANGE])
// M, m, patch, prerelease, build
// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
// 1.2 - 3.4 => >=1.2.0 <3.5.0
function hyphenReplace(
$0,
from,
fM,
fm,
fp,
fpr,
fb,
to,
tM,
tm,
tp,
tpr,
tb,
) {
if (isX(fM)) from = ''
else if (isX(fm)) from = '>=' + fM + '.0.0'
else if (isX(fp)) from = '>=' + fM + '.' + fm + '.0'
else from = '>=' + from
if (isX(tM)) to = ''
else if (isX(tm)) to = '<' + (+tM + 1) + '.0.0'
else if (isX(tp)) to = '<' + tM + '.' + (+tm + 1) + '.0'
else if (tpr) to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr
else to = '<=' + to
return (from + ' ' + to).trim()
}
// if ANY of the sets match ALL of its comparators, then pass
Range.prototype.test = function (version) {
if (!version) return false
if (typeof version === 'string') version = new SemVer(version, this.loose)
for (var i = 0; i < this.set.length; i++) {
if (testSet(this.set[i], version)) return true
}
return false
}
function testSet(set, version) {
for (var i = 0; i < set.length; i++) {
if (!set[i].test(version)) return false
}
if (version.prerelease.length) {
// Find the set of versions that are allowed to have prereleases
// For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
// That should allow `1.2.3-pr.2` to pass.
// However, `1.2.4-alpha.notready` should NOT be allowed,
// even though it's within the range set by the comparators.
for (var i = 0; i < set.length; i++) {
if (set[i].semver === ANY) continue
if (set[i].semver.prerelease.length > 0) {
var allowed = set[i].semver
if (
allowed.major === version.major &&
allowed.minor === version.minor &&
allowed.patch === version.patch
)
return true
}
}
// Version has a -pre, but it's not one of the ones we like.
return false
}
return true
}
exports.satisfies = satisfies
function satisfies(version, range, loose) {
try {
range = new Range(range, loose)
} catch (er) {
return false
}
return range.test(version)
}
exports.maxSatisfying = maxSatisfying
function maxSatisfying(versions, range, loose) {
return (
versions
.filter(function (version) {
return satisfies(version, range, loose)
})
.sort(function (a, b) {
return rcompare(a, b, loose)
})[0] || null
)
}
exports.validRange = validRange
function validRange(range, loose) {
try {
// Return '*' instead of '' so that truthiness works.
// This will throw if it's invalid anyway
return new Range(range, loose).range || '*'
} catch (er) {
return null
}
}
// Determine if version is less than all the versions possible in the range
exports.ltr = ltr
function ltr(version, range, loose) {
return outside(version, range, '<', loose)
}
// Determine if version is greater than all the versions possible in the range.
exports.gtr = gtr
function gtr(version, range, loose) {
return outside(version, range, '>', loose)
}
exports.outside = outside
function outside(version, range, hilo, loose) {
version = new SemVer(version, loose)
range = new Range(range, loose)
var gtfn, ltefn, ltfn, comp, ecomp
switch (hilo) {
case '>':
gtfn = gt
ltefn = lte
ltfn = lt
comp = '>'
ecomp = '>='
break
case '<':
gtfn = lt
ltefn = gte
ltfn = gt
comp = '<'
ecomp = '<='
break
default:
throw new TypeError('Must provide a hilo val of "<" or ">"')
}
// If it satisifes the range it is not outside
if (satisfies(version, range, loose)) {
return false
}
// From now on, variable terms are as if we're in "gtr" mode.
// but note that everything is flipped for the "ltr" function.
for (var i = 0; i < range.set.length; ++i) {
var comparators = range.set[i]
var high = null
var low = null
comparators.forEach(function (comparator) {
if (comparator.semver === ANY) {
comparator = new Comparator('>=0.0.0')
}
high = high || comparator
low = low || comparator
if (gtfn(comparator.semver, high.semver, loose)) {
high = comparator
} else if (ltfn(comparator.semver, low.semver, loose)) {
low = comparator
}
})
// If the edge version comparator has a operator then our version
// isn't outside it
if (high.operator === comp || high.operator === ecomp) {
return false
}
// If the lowest version comparator has an operator and our version
// is less than it then it isn't higher than the range
if (
(!low.operator || low.operator === comp) &&
ltefn(version, low.semver)
) {
return false
} else if (low.operator === ecomp && ltfn(version, low.semver)) {
return false
}
}
return true
}
// Use the define() function if we're in AMD land
if (typeof define === 'function' && define.amd) define(exports)
})(
typeof exports === 'object'
? exports
: typeof define === 'function' && define.amd
? {}
: (window.semver = {}),
)
/** </script src="semver.browser.js"> **/
;(function collectEbaReportingModules(window, document) {
'use strict'
const selectors = {
MODULE_ARTICLE: `#block-eba-theme-content > div > div > div.view-content > div > article.rtt-module`,
FRAMEWORK_RELEASE: `div.rtt-module__metadata > div > a`,
META_DATA: `div.rtt-module__metadata`,
MODULE_ABBR: `div.rtt-module__metadata > span.badge.badge--rtt`,
MODULE_DESC: `div.rtt-module__text`,
MODULE_TITLE: `.rtt-module__title > a`,
RESOURCES: `.rtt-module__actions > a`,
STATUS: `.rtt-module__metadata > span.link-icon.link-icon--activity > strong`,
VALID_FROM: `div.rtt-module__metadata > span.link-icon.link-icon--calendar > strong > time`,
VALID_TO: ``,
}
const EBA_REPORTING_MODULE_TIME_TRAVELLER_URL =
'https://www.eba.europa.eu/reporting-time-traveller'
const EBA_REPORTING_MODULE_BY_NAME_URL =
'https://www.eba.europa.eu/reporting-time-traveller/reporting-by-name?name='
class NavigateStep {
constructor(title, url, type = 'navigate') {
this.assertedEvents = [
{
type: 'navigation',
title,
url,
},
]
this.type = type
this.url = url
}
toString() {
return JSON.stringify(this)
}
}
const createNavigationEventSteps = (window = window, document = document) => {
const selectMenu =
document.getElementById('edit-name') ||
document.getElementById('edit-reporting-module')
return Array.from(selectMenu.options).map(
({ textContent, value }) =>
new NavigateStep(
textContent,
`${EBA_REPORTING_MODULE_BY_NAME_URL}${value}`,
),
)
}
const createViewportStep = () => {
return {
type: 'setViewport',
width: 1495,
height: 564,
deviceScaleFactor: 1,
isMobile: false,
hasTouch: false,
isLandscape: false,
}
}
const createRecorderJson = (window = window, document = document) => {
const isoDate = new Date().toISOString().replace(/T.*/gim, '')
const title = `eba-reporting-modules-by-name-${isoDate}`
const viewportStep = createViewportStep()
const navigationEvents = createNavigationEventSteps(
window,
document,
).filter(({ url }) => !url.endsWith('?name=All'))
const steps = [viewportStep, ...navigationEvents]
return {
steps,
title,
}
}
const loadReportingModuleRecording = (
window = window,
document = document,
) => {
const recording = createRecorderJson(window, document)
window.localStorage.setItem(
'za.eba.recording.elt.reportingModules',
JSON.stringify(recording),
)
return recording
}
const getAbbr = (element = document) => {
const elem = element.querySelector(selectors.MODULE_ABBR)
let abbreviation = null
if (elem) {
abbreviation = elem.innerText
} else {
try {
const title = getTitle()
const words = title.split(/\s+/)
const ONE = 1
if (words.length == ONE) {
abbreviation = words[0].toUpperCase()
} else {
abbreviation = words
.map((word) => word.charAt(0).toUpperCase())
.join('')
}
} catch (err) {
window.console.error(err)
}
}
return abbreviation
? abbreviation.replace(/[\s+|\-|\(|\)]/g, '_')
: abbreviation
}
const loadAllModulesFromLocalStorage = () => {
const len = window.localStorage.length
const modules = []
for (let i = 0; i < len; i++) {
const key = window.localStorage.key(i)
const json = window.localStorage.getItem(key)
modules.push(JSON.parse(json))
}
return _.orderBy(modules, ['abbr', 'release'])
}
const getItemBySelector = (selector, element = document) => {
let item = null
try {
item = element.querySelector(selector).innerText
} catch (err) {
window.console.error(err)
}
return item
}
const getDescription = (element = document) => {
return getItemBySelector(selectors.MODULE_DESC, element)
}
const getFileExtension = (elem) => {
const uri = new URL(elem.href)
const ext = uri.pathname.split('.').pop()
return ext.toLowerCase()
}
const getRelease = (element = document) => {
const release = getItemBySelector(selectors.FRAMEWORK_RELEASE, element)
return release
}
const getStatus = (element = document) => {
const status = getItemBySelector(selectors.STATUS, element)
if (status) {
return status.toLocaleLowerCase()
}
return status
}
const getTitle = (element = document) => {
try {
const option =
element.getElementById('edit-reporting-module') ||
element.getElementById('edit-name')
return option.querySelector(`option:checked`).text
} catch (err) {
window.console.error(err)
return null
}
}
const getValidFrom = (element = document) => {
const validFrom = element.querySelector(selectors.VALID_FROM)
return validFrom.getAttribute('datetime')
}
const convertReleaseToSemver = (module) => {
let version = null
if (_.has(module, 'release')) {
version = semver.parse(`${module.release.replace(/^v/, '')}.0`)
}
return version
}
const setValidFromDates = (modules = []) => {
const grouped = _.groupBy(modules, 'abbr')
const abbrs = Object.keys(grouped)
abbrs.forEach((abbr) => {
const { semver } = window
const modules = _.sortBy(grouped[abbr], ['release'])
const ONE = 1
const { length } = modules
for (let index = 0; index < length; index++) {
if (length > ONE) {
const a = modules[index]
const b = modules[index + 1]
if (b && a && a.status === 'superseded') {
const releaseA = convertReleaseToSemver(a)
const releaseB = convertReleaseToSemver(b)
if (b && semver.lt(releaseA, releaseB)) {
const validTo = new Date(b.valid_from)
validTo.setDate(validTo.getDate() - ONE)
a.valid_to = validTo.toISOString()
}
}
}
}
})
return modules
}
const isTemplate = (elem) => {
return getFileExtension(elem) === 'xlsx'
}
const loadUrls = (reportingModule, element = document) => {
reportingModule.urls.source = location.href
const resources = Array.from(element.querySelectorAll(selectors.RESOURCES))
resources.forEach((elem) => {
if (isTemplate(elem)) {
reportingModule.urls.templates.push(elem.href)
} else {
reportingModule.urls.docs.push(elem.href)
}
})
}
const nullReportingModule = {
abbr: getAbbr(),
description: null,
release: null,
status: null,
templates: [],
title: getTitle(),
urls: {
docs: [],
source: location.href,
templates: [],
},
valid_from: null,
valid_to: null,
}
class ReportingModule {
constructor(element = document) {
try {
this.abbr = getAbbr(element)
this.description = getDescription(element)
this.release = getRelease(element)
this.status = getStatus(element)
this.templates = []
this.title = getTitle()
this.urls = { docs: [], source: null, templates: [] }
this.valid_from = getValidFrom(element)
this.valid_to = null
loadUrls(this, element)
} catch (err) {
Object.assign(this, nullReportingModule)
}
}
toString() {
return JSON.stringify(this)
}
}
const extractEbaReportingModules = (window = window, document = document) => {
const za = { eba: {} }
const modules = document.querySelectorAll(selectors.MODULE_ARTICLE)
modules.forEach((module) => {
za.eba.module = new ReportingModule(module)
const moduleKey = `za.eba.module.${za.eba.module.abbr}.${za.eba.module.release}`
window.localStorage.setItem(moduleKey, za.eba.module.toString())
})
return setValidFromDates(loadAllModulesFromLocalStorage())
}
const extendDocumentWithNamespace = (
document,
reportingModules = [],
recording = null,
namespace = 'za',
) => {
const ns = namespace || 'za'
document[ns] = document[ns] ? document[ns] : { eba: {} }
document[ns] = {
eba: {
recording,
reportingModules,
},
}
}
const assertEquals = (elemOne, elemTwo) => {
const verdict =
elemOne === elemTwo || JSON.stringify(elemOne) === JSON.stringify(elemTwo)
if (!verdict) {
const message = 'AssertionError: The two elements are not equal.'
throw new TypeError(message)
}
}
const main = (window = window, document = document) => {
const reportingModules = extractEbaReportingModules(
window,
document,
).filter((module) => {
return !_.has(module, 'steps') && !Array.isArray(module.steps)
})
const recording = loadReportingModuleRecording(window, document)
extendDocumentWithNamespace(document, reportingModules, recording)
assertEquals(reportingModules, document.za.eba.reportingModules)
// document.za.eba.recording = recording
window.console.log(`## Usage
### List EBA Reporting Modules' Metadata
document.za.eba.reportingModules
### Get Reporting Module ELT Instructions
document.za.eba.recording
`)
}
main(window, document)
})(window, document)