mirror of
https://github.com/akkuman/gitea-release-action.git
synced 2026-03-05 12:22:06 +00:00
fix: add dep glob
This commit is contained in:
7916
dist/index.js
vendored
7916
dist/index.js
vendored
@@ -1822,6 +1822,285 @@ function isLoopbackAddress(host) {
|
||||
}
|
||||
//# sourceMappingURL=proxy.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 9417:
|
||||
/***/ ((module) => {
|
||||
|
||||
|
||||
module.exports = balanced;
|
||||
function balanced(a, b, str) {
|
||||
if (a instanceof RegExp) a = maybeMatch(a, str);
|
||||
if (b instanceof RegExp) b = maybeMatch(b, str);
|
||||
|
||||
var r = range(a, b, str);
|
||||
|
||||
return r && {
|
||||
start: r[0],
|
||||
end: r[1],
|
||||
pre: str.slice(0, r[0]),
|
||||
body: str.slice(r[0] + a.length, r[1]),
|
||||
post: str.slice(r[1] + b.length)
|
||||
};
|
||||
}
|
||||
|
||||
function maybeMatch(reg, str) {
|
||||
var m = str.match(reg);
|
||||
return m ? m[0] : null;
|
||||
}
|
||||
|
||||
balanced.range = range;
|
||||
function range(a, b, str) {
|
||||
var begs, beg, left, right, result;
|
||||
var ai = str.indexOf(a);
|
||||
var bi = str.indexOf(b, ai + 1);
|
||||
var i = ai;
|
||||
|
||||
if (ai >= 0 && bi > 0) {
|
||||
if(a===b) {
|
||||
return [ai, bi];
|
||||
}
|
||||
begs = [];
|
||||
left = str.length;
|
||||
|
||||
while (i >= 0 && !result) {
|
||||
if (i == ai) {
|
||||
begs.push(i);
|
||||
ai = str.indexOf(a, i + 1);
|
||||
} else if (begs.length == 1) {
|
||||
result = [ begs.pop(), bi ];
|
||||
} else {
|
||||
beg = begs.pop();
|
||||
if (beg < left) {
|
||||
left = beg;
|
||||
right = bi;
|
||||
}
|
||||
|
||||
bi = str.indexOf(b, i + 1);
|
||||
}
|
||||
|
||||
i = ai < bi && ai >= 0 ? ai : bi;
|
||||
}
|
||||
|
||||
if (begs.length) {
|
||||
result = [ left, right ];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3717:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
var balanced = __nccwpck_require__(9417);
|
||||
|
||||
module.exports = expandTop;
|
||||
|
||||
var escSlash = '\0SLASH'+Math.random()+'\0';
|
||||
var escOpen = '\0OPEN'+Math.random()+'\0';
|
||||
var escClose = '\0CLOSE'+Math.random()+'\0';
|
||||
var escComma = '\0COMMA'+Math.random()+'\0';
|
||||
var escPeriod = '\0PERIOD'+Math.random()+'\0';
|
||||
|
||||
function numeric(str) {
|
||||
return parseInt(str, 10) == str
|
||||
? parseInt(str, 10)
|
||||
: str.charCodeAt(0);
|
||||
}
|
||||
|
||||
function escapeBraces(str) {
|
||||
return str.split('\\\\').join(escSlash)
|
||||
.split('\\{').join(escOpen)
|
||||
.split('\\}').join(escClose)
|
||||
.split('\\,').join(escComma)
|
||||
.split('\\.').join(escPeriod);
|
||||
}
|
||||
|
||||
function unescapeBraces(str) {
|
||||
return str.split(escSlash).join('\\')
|
||||
.split(escOpen).join('{')
|
||||
.split(escClose).join('}')
|
||||
.split(escComma).join(',')
|
||||
.split(escPeriod).join('.');
|
||||
}
|
||||
|
||||
|
||||
// Basically just str.split(","), but handling cases
|
||||
// where we have nested braced sections, which should be
|
||||
// treated as individual members, like {a,{b,c},d}
|
||||
function parseCommaParts(str) {
|
||||
if (!str)
|
||||
return [''];
|
||||
|
||||
var parts = [];
|
||||
var m = balanced('{', '}', str);
|
||||
|
||||
if (!m)
|
||||
return str.split(',');
|
||||
|
||||
var pre = m.pre;
|
||||
var body = m.body;
|
||||
var post = m.post;
|
||||
var p = pre.split(',');
|
||||
|
||||
p[p.length-1] += '{' + body + '}';
|
||||
var postParts = parseCommaParts(post);
|
||||
if (post.length) {
|
||||
p[p.length-1] += postParts.shift();
|
||||
p.push.apply(p, postParts);
|
||||
}
|
||||
|
||||
parts.push.apply(parts, p);
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
function expandTop(str) {
|
||||
if (!str)
|
||||
return [];
|
||||
|
||||
// I don't know why Bash 4.3 does this, but it does.
|
||||
// Anything starting with {} will have the first two bytes preserved
|
||||
// but *only* at the top level, so {},a}b will not expand to anything,
|
||||
// but a{},b}c will be expanded to [a}c,abc].
|
||||
// One could argue that this is a bug in Bash, but since the goal of
|
||||
// this module is to match Bash's rules, we escape a leading {}
|
||||
if (str.substr(0, 2) === '{}') {
|
||||
str = '\\{\\}' + str.substr(2);
|
||||
}
|
||||
|
||||
return expand(escapeBraces(str), true).map(unescapeBraces);
|
||||
}
|
||||
|
||||
function embrace(str) {
|
||||
return '{' + str + '}';
|
||||
}
|
||||
function isPadded(el) {
|
||||
return /^-?0\d/.test(el);
|
||||
}
|
||||
|
||||
function lte(i, y) {
|
||||
return i <= y;
|
||||
}
|
||||
function gte(i, y) {
|
||||
return i >= y;
|
||||
}
|
||||
|
||||
function expand(str, isTop) {
|
||||
var expansions = [];
|
||||
|
||||
var m = balanced('{', '}', str);
|
||||
if (!m) return [str];
|
||||
|
||||
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
||||
var pre = m.pre;
|
||||
var post = m.post.length
|
||||
? expand(m.post, false)
|
||||
: [''];
|
||||
|
||||
if (/\$$/.test(m.pre)) {
|
||||
for (var k = 0; k < post.length; k++) {
|
||||
var expansion = pre+ '{' + m.body + '}' + post[k];
|
||||
expansions.push(expansion);
|
||||
}
|
||||
} else {
|
||||
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
||||
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
||||
var isSequence = isNumericSequence || isAlphaSequence;
|
||||
var isOptions = m.body.indexOf(',') >= 0;
|
||||
if (!isSequence && !isOptions) {
|
||||
// {a},b}
|
||||
if (m.post.match(/,.*\}/)) {
|
||||
str = m.pre + '{' + m.body + escClose + m.post;
|
||||
return expand(str);
|
||||
}
|
||||
return [str];
|
||||
}
|
||||
|
||||
var n;
|
||||
if (isSequence) {
|
||||
n = m.body.split(/\.\./);
|
||||
} else {
|
||||
n = parseCommaParts(m.body);
|
||||
if (n.length === 1) {
|
||||
// x{{a,b}}y ==> x{a}y x{b}y
|
||||
n = expand(n[0], false).map(embrace);
|
||||
if (n.length === 1) {
|
||||
return post.map(function(p) {
|
||||
return m.pre + n[0] + p;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this point, n is the parts, and we know it's not a comma set
|
||||
// with a single entry.
|
||||
var N;
|
||||
|
||||
if (isSequence) {
|
||||
var x = numeric(n[0]);
|
||||
var y = numeric(n[1]);
|
||||
var width = Math.max(n[0].length, n[1].length)
|
||||
var incr = n.length == 3
|
||||
? Math.abs(numeric(n[2]))
|
||||
: 1;
|
||||
var test = lte;
|
||||
var reverse = y < x;
|
||||
if (reverse) {
|
||||
incr *= -1;
|
||||
test = gte;
|
||||
}
|
||||
var pad = n.some(isPadded);
|
||||
|
||||
N = [];
|
||||
|
||||
for (var i = x; test(i, y); i += incr) {
|
||||
var c;
|
||||
if (isAlphaSequence) {
|
||||
c = String.fromCharCode(i);
|
||||
if (c === '\\')
|
||||
c = '';
|
||||
} else {
|
||||
c = String(i);
|
||||
if (pad) {
|
||||
var need = width - c.length;
|
||||
if (need > 0) {
|
||||
var z = new Array(need + 1).join('0');
|
||||
if (i < 0)
|
||||
c = '-' + z + c.slice(1);
|
||||
else
|
||||
c = z + c;
|
||||
}
|
||||
}
|
||||
}
|
||||
N.push(c);
|
||||
}
|
||||
} else {
|
||||
N = [];
|
||||
|
||||
for (var j = 0; j < n.length; j++) {
|
||||
N.push.apply(N, expand(n[j], false));
|
||||
}
|
||||
}
|
||||
|
||||
for (var j = 0; j < N.length; j++) {
|
||||
for (var k = 0; k < post.length; k++) {
|
||||
var expansion = pre + N[j] + post[k];
|
||||
if (!isTop || isSequence || expansion)
|
||||
expansions.push(expansion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expansions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 1402:
|
||||
@@ -33001,6 +33280,64 @@ module.exports = parseParams
|
||||
/******/ }
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/create fake namespace object */
|
||||
/******/ (() => {
|
||||
/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);
|
||||
/******/ var leafPrototypes;
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 16: return value when it's Promise-like
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __nccwpck_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = this(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if(typeof value === 'object' && value) {
|
||||
/******/ if((mode & 4) && value.__esModule) return value;
|
||||
/******/ if((mode & 16) && typeof value.then === 'function') return value;
|
||||
/******/ }
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __nccwpck_require__.r(ns);
|
||||
/******/ var def = {};
|
||||
/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];
|
||||
/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {
|
||||
/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));
|
||||
/******/ }
|
||||
/******/ def['default'] = () => (value);
|
||||
/******/ __nccwpck_require__.d(ns, def);
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ (() => {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __nccwpck_require__.d = (exports, definition) => {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__nccwpck_require__.o(definition, key) && !__nccwpck_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __nccwpck_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __nccwpck_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/compat */
|
||||
/******/
|
||||
/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = new URL('.', import.meta.url).pathname.slice(import.meta.url.match(/^file:\/\/\/\w:/) ? 1 : 0, -1) + "/";
|
||||
@@ -33009,11 +33346,7546 @@ module.exports = parseParams
|
||||
var __webpack_exports__ = {};
|
||||
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||
(() => {
|
||||
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(7147);
|
||||
/* harmony import */ var buffer__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(4300);
|
||||
/* harmony import */ var _actions_core__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(2186);
|
||||
/* harmony import */ var gitea_api__WEBPACK_IMPORTED_MODULE_3__ = __nccwpck_require__(5371);
|
||||
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_4__ = __nccwpck_require__(1017);
|
||||
|
||||
// EXTERNAL MODULE: external "fs"
|
||||
var external_fs_ = __nccwpck_require__(7147);
|
||||
var external_fs_namespaceObject = /*#__PURE__*/__nccwpck_require__.t(external_fs_, 2);
|
||||
// EXTERNAL MODULE: external "buffer"
|
||||
var external_buffer_ = __nccwpck_require__(4300);
|
||||
// EXTERNAL MODULE: ./node_modules/brace-expansion/index.js
|
||||
var brace_expansion = __nccwpck_require__(3717);
|
||||
;// CONCATENATED MODULE: ./node_modules/minimatch/dist/mjs/assert-valid-pattern.js
|
||||
const MAX_PATTERN_LENGTH = 1024 * 64;
|
||||
const assertValidPattern = (pattern) => {
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('invalid pattern');
|
||||
}
|
||||
if (pattern.length > MAX_PATTERN_LENGTH) {
|
||||
throw new TypeError('pattern is too long');
|
||||
}
|
||||
};
|
||||
//# sourceMappingURL=assert-valid-pattern.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/minimatch/dist/mjs/brace-expressions.js
|
||||
// translate the various posix character classes into unicode properties
|
||||
// this works across all unicode locales
|
||||
// { <posix class>: [<translation>, /u flag required, negated]
|
||||
const posixClasses = {
|
||||
'[:alnum:]': ['\\p{L}\\p{Nl}\\p{Nd}', true],
|
||||
'[:alpha:]': ['\\p{L}\\p{Nl}', true],
|
||||
'[:ascii:]': ['\\x' + '00-\\x' + '7f', false],
|
||||
'[:blank:]': ['\\p{Zs}\\t', true],
|
||||
'[:cntrl:]': ['\\p{Cc}', true],
|
||||
'[:digit:]': ['\\p{Nd}', true],
|
||||
'[:graph:]': ['\\p{Z}\\p{C}', true, true],
|
||||
'[:lower:]': ['\\p{Ll}', true],
|
||||
'[:print:]': ['\\p{C}', true],
|
||||
'[:punct:]': ['\\p{P}', true],
|
||||
'[:space:]': ['\\p{Z}\\t\\r\\n\\v\\f', true],
|
||||
'[:upper:]': ['\\p{Lu}', true],
|
||||
'[:word:]': ['\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}', true],
|
||||
'[:xdigit:]': ['A-Fa-f0-9', false],
|
||||
};
|
||||
// only need to escape a few things inside of brace expressions
|
||||
// escapes: [ \ ] -
|
||||
const braceEscape = (s) => s.replace(/[[\]\\-]/g, '\\$&');
|
||||
// escape all regexp magic characters
|
||||
const regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
// everything has already been escaped, we just have to join
|
||||
const rangesToString = (ranges) => ranges.join('');
|
||||
// takes a glob string at a posix brace expression, and returns
|
||||
// an equivalent regular expression source, and boolean indicating
|
||||
// whether the /u flag needs to be applied, and the number of chars
|
||||
// consumed to parse the character class.
|
||||
// This also removes out of order ranges, and returns ($.) if the
|
||||
// entire class just no good.
|
||||
const parseClass = (glob, position) => {
|
||||
const pos = position;
|
||||
/* c8 ignore start */
|
||||
if (glob.charAt(pos) !== '[') {
|
||||
throw new Error('not in a brace expression');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
const ranges = [];
|
||||
const negs = [];
|
||||
let i = pos + 1;
|
||||
let sawStart = false;
|
||||
let uflag = false;
|
||||
let escaping = false;
|
||||
let negate = false;
|
||||
let endPos = pos;
|
||||
let rangeStart = '';
|
||||
WHILE: while (i < glob.length) {
|
||||
const c = glob.charAt(i);
|
||||
if ((c === '!' || c === '^') && i === pos + 1) {
|
||||
negate = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (c === ']' && sawStart && !escaping) {
|
||||
endPos = i + 1;
|
||||
break;
|
||||
}
|
||||
sawStart = true;
|
||||
if (c === '\\') {
|
||||
if (!escaping) {
|
||||
escaping = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// escaped \ char, fall through and treat like normal char
|
||||
}
|
||||
if (c === '[' && !escaping) {
|
||||
// either a posix class, a collation equivalent, or just a [
|
||||
for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) {
|
||||
if (glob.startsWith(cls, i)) {
|
||||
// invalid, [a-[] is fine, but not [a-[:alpha]]
|
||||
if (rangeStart) {
|
||||
return ['$.', false, glob.length - pos, true];
|
||||
}
|
||||
i += cls.length;
|
||||
if (neg)
|
||||
negs.push(unip);
|
||||
else
|
||||
ranges.push(unip);
|
||||
uflag = uflag || u;
|
||||
continue WHILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// now it's just a normal character, effectively
|
||||
escaping = false;
|
||||
if (rangeStart) {
|
||||
// throw this range away if it's not valid, but others
|
||||
// can still match.
|
||||
if (c > rangeStart) {
|
||||
ranges.push(braceEscape(rangeStart) + '-' + braceEscape(c));
|
||||
}
|
||||
else if (c === rangeStart) {
|
||||
ranges.push(braceEscape(c));
|
||||
}
|
||||
rangeStart = '';
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// now might be the start of a range.
|
||||
// can be either c-d or c-] or c<more...>] or c] at this point
|
||||
if (glob.startsWith('-]', i + 1)) {
|
||||
ranges.push(braceEscape(c + '-'));
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
if (glob.startsWith('-', i + 1)) {
|
||||
rangeStart = c;
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
// not the start of a range, just a single character
|
||||
ranges.push(braceEscape(c));
|
||||
i++;
|
||||
}
|
||||
if (endPos < i) {
|
||||
// didn't see the end of the class, not a valid class,
|
||||
// but might still be valid as a literal match.
|
||||
return ['', false, 0, false];
|
||||
}
|
||||
// if we got no ranges and no negates, then we have a range that
|
||||
// cannot possibly match anything, and that poisons the whole glob
|
||||
if (!ranges.length && !negs.length) {
|
||||
return ['$.', false, glob.length - pos, true];
|
||||
}
|
||||
// if we got one positive range, and it's a single character, then that's
|
||||
// not actually a magic pattern, it's just that one literal character.
|
||||
// we should not treat that as "magic", we should just return the literal
|
||||
// character. [_] is a perfectly valid way to escape glob magic chars.
|
||||
if (negs.length === 0 &&
|
||||
ranges.length === 1 &&
|
||||
/^\\?.$/.test(ranges[0]) &&
|
||||
!negate) {
|
||||
const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0];
|
||||
return [regexpEscape(r), false, endPos - pos, false];
|
||||
}
|
||||
const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']';
|
||||
const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']';
|
||||
const comb = ranges.length && negs.length
|
||||
? '(' + sranges + '|' + snegs + ')'
|
||||
: ranges.length
|
||||
? sranges
|
||||
: snegs;
|
||||
return [comb, uflag, endPos - pos, true];
|
||||
};
|
||||
//# sourceMappingURL=brace-expressions.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/minimatch/dist/mjs/unescape.js
|
||||
/**
|
||||
* Un-escape a string that has been escaped with {@link escape}.
|
||||
*
|
||||
* If the {@link windowsPathsNoEscape} option is used, then square-brace
|
||||
* escapes are removed, but not backslash escapes. For example, it will turn
|
||||
* the string `'[*]'` into `*`, but it will not turn `'\\*'` into `'*'`,
|
||||
* becuase `\` is a path separator in `windowsPathsNoEscape` mode.
|
||||
*
|
||||
* When `windowsPathsNoEscape` is not set, then both brace escapes and
|
||||
* backslash escapes are removed.
|
||||
*
|
||||
* Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot be escaped
|
||||
* or unescaped.
|
||||
*/
|
||||
const unescape_unescape = (s, { windowsPathsNoEscape = false, } = {}) => {
|
||||
return windowsPathsNoEscape
|
||||
? s.replace(/\[([^\/\\])\]/g, '$1')
|
||||
: s.replace(/((?!\\).|^)\[([^\/\\])\]/g, '$1$2').replace(/\\([^\/])/g, '$1');
|
||||
};
|
||||
//# sourceMappingURL=unescape.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/minimatch/dist/mjs/ast.js
|
||||
// parse a single path portion
|
||||
|
||||
|
||||
const types = new Set(['!', '?', '+', '*', '@']);
|
||||
const isExtglobType = (c) => types.has(c);
|
||||
// Patterns that get prepended to bind to the start of either the
|
||||
// entire string, or just a single path portion, to prevent dots
|
||||
// and/or traversal patterns, when needed.
|
||||
// Exts don't need the ^ or / bit, because the root binds that already.
|
||||
const startNoTraversal = '(?!(?:^|/)\\.\\.?(?:$|/))';
|
||||
const startNoDot = '(?!\\.)';
|
||||
// characters that indicate a start of pattern needs the "no dots" bit,
|
||||
// because a dot *might* be matched. ( is not in the list, because in
|
||||
// the case of a child extglob, it will handle the prevention itself.
|
||||
const addPatternStart = new Set(['[', '.']);
|
||||
// cases where traversal is A-OK, no dot prevention needed
|
||||
const justDots = new Set(['..', '.']);
|
||||
const reSpecials = new Set('().*{}+?[]^$\\!');
|
||||
const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
// any single thing other than /
|
||||
const qmark = '[^/]';
|
||||
// * => any number of characters
|
||||
const star = qmark + '*?';
|
||||
// use + when we need to ensure that *something* matches, because the * is
|
||||
// the only thing in the path portion.
|
||||
const starNoEmpty = qmark + '+?';
|
||||
// remove the \ chars that we added if we end up doing a nonmagic compare
|
||||
// const deslash = (s: string) => s.replace(/\\(.)/g, '$1')
|
||||
class AST {
|
||||
type;
|
||||
#root;
|
||||
#hasMagic;
|
||||
#uflag = false;
|
||||
#parts = [];
|
||||
#parent;
|
||||
#parentIndex;
|
||||
#negs;
|
||||
#filledNegs = false;
|
||||
#options;
|
||||
#toString;
|
||||
// set to true if it's an extglob with no children
|
||||
// (which really means one child of '')
|
||||
#emptyExt = false;
|
||||
constructor(type, parent, options = {}) {
|
||||
this.type = type;
|
||||
// extglobs are inherently magical
|
||||
if (type)
|
||||
this.#hasMagic = true;
|
||||
this.#parent = parent;
|
||||
this.#root = this.#parent ? this.#parent.#root : this;
|
||||
this.#options = this.#root === this ? options : this.#root.#options;
|
||||
this.#negs = this.#root === this ? [] : this.#root.#negs;
|
||||
if (type === '!' && !this.#root.#filledNegs)
|
||||
this.#negs.push(this);
|
||||
this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
|
||||
}
|
||||
get hasMagic() {
|
||||
/* c8 ignore start */
|
||||
if (this.#hasMagic !== undefined)
|
||||
return this.#hasMagic;
|
||||
/* c8 ignore stop */
|
||||
for (const p of this.#parts) {
|
||||
if (typeof p === 'string')
|
||||
continue;
|
||||
if (p.type || p.hasMagic)
|
||||
return (this.#hasMagic = true);
|
||||
}
|
||||
// note: will be undefined until we generate the regexp src and find out
|
||||
return this.#hasMagic;
|
||||
}
|
||||
// reconstructs the pattern
|
||||
toString() {
|
||||
if (this.#toString !== undefined)
|
||||
return this.#toString;
|
||||
if (!this.type) {
|
||||
return (this.#toString = this.#parts.map(p => String(p)).join(''));
|
||||
}
|
||||
else {
|
||||
return (this.#toString =
|
||||
this.type + '(' + this.#parts.map(p => String(p)).join('|') + ')');
|
||||
}
|
||||
}
|
||||
#fillNegs() {
|
||||
/* c8 ignore start */
|
||||
if (this !== this.#root)
|
||||
throw new Error('should only call on root');
|
||||
if (this.#filledNegs)
|
||||
return this;
|
||||
/* c8 ignore stop */
|
||||
// call toString() once to fill this out
|
||||
this.toString();
|
||||
this.#filledNegs = true;
|
||||
let n;
|
||||
while ((n = this.#negs.pop())) {
|
||||
if (n.type !== '!')
|
||||
continue;
|
||||
// walk up the tree, appending everthing that comes AFTER parentIndex
|
||||
let p = n;
|
||||
let pp = p.#parent;
|
||||
while (pp) {
|
||||
for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) {
|
||||
for (const part of n.#parts) {
|
||||
/* c8 ignore start */
|
||||
if (typeof part === 'string') {
|
||||
throw new Error('string part in extglob AST??');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
part.copyIn(pp.#parts[i]);
|
||||
}
|
||||
}
|
||||
p = pp;
|
||||
pp = p.#parent;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
push(...parts) {
|
||||
for (const p of parts) {
|
||||
if (p === '')
|
||||
continue;
|
||||
/* c8 ignore start */
|
||||
if (typeof p !== 'string' && !(p instanceof AST && p.#parent === this)) {
|
||||
throw new Error('invalid part: ' + p);
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
this.#parts.push(p);
|
||||
}
|
||||
}
|
||||
toJSON() {
|
||||
const ret = this.type === null
|
||||
? this.#parts.slice().map(p => (typeof p === 'string' ? p : p.toJSON()))
|
||||
: [this.type, ...this.#parts.map(p => p.toJSON())];
|
||||
if (this.isStart() && !this.type)
|
||||
ret.unshift([]);
|
||||
if (this.isEnd() &&
|
||||
(this === this.#root ||
|
||||
(this.#root.#filledNegs && this.#parent?.type === '!'))) {
|
||||
ret.push({});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
isStart() {
|
||||
if (this.#root === this)
|
||||
return true;
|
||||
// if (this.type) return !!this.#parent?.isStart()
|
||||
if (!this.#parent?.isStart())
|
||||
return false;
|
||||
if (this.#parentIndex === 0)
|
||||
return true;
|
||||
// if everything AHEAD of this is a negation, then it's still the "start"
|
||||
const p = this.#parent;
|
||||
for (let i = 0; i < this.#parentIndex; i++) {
|
||||
const pp = p.#parts[i];
|
||||
if (!(pp instanceof AST && pp.type === '!')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
isEnd() {
|
||||
if (this.#root === this)
|
||||
return true;
|
||||
if (this.#parent?.type === '!')
|
||||
return true;
|
||||
if (!this.#parent?.isEnd())
|
||||
return false;
|
||||
if (!this.type)
|
||||
return this.#parent?.isEnd();
|
||||
// if not root, it'll always have a parent
|
||||
/* c8 ignore start */
|
||||
const pl = this.#parent ? this.#parent.#parts.length : 0;
|
||||
/* c8 ignore stop */
|
||||
return this.#parentIndex === pl - 1;
|
||||
}
|
||||
copyIn(part) {
|
||||
if (typeof part === 'string')
|
||||
this.push(part);
|
||||
else
|
||||
this.push(part.clone(this));
|
||||
}
|
||||
clone(parent) {
|
||||
const c = new AST(this.type, parent);
|
||||
for (const p of this.#parts) {
|
||||
c.copyIn(p);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
static #parseAST(str, ast, pos, opt) {
|
||||
let escaping = false;
|
||||
let inBrace = false;
|
||||
let braceStart = -1;
|
||||
let braceNeg = false;
|
||||
if (ast.type === null) {
|
||||
// outside of a extglob, append until we find a start
|
||||
let i = pos;
|
||||
let acc = '';
|
||||
while (i < str.length) {
|
||||
const c = str.charAt(i++);
|
||||
// still accumulate escapes at this point, but we do ignore
|
||||
// starts that are escaped
|
||||
if (escaping || c === '\\') {
|
||||
escaping = !escaping;
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
if (inBrace) {
|
||||
if (i === braceStart + 1) {
|
||||
if (c === '^' || c === '!') {
|
||||
braceNeg = true;
|
||||
}
|
||||
}
|
||||
else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
|
||||
inBrace = false;
|
||||
}
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
else if (c === '[') {
|
||||
inBrace = true;
|
||||
braceStart = i;
|
||||
braceNeg = false;
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
if (!opt.noext && isExtglobType(c) && str.charAt(i) === '(') {
|
||||
ast.push(acc);
|
||||
acc = '';
|
||||
const ext = new AST(c, ast);
|
||||
i = AST.#parseAST(str, ext, i, opt);
|
||||
ast.push(ext);
|
||||
continue;
|
||||
}
|
||||
acc += c;
|
||||
}
|
||||
ast.push(acc);
|
||||
return i;
|
||||
}
|
||||
// some kind of extglob, pos is at the (
|
||||
// find the next | or )
|
||||
let i = pos + 1;
|
||||
let part = new AST(null, ast);
|
||||
const parts = [];
|
||||
let acc = '';
|
||||
while (i < str.length) {
|
||||
const c = str.charAt(i++);
|
||||
// still accumulate escapes at this point, but we do ignore
|
||||
// starts that are escaped
|
||||
if (escaping || c === '\\') {
|
||||
escaping = !escaping;
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
if (inBrace) {
|
||||
if (i === braceStart + 1) {
|
||||
if (c === '^' || c === '!') {
|
||||
braceNeg = true;
|
||||
}
|
||||
}
|
||||
else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
|
||||
inBrace = false;
|
||||
}
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
else if (c === '[') {
|
||||
inBrace = true;
|
||||
braceStart = i;
|
||||
braceNeg = false;
|
||||
acc += c;
|
||||
continue;
|
||||
}
|
||||
if (isExtglobType(c) && str.charAt(i) === '(') {
|
||||
part.push(acc);
|
||||
acc = '';
|
||||
const ext = new AST(c, part);
|
||||
part.push(ext);
|
||||
i = AST.#parseAST(str, ext, i, opt);
|
||||
continue;
|
||||
}
|
||||
if (c === '|') {
|
||||
part.push(acc);
|
||||
acc = '';
|
||||
parts.push(part);
|
||||
part = new AST(null, ast);
|
||||
continue;
|
||||
}
|
||||
if (c === ')') {
|
||||
if (acc === '' && ast.#parts.length === 0) {
|
||||
ast.#emptyExt = true;
|
||||
}
|
||||
part.push(acc);
|
||||
acc = '';
|
||||
ast.push(...parts, part);
|
||||
return i;
|
||||
}
|
||||
acc += c;
|
||||
}
|
||||
// unfinished extglob
|
||||
// if we got here, it was a malformed extglob! not an extglob, but
|
||||
// maybe something else in there.
|
||||
ast.type = null;
|
||||
ast.#hasMagic = undefined;
|
||||
ast.#parts = [str.substring(pos - 1)];
|
||||
return i;
|
||||
}
|
||||
static fromGlob(pattern, options = {}) {
|
||||
const ast = new AST(null, undefined, options);
|
||||
AST.#parseAST(pattern, ast, 0, options);
|
||||
return ast;
|
||||
}
|
||||
// returns the regular expression if there's magic, or the unescaped
|
||||
// string if not.
|
||||
toMMPattern() {
|
||||
// should only be called on root
|
||||
/* c8 ignore start */
|
||||
if (this !== this.#root)
|
||||
return this.#root.toMMPattern();
|
||||
/* c8 ignore stop */
|
||||
const glob = this.toString();
|
||||
const [re, body, hasMagic, uflag] = this.toRegExpSource();
|
||||
// if we're in nocase mode, and not nocaseMagicOnly, then we do
|
||||
// still need a regular expression if we have to case-insensitively
|
||||
// match capital/lowercase characters.
|
||||
const anyMagic = hasMagic ||
|
||||
this.#hasMagic ||
|
||||
(this.#options.nocase &&
|
||||
!this.#options.nocaseMagicOnly &&
|
||||
glob.toUpperCase() !== glob.toLowerCase());
|
||||
if (!anyMagic) {
|
||||
return body;
|
||||
}
|
||||
const flags = (this.#options.nocase ? 'i' : '') + (uflag ? 'u' : '');
|
||||
return Object.assign(new RegExp(`^${re}$`, flags), {
|
||||
_src: re,
|
||||
_glob: glob,
|
||||
});
|
||||
}
|
||||
// returns the string match, the regexp source, whether there's magic
|
||||
// in the regexp (so a regular expression is required) and whether or
|
||||
// not the uflag is needed for the regular expression (for posix classes)
|
||||
// TODO: instead of injecting the start/end at this point, just return
|
||||
// the BODY of the regexp, along with the start/end portions suitable
|
||||
// for binding the start/end in either a joined full-path makeRe context
|
||||
// (where we bind to (^|/), or a standalone matchPart context (where
|
||||
// we bind to ^, and not /). Otherwise slashes get duped!
|
||||
//
|
||||
// In part-matching mode, the start is:
|
||||
// - if not isStart: nothing
|
||||
// - if traversal possible, but not allowed: ^(?!\.\.?$)
|
||||
// - if dots allowed or not possible: ^
|
||||
// - if dots possible and not allowed: ^(?!\.)
|
||||
// end is:
|
||||
// - if not isEnd(): nothing
|
||||
// - else: $
|
||||
//
|
||||
// In full-path matching mode, we put the slash at the START of the
|
||||
// pattern, so start is:
|
||||
// - if first pattern: same as part-matching mode
|
||||
// - if not isStart(): nothing
|
||||
// - if traversal possible, but not allowed: /(?!\.\.?(?:$|/))
|
||||
// - if dots allowed or not possible: /
|
||||
// - if dots possible and not allowed: /(?!\.)
|
||||
// end is:
|
||||
// - if last pattern, same as part-matching mode
|
||||
// - else nothing
|
||||
//
|
||||
// Always put the (?:$|/) on negated tails, though, because that has to be
|
||||
// there to bind the end of the negated pattern portion, and it's easier to
|
||||
// just stick it in now rather than try to inject it later in the middle of
|
||||
// the pattern.
|
||||
//
|
||||
// We can just always return the same end, and leave it up to the caller
|
||||
// to know whether it's going to be used joined or in parts.
|
||||
// And, if the start is adjusted slightly, can do the same there:
|
||||
// - if not isStart: nothing
|
||||
// - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$)
|
||||
// - if dots allowed or not possible: (?:/|^)
|
||||
// - if dots possible and not allowed: (?:/|^)(?!\.)
|
||||
//
|
||||
// But it's better to have a simpler binding without a conditional, for
|
||||
// performance, so probably better to return both start options.
|
||||
//
|
||||
// Then the caller just ignores the end if it's not the first pattern,
|
||||
// and the start always gets applied.
|
||||
//
|
||||
// But that's always going to be $ if it's the ending pattern, or nothing,
|
||||
// so the caller can just attach $ at the end of the pattern when building.
|
||||
//
|
||||
// So the todo is:
|
||||
// - better detect what kind of start is needed
|
||||
// - return both flavors of starting pattern
|
||||
// - attach $ at the end of the pattern when creating the actual RegExp
|
||||
//
|
||||
// Ah, but wait, no, that all only applies to the root when the first pattern
|
||||
// is not an extglob. If the first pattern IS an extglob, then we need all
|
||||
// that dot prevention biz to live in the extglob portions, because eg
|
||||
// +(*|.x*) can match .xy but not .yx.
|
||||
//
|
||||
// So, return the two flavors if it's #root and the first child is not an
|
||||
// AST, otherwise leave it to the child AST to handle it, and there,
|
||||
// use the (?:^|/) style of start binding.
|
||||
//
|
||||
// Even simplified further:
|
||||
// - Since the start for a join is eg /(?!\.) and the start for a part
|
||||
// is ^(?!\.), we can just prepend (?!\.) to the pattern (either root
|
||||
// or start or whatever) and prepend ^ or / at the Regexp construction.
|
||||
toRegExpSource(allowDot) {
|
||||
const dot = allowDot ?? !!this.#options.dot;
|
||||
if (this.#root === this)
|
||||
this.#fillNegs();
|
||||
if (!this.type) {
|
||||
const noEmpty = this.isStart() && this.isEnd();
|
||||
const src = this.#parts
|
||||
.map(p => {
|
||||
const [re, _, hasMagic, uflag] = typeof p === 'string'
|
||||
? AST.#parseGlob(p, this.#hasMagic, noEmpty)
|
||||
: p.toRegExpSource(allowDot);
|
||||
this.#hasMagic = this.#hasMagic || hasMagic;
|
||||
this.#uflag = this.#uflag || uflag;
|
||||
return re;
|
||||
})
|
||||
.join('');
|
||||
let start = '';
|
||||
if (this.isStart()) {
|
||||
if (typeof this.#parts[0] === 'string') {
|
||||
// this is the string that will match the start of the pattern,
|
||||
// so we need to protect against dots and such.
|
||||
// '.' and '..' cannot match unless the pattern is that exactly,
|
||||
// even if it starts with . or dot:true is set.
|
||||
const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);
|
||||
if (!dotTravAllowed) {
|
||||
const aps = addPatternStart;
|
||||
// check if we have a possibility of matching . or ..,
|
||||
// and prevent that.
|
||||
const needNoTrav =
|
||||
// dots are allowed, and the pattern starts with [ or .
|
||||
(dot && aps.has(src.charAt(0))) ||
|
||||
// the pattern starts with \., and then [ or .
|
||||
(src.startsWith('\\.') && aps.has(src.charAt(2))) ||
|
||||
// the pattern starts with \.\., and then [ or .
|
||||
(src.startsWith('\\.\\.') && aps.has(src.charAt(4)));
|
||||
// no need to prevent dots if it can't match a dot, or if a
|
||||
// sub-pattern will be preventing it anyway.
|
||||
const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
|
||||
start = needNoTrav ? startNoTraversal : needNoDot ? startNoDot : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
// append the "end of path portion" pattern to negation tails
|
||||
let end = '';
|
||||
if (this.isEnd() &&
|
||||
this.#root.#filledNegs &&
|
||||
this.#parent?.type === '!') {
|
||||
end = '(?:$|\\/)';
|
||||
}
|
||||
const final = start + src + end;
|
||||
return [
|
||||
final,
|
||||
unescape_unescape(src),
|
||||
(this.#hasMagic = !!this.#hasMagic),
|
||||
this.#uflag,
|
||||
];
|
||||
}
|
||||
// We need to calculate the body *twice* if it's a repeat pattern
|
||||
// at the start, once in nodot mode, then again in dot mode, so a
|
||||
// pattern like *(?) can match 'x.y'
|
||||
const repeated = this.type === '*' || this.type === '+';
|
||||
// some kind of extglob
|
||||
const start = this.type === '!' ? '(?:(?!(?:' : '(?:';
|
||||
let body = this.#partsToRegExp(dot);
|
||||
if (this.isStart() && this.isEnd() && !body && this.type !== '!') {
|
||||
// invalid extglob, has to at least be *something* present, if it's
|
||||
// the entire path portion.
|
||||
const s = this.toString();
|
||||
this.#parts = [s];
|
||||
this.type = null;
|
||||
this.#hasMagic = undefined;
|
||||
return [s, unescape_unescape(this.toString()), false, false];
|
||||
}
|
||||
// XXX abstract out this map method
|
||||
let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot
|
||||
? ''
|
||||
: this.#partsToRegExp(true);
|
||||
if (bodyDotAllowed === body) {
|
||||
bodyDotAllowed = '';
|
||||
}
|
||||
if (bodyDotAllowed) {
|
||||
body = `(?:${body})(?:${bodyDotAllowed})*?`;
|
||||
}
|
||||
// an empty !() is exactly equivalent to a starNoEmpty
|
||||
let final = '';
|
||||
if (this.type === '!' && this.#emptyExt) {
|
||||
final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty;
|
||||
}
|
||||
else {
|
||||
const close = this.type === '!'
|
||||
? // !() must match something,but !(x) can match ''
|
||||
'))' +
|
||||
(this.isStart() && !dot && !allowDot ? startNoDot : '') +
|
||||
star +
|
||||
')'
|
||||
: this.type === '@'
|
||||
? ')'
|
||||
: this.type === '?'
|
||||
? ')?'
|
||||
: this.type === '+' && bodyDotAllowed
|
||||
? ')'
|
||||
: this.type === '*' && bodyDotAllowed
|
||||
? `)?`
|
||||
: `)${this.type}`;
|
||||
final = start + body + close;
|
||||
}
|
||||
return [
|
||||
final,
|
||||
unescape_unescape(body),
|
||||
(this.#hasMagic = !!this.#hasMagic),
|
||||
this.#uflag,
|
||||
];
|
||||
}
|
||||
#partsToRegExp(dot) {
|
||||
return this.#parts
|
||||
.map(p => {
|
||||
// extglob ASTs should only contain parent ASTs
|
||||
/* c8 ignore start */
|
||||
if (typeof p === 'string') {
|
||||
throw new Error('string type in extglob ast??');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
// can ignore hasMagic, because extglobs are already always magic
|
||||
const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot);
|
||||
this.#uflag = this.#uflag || uflag;
|
||||
return re;
|
||||
})
|
||||
.filter(p => !(this.isStart() && this.isEnd()) || !!p)
|
||||
.join('|');
|
||||
}
|
||||
static #parseGlob(glob, hasMagic, noEmpty = false) {
|
||||
let escaping = false;
|
||||
let re = '';
|
||||
let uflag = false;
|
||||
for (let i = 0; i < glob.length; i++) {
|
||||
const c = glob.charAt(i);
|
||||
if (escaping) {
|
||||
escaping = false;
|
||||
re += (reSpecials.has(c) ? '\\' : '') + c;
|
||||
continue;
|
||||
}
|
||||
if (c === '\\') {
|
||||
if (i === glob.length - 1) {
|
||||
re += '\\\\';
|
||||
}
|
||||
else {
|
||||
escaping = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c === '[') {
|
||||
const [src, needUflag, consumed, magic] = parseClass(glob, i);
|
||||
if (consumed) {
|
||||
re += src;
|
||||
uflag = uflag || needUflag;
|
||||
i += consumed - 1;
|
||||
hasMagic = hasMagic || magic;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (c === '*') {
|
||||
if (noEmpty && glob === '*')
|
||||
re += starNoEmpty;
|
||||
else
|
||||
re += star;
|
||||
hasMagic = true;
|
||||
continue;
|
||||
}
|
||||
if (c === '?') {
|
||||
re += qmark;
|
||||
hasMagic = true;
|
||||
continue;
|
||||
}
|
||||
re += regExpEscape(c);
|
||||
}
|
||||
return [re, unescape_unescape(glob), !!hasMagic, uflag];
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ast.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/minimatch/dist/mjs/escape.js
|
||||
/**
|
||||
* Escape all magic characters in a glob pattern.
|
||||
*
|
||||
* If the {@link windowsPathsNoEscape | GlobOptions.windowsPathsNoEscape}
|
||||
* option is used, then characters are escaped by wrapping in `[]`, because
|
||||
* a magic character wrapped in a character class can only be satisfied by
|
||||
* that exact character. In this mode, `\` is _not_ escaped, because it is
|
||||
* not interpreted as a magic character, but instead as a path separator.
|
||||
*/
|
||||
const escape_escape = (s, { windowsPathsNoEscape = false, } = {}) => {
|
||||
// don't need to escape +@! because we escape the parens
|
||||
// that make those magic, and escaping ! as [!] isn't valid,
|
||||
// because [!]] is a valid glob class meaning not ']'.
|
||||
return windowsPathsNoEscape
|
||||
? s.replace(/[?*()[\]]/g, '[$&]')
|
||||
: s.replace(/[?*()[\]\\]/g, '\\$&');
|
||||
};
|
||||
//# sourceMappingURL=escape.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/minimatch/dist/mjs/index.js
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const minimatch = (p, pattern, options = {}) => {
|
||||
assertValidPattern(pattern);
|
||||
// shortcut: comments match nothing.
|
||||
if (!options.nocomment && pattern.charAt(0) === '#') {
|
||||
return false;
|
||||
}
|
||||
return new Minimatch(pattern, options).match(p);
|
||||
};
|
||||
// Optimized checking for the most common glob patterns.
|
||||
const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/;
|
||||
const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext);
|
||||
const starDotExtTestDot = (ext) => (f) => f.endsWith(ext);
|
||||
const starDotExtTestNocase = (ext) => {
|
||||
ext = ext.toLowerCase();
|
||||
return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext);
|
||||
};
|
||||
const starDotExtTestNocaseDot = (ext) => {
|
||||
ext = ext.toLowerCase();
|
||||
return (f) => f.toLowerCase().endsWith(ext);
|
||||
};
|
||||
const starDotStarRE = /^\*+\.\*+$/;
|
||||
const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.');
|
||||
const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.');
|
||||
const dotStarRE = /^\.\*+$/;
|
||||
const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.');
|
||||
const starRE = /^\*+$/;
|
||||
const starTest = (f) => f.length !== 0 && !f.startsWith('.');
|
||||
const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..';
|
||||
const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/;
|
||||
const qmarksTestNocase = ([$0, ext = '']) => {
|
||||
const noext = qmarksTestNoExt([$0]);
|
||||
if (!ext)
|
||||
return noext;
|
||||
ext = ext.toLowerCase();
|
||||
return (f) => noext(f) && f.toLowerCase().endsWith(ext);
|
||||
};
|
||||
const qmarksTestNocaseDot = ([$0, ext = '']) => {
|
||||
const noext = qmarksTestNoExtDot([$0]);
|
||||
if (!ext)
|
||||
return noext;
|
||||
ext = ext.toLowerCase();
|
||||
return (f) => noext(f) && f.toLowerCase().endsWith(ext);
|
||||
};
|
||||
const qmarksTestDot = ([$0, ext = '']) => {
|
||||
const noext = qmarksTestNoExtDot([$0]);
|
||||
return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
|
||||
};
|
||||
const qmarksTest = ([$0, ext = '']) => {
|
||||
const noext = qmarksTestNoExt([$0]);
|
||||
return !ext ? noext : (f) => noext(f) && f.endsWith(ext);
|
||||
};
|
||||
const qmarksTestNoExt = ([$0]) => {
|
||||
const len = $0.length;
|
||||
return (f) => f.length === len && !f.startsWith('.');
|
||||
};
|
||||
const qmarksTestNoExtDot = ([$0]) => {
|
||||
const len = $0.length;
|
||||
return (f) => f.length === len && f !== '.' && f !== '..';
|
||||
};
|
||||
/* c8 ignore start */
|
||||
const defaultPlatform = (typeof process === 'object' && process
|
||||
? (typeof process.env === 'object' &&
|
||||
process.env &&
|
||||
process.env.__MINIMATCH_TESTING_PLATFORM__) ||
|
||||
process.platform
|
||||
: 'posix');
|
||||
const path = {
|
||||
win32: { sep: '\\' },
|
||||
posix: { sep: '/' },
|
||||
};
|
||||
/* c8 ignore stop */
|
||||
const sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep;
|
||||
minimatch.sep = sep;
|
||||
const GLOBSTAR = Symbol('globstar **');
|
||||
minimatch.GLOBSTAR = GLOBSTAR;
|
||||
// any single thing other than /
|
||||
// don't need to escape / when using new RegExp()
|
||||
const mjs_qmark = '[^/]';
|
||||
// * => any number of characters
|
||||
const mjs_star = mjs_qmark + '*?';
|
||||
// ** when dots are allowed. Anything goes, except .. and .
|
||||
// not (^ or / followed by one or two dots followed by $ or /),
|
||||
// followed by anything, any number of times.
|
||||
const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';
|
||||
// not a ^ or / followed by a dot,
|
||||
// followed by anything, any number of times.
|
||||
const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?';
|
||||
const filter = (pattern, options = {}) => (p) => minimatch(p, pattern, options);
|
||||
minimatch.filter = filter;
|
||||
const ext = (a, b = {}) => Object.assign({}, a, b);
|
||||
const defaults = (def) => {
|
||||
if (!def || typeof def !== 'object' || !Object.keys(def).length) {
|
||||
return minimatch;
|
||||
}
|
||||
const orig = minimatch;
|
||||
const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options));
|
||||
return Object.assign(m, {
|
||||
Minimatch: class Minimatch extends orig.Minimatch {
|
||||
constructor(pattern, options = {}) {
|
||||
super(pattern, ext(def, options));
|
||||
}
|
||||
static defaults(options) {
|
||||
return orig.defaults(ext(def, options)).Minimatch;
|
||||
}
|
||||
},
|
||||
AST: class AST extends orig.AST {
|
||||
/* c8 ignore start */
|
||||
constructor(type, parent, options = {}) {
|
||||
super(type, parent, ext(def, options));
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
static fromGlob(pattern, options = {}) {
|
||||
return orig.AST.fromGlob(pattern, ext(def, options));
|
||||
}
|
||||
},
|
||||
unescape: (s, options = {}) => orig.unescape(s, ext(def, options)),
|
||||
escape: (s, options = {}) => orig.escape(s, ext(def, options)),
|
||||
filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)),
|
||||
defaults: (options) => orig.defaults(ext(def, options)),
|
||||
makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)),
|
||||
braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)),
|
||||
match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)),
|
||||
sep: orig.sep,
|
||||
GLOBSTAR: GLOBSTAR,
|
||||
});
|
||||
};
|
||||
minimatch.defaults = defaults;
|
||||
// Brace expansion:
|
||||
// a{b,c}d -> abd acd
|
||||
// a{b,}c -> abc ac
|
||||
// a{0..3}d -> a0d a1d a2d a3d
|
||||
// a{b,c{d,e}f}g -> abg acdfg acefg
|
||||
// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
|
||||
//
|
||||
// Invalid sets are not expanded.
|
||||
// a{2..}b -> a{2..}b
|
||||
// a{b}c -> a{b}c
|
||||
const braceExpand = (pattern, options = {}) => {
|
||||
assertValidPattern(pattern);
|
||||
// Thanks to Yeting Li <https://github.com/yetingli> for
|
||||
// improving this regexp to avoid a ReDOS vulnerability.
|
||||
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
|
||||
// shortcut. no need to expand.
|
||||
return [pattern];
|
||||
}
|
||||
return brace_expansion(pattern);
|
||||
};
|
||||
minimatch.braceExpand = braceExpand;
|
||||
// parse a component of the expanded set.
|
||||
// At this point, no pattern may contain "/" in it
|
||||
// so we're going to return a 2d array, where each entry is the full
|
||||
// pattern, split on '/', and then turned into a regular expression.
|
||||
// A regexp is made at the end which joins each array with an
|
||||
// escaped /, and another full one which joins each regexp with |.
|
||||
//
|
||||
// Following the lead of Bash 4.1, note that "**" only has special meaning
|
||||
// when it is the *only* thing in a path portion. Otherwise, any series
|
||||
// of * is equivalent to a single *. Globstar behavior is enabled by
|
||||
// default, and can be disabled by setting options.noglobstar.
|
||||
const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe();
|
||||
minimatch.makeRe = makeRe;
|
||||
const match = (list, pattern, options = {}) => {
|
||||
const mm = new Minimatch(pattern, options);
|
||||
list = list.filter(f => mm.match(f));
|
||||
if (mm.options.nonull && !list.length) {
|
||||
list.push(pattern);
|
||||
}
|
||||
return list;
|
||||
};
|
||||
minimatch.match = match;
|
||||
// replace stuff like \* with *
|
||||
const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/;
|
||||
const mjs_regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
class Minimatch {
|
||||
options;
|
||||
set;
|
||||
pattern;
|
||||
windowsPathsNoEscape;
|
||||
nonegate;
|
||||
negate;
|
||||
comment;
|
||||
empty;
|
||||
preserveMultipleSlashes;
|
||||
partial;
|
||||
globSet;
|
||||
globParts;
|
||||
nocase;
|
||||
isWindows;
|
||||
platform;
|
||||
windowsNoMagicRoot;
|
||||
regexp;
|
||||
constructor(pattern, options = {}) {
|
||||
assertValidPattern(pattern);
|
||||
options = options || {};
|
||||
this.options = options;
|
||||
this.pattern = pattern;
|
||||
this.platform = options.platform || defaultPlatform;
|
||||
this.isWindows = this.platform === 'win32';
|
||||
this.windowsPathsNoEscape =
|
||||
!!options.windowsPathsNoEscape || options.allowWindowsEscape === false;
|
||||
if (this.windowsPathsNoEscape) {
|
||||
this.pattern = this.pattern.replace(/\\/g, '/');
|
||||
}
|
||||
this.preserveMultipleSlashes = !!options.preserveMultipleSlashes;
|
||||
this.regexp = null;
|
||||
this.negate = false;
|
||||
this.nonegate = !!options.nonegate;
|
||||
this.comment = false;
|
||||
this.empty = false;
|
||||
this.partial = !!options.partial;
|
||||
this.nocase = !!this.options.nocase;
|
||||
this.windowsNoMagicRoot =
|
||||
options.windowsNoMagicRoot !== undefined
|
||||
? options.windowsNoMagicRoot
|
||||
: !!(this.isWindows && this.nocase);
|
||||
this.globSet = [];
|
||||
this.globParts = [];
|
||||
this.set = [];
|
||||
// make the set of regexps etc.
|
||||
this.make();
|
||||
}
|
||||
hasMagic() {
|
||||
if (this.options.magicalBraces && this.set.length > 1) {
|
||||
return true;
|
||||
}
|
||||
for (const pattern of this.set) {
|
||||
for (const part of pattern) {
|
||||
if (typeof part !== 'string')
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
debug(..._) { }
|
||||
make() {
|
||||
const pattern = this.pattern;
|
||||
const options = this.options;
|
||||
// empty patterns and comments match nothing.
|
||||
if (!options.nocomment && pattern.charAt(0) === '#') {
|
||||
this.comment = true;
|
||||
return;
|
||||
}
|
||||
if (!pattern) {
|
||||
this.empty = true;
|
||||
return;
|
||||
}
|
||||
// step 1: figure out negation, etc.
|
||||
this.parseNegate();
|
||||
// step 2: expand braces
|
||||
this.globSet = [...new Set(this.braceExpand())];
|
||||
if (options.debug) {
|
||||
this.debug = (...args) => console.error(...args);
|
||||
}
|
||||
this.debug(this.pattern, this.globSet);
|
||||
// step 3: now we have a set, so turn each one into a series of
|
||||
// path-portion matching patterns.
|
||||
// These will be regexps, except in the case of "**", which is
|
||||
// set to the GLOBSTAR object for globstar behavior,
|
||||
// and will not contain any / characters
|
||||
//
|
||||
// First, we preprocess to make the glob pattern sets a bit simpler
|
||||
// and deduped. There are some perf-killing patterns that can cause
|
||||
// problems with a glob walk, but we can simplify them down a bit.
|
||||
const rawGlobParts = this.globSet.map(s => this.slashSplit(s));
|
||||
this.globParts = this.preprocess(rawGlobParts);
|
||||
this.debug(this.pattern, this.globParts);
|
||||
// glob --> regexps
|
||||
let set = this.globParts.map((s, _, __) => {
|
||||
if (this.isWindows && this.windowsNoMagicRoot) {
|
||||
// check if it's a drive or unc path.
|
||||
const isUNC = s[0] === '' &&
|
||||
s[1] === '' &&
|
||||
(s[2] === '?' || !globMagic.test(s[2])) &&
|
||||
!globMagic.test(s[3]);
|
||||
const isDrive = /^[a-z]:/i.test(s[0]);
|
||||
if (isUNC) {
|
||||
return [...s.slice(0, 4), ...s.slice(4).map(ss => this.parse(ss))];
|
||||
}
|
||||
else if (isDrive) {
|
||||
return [s[0], ...s.slice(1).map(ss => this.parse(ss))];
|
||||
}
|
||||
}
|
||||
return s.map(ss => this.parse(ss));
|
||||
});
|
||||
this.debug(this.pattern, set);
|
||||
// filter out everything that didn't compile properly.
|
||||
this.set = set.filter(s => s.indexOf(false) === -1);
|
||||
// do not treat the ? in UNC paths as magic
|
||||
if (this.isWindows) {
|
||||
for (let i = 0; i < this.set.length; i++) {
|
||||
const p = this.set[i];
|
||||
if (p[0] === '' &&
|
||||
p[1] === '' &&
|
||||
this.globParts[i][2] === '?' &&
|
||||
typeof p[3] === 'string' &&
|
||||
/^[a-z]:$/i.test(p[3])) {
|
||||
p[2] = '?';
|
||||
}
|
||||
}
|
||||
}
|
||||
this.debug(this.pattern, this.set);
|
||||
}
|
||||
// various transforms to equivalent pattern sets that are
|
||||
// faster to process in a filesystem walk. The goal is to
|
||||
// eliminate what we can, and push all ** patterns as far
|
||||
// to the right as possible, even if it increases the number
|
||||
// of patterns that we have to process.
|
||||
preprocess(globParts) {
|
||||
// if we're not in globstar mode, then turn all ** into *
|
||||
if (this.options.noglobstar) {
|
||||
for (let i = 0; i < globParts.length; i++) {
|
||||
for (let j = 0; j < globParts[i].length; j++) {
|
||||
if (globParts[i][j] === '**') {
|
||||
globParts[i][j] = '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const { optimizationLevel = 1 } = this.options;
|
||||
if (optimizationLevel >= 2) {
|
||||
// aggressive optimization for the purpose of fs walking
|
||||
globParts = this.firstPhasePreProcess(globParts);
|
||||
globParts = this.secondPhasePreProcess(globParts);
|
||||
}
|
||||
else if (optimizationLevel >= 1) {
|
||||
// just basic optimizations to remove some .. parts
|
||||
globParts = this.levelOneOptimize(globParts);
|
||||
}
|
||||
else {
|
||||
globParts = this.adjascentGlobstarOptimize(globParts);
|
||||
}
|
||||
return globParts;
|
||||
}
|
||||
// just get rid of adjascent ** portions
|
||||
adjascentGlobstarOptimize(globParts) {
|
||||
return globParts.map(parts => {
|
||||
let gs = -1;
|
||||
while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
|
||||
let i = gs;
|
||||
while (parts[i + 1] === '**') {
|
||||
i++;
|
||||
}
|
||||
if (i !== gs) {
|
||||
parts.splice(gs, i - gs);
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
});
|
||||
}
|
||||
// get rid of adjascent ** and resolve .. portions
|
||||
levelOneOptimize(globParts) {
|
||||
return globParts.map(parts => {
|
||||
parts = parts.reduce((set, part) => {
|
||||
const prev = set[set.length - 1];
|
||||
if (part === '**' && prev === '**') {
|
||||
return set;
|
||||
}
|
||||
if (part === '..') {
|
||||
if (prev && prev !== '..' && prev !== '.' && prev !== '**') {
|
||||
set.pop();
|
||||
return set;
|
||||
}
|
||||
}
|
||||
set.push(part);
|
||||
return set;
|
||||
}, []);
|
||||
return parts.length === 0 ? [''] : parts;
|
||||
});
|
||||
}
|
||||
levelTwoFileOptimize(parts) {
|
||||
if (!Array.isArray(parts)) {
|
||||
parts = this.slashSplit(parts);
|
||||
}
|
||||
let didSomething = false;
|
||||
do {
|
||||
didSomething = false;
|
||||
// <pre>/<e>/<rest> -> <pre>/<rest>
|
||||
if (!this.preserveMultipleSlashes) {
|
||||
for (let i = 1; i < parts.length - 1; i++) {
|
||||
const p = parts[i];
|
||||
// don't squeeze out UNC patterns
|
||||
if (i === 1 && p === '' && parts[0] === '')
|
||||
continue;
|
||||
if (p === '.' || p === '') {
|
||||
didSomething = true;
|
||||
parts.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (parts[0] === '.' &&
|
||||
parts.length === 2 &&
|
||||
(parts[1] === '.' || parts[1] === '')) {
|
||||
didSomething = true;
|
||||
parts.pop();
|
||||
}
|
||||
}
|
||||
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
||||
let dd = 0;
|
||||
while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
|
||||
const p = parts[dd - 1];
|
||||
if (p && p !== '.' && p !== '..' && p !== '**') {
|
||||
didSomething = true;
|
||||
parts.splice(dd - 1, 2);
|
||||
dd -= 2;
|
||||
}
|
||||
}
|
||||
} while (didSomething);
|
||||
return parts.length === 0 ? [''] : parts;
|
||||
}
|
||||
// First phase: single-pattern processing
|
||||
// <pre> is 1 or more portions
|
||||
// <rest> is 1 or more portions
|
||||
// <p> is any portion other than ., .., '', or **
|
||||
// <e> is . or ''
|
||||
//
|
||||
// **/.. is *brutal* for filesystem walking performance, because
|
||||
// it effectively resets the recursive walk each time it occurs,
|
||||
// and ** cannot be reduced out by a .. pattern part like a regexp
|
||||
// or most strings (other than .., ., and '') can be.
|
||||
//
|
||||
// <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
|
||||
// <pre>/<e>/<rest> -> <pre>/<rest>
|
||||
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
||||
// **/**/<rest> -> **/<rest>
|
||||
//
|
||||
// **/*/<rest> -> */**/<rest> <== not valid because ** doesn't follow
|
||||
// this WOULD be allowed if ** did follow symlinks, or * didn't
|
||||
firstPhasePreProcess(globParts) {
|
||||
let didSomething = false;
|
||||
do {
|
||||
didSomething = false;
|
||||
// <pre>/**/../<p>/<p>/<rest> -> {<pre>/../<p>/<p>/<rest>,<pre>/**/<p>/<p>/<rest>}
|
||||
for (let parts of globParts) {
|
||||
let gs = -1;
|
||||
while (-1 !== (gs = parts.indexOf('**', gs + 1))) {
|
||||
let gss = gs;
|
||||
while (parts[gss + 1] === '**') {
|
||||
// <pre>/**/**/<rest> -> <pre>/**/<rest>
|
||||
gss++;
|
||||
}
|
||||
// eg, if gs is 2 and gss is 4, that means we have 3 **
|
||||
// parts, and can remove 2 of them.
|
||||
if (gss > gs) {
|
||||
parts.splice(gs + 1, gss - gs);
|
||||
}
|
||||
let next = parts[gs + 1];
|
||||
const p = parts[gs + 2];
|
||||
const p2 = parts[gs + 3];
|
||||
if (next !== '..')
|
||||
continue;
|
||||
if (!p ||
|
||||
p === '.' ||
|
||||
p === '..' ||
|
||||
!p2 ||
|
||||
p2 === '.' ||
|
||||
p2 === '..') {
|
||||
continue;
|
||||
}
|
||||
didSomething = true;
|
||||
// edit parts in place, and push the new one
|
||||
parts.splice(gs, 1);
|
||||
const other = parts.slice(0);
|
||||
other[gs] = '**';
|
||||
globParts.push(other);
|
||||
gs--;
|
||||
}
|
||||
// <pre>/<e>/<rest> -> <pre>/<rest>
|
||||
if (!this.preserveMultipleSlashes) {
|
||||
for (let i = 1; i < parts.length - 1; i++) {
|
||||
const p = parts[i];
|
||||
// don't squeeze out UNC patterns
|
||||
if (i === 1 && p === '' && parts[0] === '')
|
||||
continue;
|
||||
if (p === '.' || p === '') {
|
||||
didSomething = true;
|
||||
parts.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (parts[0] === '.' &&
|
||||
parts.length === 2 &&
|
||||
(parts[1] === '.' || parts[1] === '')) {
|
||||
didSomething = true;
|
||||
parts.pop();
|
||||
}
|
||||
}
|
||||
// <pre>/<p>/../<rest> -> <pre>/<rest>
|
||||
let dd = 0;
|
||||
while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
|
||||
const p = parts[dd - 1];
|
||||
if (p && p !== '.' && p !== '..' && p !== '**') {
|
||||
didSomething = true;
|
||||
const needDot = dd === 1 && parts[dd + 1] === '**';
|
||||
const splin = needDot ? ['.'] : [];
|
||||
parts.splice(dd - 1, 2, ...splin);
|
||||
if (parts.length === 0)
|
||||
parts.push('');
|
||||
dd -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (didSomething);
|
||||
return globParts;
|
||||
}
|
||||
// second phase: multi-pattern dedupes
|
||||
// {<pre>/*/<rest>,<pre>/<p>/<rest>} -> <pre>/*/<rest>
|
||||
// {<pre>/<rest>,<pre>/<rest>} -> <pre>/<rest>
|
||||
// {<pre>/**/<rest>,<pre>/<rest>} -> <pre>/**/<rest>
|
||||
//
|
||||
// {<pre>/**/<rest>,<pre>/**/<p>/<rest>} -> <pre>/**/<rest>
|
||||
// ^-- not valid because ** doens't follow symlinks
|
||||
secondPhasePreProcess(globParts) {
|
||||
for (let i = 0; i < globParts.length - 1; i++) {
|
||||
for (let j = i + 1; j < globParts.length; j++) {
|
||||
const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
|
||||
if (!matched)
|
||||
continue;
|
||||
globParts[i] = matched;
|
||||
globParts[j] = [];
|
||||
}
|
||||
}
|
||||
return globParts.filter(gs => gs.length);
|
||||
}
|
||||
partsMatch(a, b, emptyGSMatch = false) {
|
||||
let ai = 0;
|
||||
let bi = 0;
|
||||
let result = [];
|
||||
let which = '';
|
||||
while (ai < a.length && bi < b.length) {
|
||||
if (a[ai] === b[bi]) {
|
||||
result.push(which === 'b' ? b[bi] : a[ai]);
|
||||
ai++;
|
||||
bi++;
|
||||
}
|
||||
else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
|
||||
result.push(a[ai]);
|
||||
ai++;
|
||||
}
|
||||
else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
|
||||
result.push(b[bi]);
|
||||
bi++;
|
||||
}
|
||||
else if (a[ai] === '*' &&
|
||||
b[bi] &&
|
||||
(this.options.dot || !b[bi].startsWith('.')) &&
|
||||
b[bi] !== '**') {
|
||||
if (which === 'b')
|
||||
return false;
|
||||
which = 'a';
|
||||
result.push(a[ai]);
|
||||
ai++;
|
||||
bi++;
|
||||
}
|
||||
else if (b[bi] === '*' &&
|
||||
a[ai] &&
|
||||
(this.options.dot || !a[ai].startsWith('.')) &&
|
||||
a[ai] !== '**') {
|
||||
if (which === 'a')
|
||||
return false;
|
||||
which = 'b';
|
||||
result.push(b[bi]);
|
||||
ai++;
|
||||
bi++;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if we fall out of the loop, it means they two are identical
|
||||
// as long as their lengths match
|
||||
return a.length === b.length && result;
|
||||
}
|
||||
parseNegate() {
|
||||
if (this.nonegate)
|
||||
return;
|
||||
const pattern = this.pattern;
|
||||
let negate = false;
|
||||
let negateOffset = 0;
|
||||
for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
|
||||
negate = !negate;
|
||||
negateOffset++;
|
||||
}
|
||||
if (negateOffset)
|
||||
this.pattern = pattern.slice(negateOffset);
|
||||
this.negate = negate;
|
||||
}
|
||||
// set partial to true to test if, for example,
|
||||
// "/a/b" matches the start of "/*/b/*/d"
|
||||
// Partial means, if you run out of file before you run
|
||||
// out of pattern, then that's fine, as long as all
|
||||
// the parts match.
|
||||
matchOne(file, pattern, partial = false) {
|
||||
const options = this.options;
|
||||
// UNC paths like //?/X:/... can match X:/... and vice versa
|
||||
// Drive letters in absolute drive or unc paths are always compared
|
||||
// case-insensitively.
|
||||
if (this.isWindows) {
|
||||
const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]);
|
||||
const fileUNC = !fileDrive &&
|
||||
file[0] === '' &&
|
||||
file[1] === '' &&
|
||||
file[2] === '?' &&
|
||||
/^[a-z]:$/i.test(file[3]);
|
||||
const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]);
|
||||
const patternUNC = !patternDrive &&
|
||||
pattern[0] === '' &&
|
||||
pattern[1] === '' &&
|
||||
pattern[2] === '?' &&
|
||||
typeof pattern[3] === 'string' &&
|
||||
/^[a-z]:$/i.test(pattern[3]);
|
||||
const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined;
|
||||
const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined;
|
||||
if (typeof fdi === 'number' && typeof pdi === 'number') {
|
||||
const [fd, pd] = [file[fdi], pattern[pdi]];
|
||||
if (fd.toLowerCase() === pd.toLowerCase()) {
|
||||
pattern[pdi] = fd;
|
||||
if (pdi > fdi) {
|
||||
pattern = pattern.slice(pdi);
|
||||
}
|
||||
else if (fdi > pdi) {
|
||||
file = file.slice(fdi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// resolve and reduce . and .. portions in the file as well.
|
||||
// dont' need to do the second phase, because it's only one string[]
|
||||
const { optimizationLevel = 1 } = this.options;
|
||||
if (optimizationLevel >= 2) {
|
||||
file = this.levelTwoFileOptimize(file);
|
||||
}
|
||||
this.debug('matchOne', this, { file, pattern });
|
||||
this.debug('matchOne', file.length, pattern.length);
|
||||
for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
|
||||
this.debug('matchOne loop');
|
||||
var p = pattern[pi];
|
||||
var f = file[fi];
|
||||
this.debug(pattern, p, f);
|
||||
// should be impossible.
|
||||
// some invalid regexp stuff in the set.
|
||||
/* c8 ignore start */
|
||||
if (p === false) {
|
||||
return false;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
if (p === GLOBSTAR) {
|
||||
this.debug('GLOBSTAR', [pattern, p, f]);
|
||||
// "**"
|
||||
// a/**/b/**/c would match the following:
|
||||
// a/b/x/y/z/c
|
||||
// a/x/y/z/b/c
|
||||
// a/b/x/b/x/c
|
||||
// a/b/c
|
||||
// To do this, take the rest of the pattern after
|
||||
// the **, and see if it would match the file remainder.
|
||||
// If so, return success.
|
||||
// If not, the ** "swallows" a segment, and try again.
|
||||
// This is recursively awful.
|
||||
//
|
||||
// a/**/b/**/c matching a/b/x/y/z/c
|
||||
// - a matches a
|
||||
// - doublestar
|
||||
// - matchOne(b/x/y/z/c, b/**/c)
|
||||
// - b matches b
|
||||
// - doublestar
|
||||
// - matchOne(x/y/z/c, c) -> no
|
||||
// - matchOne(y/z/c, c) -> no
|
||||
// - matchOne(z/c, c) -> no
|
||||
// - matchOne(c, c) yes, hit
|
||||
var fr = fi;
|
||||
var pr = pi + 1;
|
||||
if (pr === pl) {
|
||||
this.debug('** at the end');
|
||||
// a ** at the end will just swallow the rest.
|
||||
// We have found a match.
|
||||
// however, it will not swallow /.x, unless
|
||||
// options.dot is set.
|
||||
// . and .. are *never* matched by **, for explosively
|
||||
// exponential reasons.
|
||||
for (; fi < fl; fi++) {
|
||||
if (file[fi] === '.' ||
|
||||
file[fi] === '..' ||
|
||||
(!options.dot && file[fi].charAt(0) === '.'))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// ok, let's see if we can swallow whatever we can.
|
||||
while (fr < fl) {
|
||||
var swallowee = file[fr];
|
||||
this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
|
||||
// XXX remove this slice. Just pass the start index.
|
||||
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
|
||||
this.debug('globstar found match!', fr, fl, swallowee);
|
||||
// found a match.
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// can't swallow "." or ".." ever.
|
||||
// can only swallow ".foo" when explicitly asked.
|
||||
if (swallowee === '.' ||
|
||||
swallowee === '..' ||
|
||||
(!options.dot && swallowee.charAt(0) === '.')) {
|
||||
this.debug('dot detected!', file, fr, pattern, pr);
|
||||
break;
|
||||
}
|
||||
// ** swallows a segment, and continue.
|
||||
this.debug('globstar swallow a segment, and continue');
|
||||
fr++;
|
||||
}
|
||||
}
|
||||
// no match was found.
|
||||
// However, in partial mode, we can't say this is necessarily over.
|
||||
/* c8 ignore start */
|
||||
if (partial) {
|
||||
// ran out of file
|
||||
this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
|
||||
if (fr === fl) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return false;
|
||||
}
|
||||
// something other than **
|
||||
// non-magic patterns just have to match exactly
|
||||
// patterns with magic have been turned into regexps.
|
||||
let hit;
|
||||
if (typeof p === 'string') {
|
||||
hit = f === p;
|
||||
this.debug('string match', p, f, hit);
|
||||
}
|
||||
else {
|
||||
hit = p.test(f);
|
||||
this.debug('pattern match', p, f, hit);
|
||||
}
|
||||
if (!hit)
|
||||
return false;
|
||||
}
|
||||
// Note: ending in / means that we'll get a final ""
|
||||
// at the end of the pattern. This can only match a
|
||||
// corresponding "" at the end of the file.
|
||||
// If the file ends in /, then it can only match a
|
||||
// a pattern that ends in /, unless the pattern just
|
||||
// doesn't have any more for it. But, a/b/ should *not*
|
||||
// match "a/b/*", even though "" matches against the
|
||||
// [^/]*? pattern, except in partial mode, where it might
|
||||
// simply not be reached yet.
|
||||
// However, a/b/ should still satisfy a/*
|
||||
// now either we fell off the end of the pattern, or we're done.
|
||||
if (fi === fl && pi === pl) {
|
||||
// ran out of pattern and filename at the same time.
|
||||
// an exact hit!
|
||||
return true;
|
||||
}
|
||||
else if (fi === fl) {
|
||||
// ran out of file, but still had pattern left.
|
||||
// this is ok if we're doing the match as part of
|
||||
// a glob fs traversal.
|
||||
return partial;
|
||||
}
|
||||
else if (pi === pl) {
|
||||
// ran out of pattern, still have file left.
|
||||
// this is only acceptable if we're on the very last
|
||||
// empty segment of a file with a trailing slash.
|
||||
// a/* should match a/b/
|
||||
return fi === fl - 1 && file[fi] === '';
|
||||
/* c8 ignore start */
|
||||
}
|
||||
else {
|
||||
// should be unreachable.
|
||||
throw new Error('wtf?');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
braceExpand() {
|
||||
return braceExpand(this.pattern, this.options);
|
||||
}
|
||||
parse(pattern) {
|
||||
assertValidPattern(pattern);
|
||||
const options = this.options;
|
||||
// shortcuts
|
||||
if (pattern === '**')
|
||||
return GLOBSTAR;
|
||||
if (pattern === '')
|
||||
return '';
|
||||
// far and away, the most common glob pattern parts are
|
||||
// *, *.*, and *.<ext> Add a fast check method for those.
|
||||
let m;
|
||||
let fastTest = null;
|
||||
if ((m = pattern.match(starRE))) {
|
||||
fastTest = options.dot ? starTestDot : starTest;
|
||||
}
|
||||
else if ((m = pattern.match(starDotExtRE))) {
|
||||
fastTest = (options.nocase
|
||||
? options.dot
|
||||
? starDotExtTestNocaseDot
|
||||
: starDotExtTestNocase
|
||||
: options.dot
|
||||
? starDotExtTestDot
|
||||
: starDotExtTest)(m[1]);
|
||||
}
|
||||
else if ((m = pattern.match(qmarksRE))) {
|
||||
fastTest = (options.nocase
|
||||
? options.dot
|
||||
? qmarksTestNocaseDot
|
||||
: qmarksTestNocase
|
||||
: options.dot
|
||||
? qmarksTestDot
|
||||
: qmarksTest)(m);
|
||||
}
|
||||
else if ((m = pattern.match(starDotStarRE))) {
|
||||
fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
|
||||
}
|
||||
else if ((m = pattern.match(dotStarRE))) {
|
||||
fastTest = dotStarTest;
|
||||
}
|
||||
const re = AST.fromGlob(pattern, this.options).toMMPattern();
|
||||
return fastTest ? Object.assign(re, { test: fastTest }) : re;
|
||||
}
|
||||
makeRe() {
|
||||
if (this.regexp || this.regexp === false)
|
||||
return this.regexp;
|
||||
// at this point, this.set is a 2d array of partial
|
||||
// pattern strings, or "**".
|
||||
//
|
||||
// It's better to use .match(). This function shouldn't
|
||||
// be used, really, but it's pretty convenient sometimes,
|
||||
// when you just want to work with a regex.
|
||||
const set = this.set;
|
||||
if (!set.length) {
|
||||
this.regexp = false;
|
||||
return this.regexp;
|
||||
}
|
||||
const options = this.options;
|
||||
const twoStar = options.noglobstar
|
||||
? mjs_star
|
||||
: options.dot
|
||||
? twoStarDot
|
||||
: twoStarNoDot;
|
||||
const flags = new Set(options.nocase ? ['i'] : []);
|
||||
// regexpify non-globstar patterns
|
||||
// if ** is only item, then we just do one twoStar
|
||||
// if ** is first, and there are more, prepend (\/|twoStar\/)? to next
|
||||
// if ** is last, append (\/twoStar|) to previous
|
||||
// if ** is in the middle, append (\/|\/twoStar\/) to previous
|
||||
// then filter out GLOBSTAR symbols
|
||||
let re = set
|
||||
.map(pattern => {
|
||||
const pp = pattern.map(p => {
|
||||
if (p instanceof RegExp) {
|
||||
for (const f of p.flags.split(''))
|
||||
flags.add(f);
|
||||
}
|
||||
return typeof p === 'string'
|
||||
? mjs_regExpEscape(p)
|
||||
: p === GLOBSTAR
|
||||
? GLOBSTAR
|
||||
: p._src;
|
||||
});
|
||||
pp.forEach((p, i) => {
|
||||
const next = pp[i + 1];
|
||||
const prev = pp[i - 1];
|
||||
if (p !== GLOBSTAR || prev === GLOBSTAR) {
|
||||
return;
|
||||
}
|
||||
if (prev === undefined) {
|
||||
if (next !== undefined && next !== GLOBSTAR) {
|
||||
pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
|
||||
}
|
||||
else {
|
||||
pp[i] = twoStar;
|
||||
}
|
||||
}
|
||||
else if (next === undefined) {
|
||||
pp[i - 1] = prev + '(?:\\/|' + twoStar + ')?';
|
||||
}
|
||||
else if (next !== GLOBSTAR) {
|
||||
pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
|
||||
pp[i + 1] = GLOBSTAR;
|
||||
}
|
||||
});
|
||||
return pp.filter(p => p !== GLOBSTAR).join('/');
|
||||
})
|
||||
.join('|');
|
||||
// need to wrap in parens if we had more than one thing with |,
|
||||
// otherwise only the first will be anchored to ^ and the last to $
|
||||
const [open, close] = set.length > 1 ? ['(?:', ')'] : ['', ''];
|
||||
// must match entire pattern
|
||||
// ending in a * or ** will make it less strict.
|
||||
re = '^' + open + re + close + '$';
|
||||
// can match anything, as long as it's not this.
|
||||
if (this.negate)
|
||||
re = '^(?!' + re + ').+$';
|
||||
try {
|
||||
this.regexp = new RegExp(re, [...flags].join(''));
|
||||
/* c8 ignore start */
|
||||
}
|
||||
catch (ex) {
|
||||
// should be impossible
|
||||
this.regexp = false;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return this.regexp;
|
||||
}
|
||||
slashSplit(p) {
|
||||
// if p starts with // on windows, we preserve that
|
||||
// so that UNC paths aren't broken. Otherwise, any number of
|
||||
// / characters are coalesced into one, unless
|
||||
// preserveMultipleSlashes is set to true.
|
||||
if (this.preserveMultipleSlashes) {
|
||||
return p.split('/');
|
||||
}
|
||||
else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
|
||||
// add an extra '' for the one we lose
|
||||
return ['', ...p.split(/\/+/)];
|
||||
}
|
||||
else {
|
||||
return p.split(/\/+/);
|
||||
}
|
||||
}
|
||||
match(f, partial = this.partial) {
|
||||
this.debug('match', f, this.pattern);
|
||||
// short-circuit in the case of busted things.
|
||||
// comments, etc.
|
||||
if (this.comment) {
|
||||
return false;
|
||||
}
|
||||
if (this.empty) {
|
||||
return f === '';
|
||||
}
|
||||
if (f === '/' && partial) {
|
||||
return true;
|
||||
}
|
||||
const options = this.options;
|
||||
// windows: need to use /, not \
|
||||
if (this.isWindows) {
|
||||
f = f.split('\\').join('/');
|
||||
}
|
||||
// treat the test path as a set of pathparts.
|
||||
const ff = this.slashSplit(f);
|
||||
this.debug(this.pattern, 'split', ff);
|
||||
// just ONE of the pattern sets in this.set needs to match
|
||||
// in order for it to be valid. If negating, then just one
|
||||
// match means that we have failed.
|
||||
// Either way, return on the first hit.
|
||||
const set = this.set;
|
||||
this.debug(this.pattern, 'set', set);
|
||||
// Find the basename of the path by looking for the last non-empty segment
|
||||
let filename = ff[ff.length - 1];
|
||||
if (!filename) {
|
||||
for (let i = ff.length - 2; !filename && i >= 0; i--) {
|
||||
filename = ff[i];
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < set.length; i++) {
|
||||
const pattern = set[i];
|
||||
let file = ff;
|
||||
if (options.matchBase && pattern.length === 1) {
|
||||
file = [filename];
|
||||
}
|
||||
const hit = this.matchOne(file, pattern, partial);
|
||||
if (hit) {
|
||||
if (options.flipNegate) {
|
||||
return true;
|
||||
}
|
||||
return !this.negate;
|
||||
}
|
||||
}
|
||||
// didn't get any hits. this is success if it's a negative
|
||||
// pattern, failure otherwise.
|
||||
if (options.flipNegate) {
|
||||
return false;
|
||||
}
|
||||
return this.negate;
|
||||
}
|
||||
static defaults(def) {
|
||||
return minimatch.defaults(def).Minimatch;
|
||||
}
|
||||
}
|
||||
/* c8 ignore start */
|
||||
|
||||
|
||||
|
||||
/* c8 ignore stop */
|
||||
minimatch.AST = AST;
|
||||
minimatch.Minimatch = Minimatch;
|
||||
minimatch.escape = escape_escape;
|
||||
minimatch.unescape = unescape_unescape;
|
||||
//# sourceMappingURL=index.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/lru-cache/dist/esm/index.js
|
||||
/**
|
||||
* @module LRUCache
|
||||
*/
|
||||
const perf = typeof performance === 'object' &&
|
||||
performance &&
|
||||
typeof performance.now === 'function'
|
||||
? performance
|
||||
: Date;
|
||||
const warned = new Set();
|
||||
/* c8 ignore start */
|
||||
const PROCESS = (typeof process === 'object' && !!process ? process : {});
|
||||
/* c8 ignore start */
|
||||
const emitWarning = (msg, type, code, fn) => {
|
||||
typeof PROCESS.emitWarning === 'function'
|
||||
? PROCESS.emitWarning(msg, type, code, fn)
|
||||
: console.error(`[${code}] ${type}: ${msg}`);
|
||||
};
|
||||
let AC = globalThis.AbortController;
|
||||
let AS = globalThis.AbortSignal;
|
||||
/* c8 ignore start */
|
||||
if (typeof AC === 'undefined') {
|
||||
//@ts-ignore
|
||||
AS = class AbortSignal {
|
||||
onabort;
|
||||
_onabort = [];
|
||||
reason;
|
||||
aborted = false;
|
||||
addEventListener(_, fn) {
|
||||
this._onabort.push(fn);
|
||||
}
|
||||
};
|
||||
//@ts-ignore
|
||||
AC = class AbortController {
|
||||
constructor() {
|
||||
warnACPolyfill();
|
||||
}
|
||||
signal = new AS();
|
||||
abort(reason) {
|
||||
if (this.signal.aborted)
|
||||
return;
|
||||
//@ts-ignore
|
||||
this.signal.reason = reason;
|
||||
//@ts-ignore
|
||||
this.signal.aborted = true;
|
||||
//@ts-ignore
|
||||
for (const fn of this.signal._onabort) {
|
||||
fn(reason);
|
||||
}
|
||||
this.signal.onabort?.(reason);
|
||||
}
|
||||
};
|
||||
let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== '1';
|
||||
const warnACPolyfill = () => {
|
||||
if (!printACPolyfillWarning)
|
||||
return;
|
||||
printACPolyfillWarning = false;
|
||||
emitWarning('AbortController is not defined. If using lru-cache in ' +
|
||||
'node 14, load an AbortController polyfill from the ' +
|
||||
'`node-abort-controller` package. A minimal polyfill is ' +
|
||||
'provided for use by LRUCache.fetch(), but it should not be ' +
|
||||
'relied upon in other contexts (eg, passing it to other APIs that ' +
|
||||
'use AbortController/AbortSignal might have undesirable effects). ' +
|
||||
'You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.', 'NO_ABORT_CONTROLLER', 'ENOTSUP', warnACPolyfill);
|
||||
};
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
const shouldWarn = (code) => !warned.has(code);
|
||||
const TYPE = Symbol('type');
|
||||
const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
||||
/* c8 ignore start */
|
||||
// This is a little bit ridiculous, tbh.
|
||||
// The maximum array length is 2^32-1 or thereabouts on most JS impls.
|
||||
// And well before that point, you're caching the entire world, I mean,
|
||||
// that's ~32GB of just integers for the next/prev links, plus whatever
|
||||
// else to hold that many keys and values. Just filling the memory with
|
||||
// zeroes at init time is brutal when you get that big.
|
||||
// But why not be complete?
|
||||
// Maybe in the future, these limits will have expanded.
|
||||
const getUintArray = (max) => !isPosInt(max)
|
||||
? null
|
||||
: max <= Math.pow(2, 8)
|
||||
? Uint8Array
|
||||
: max <= Math.pow(2, 16)
|
||||
? Uint16Array
|
||||
: max <= Math.pow(2, 32)
|
||||
? Uint32Array
|
||||
: max <= Number.MAX_SAFE_INTEGER
|
||||
? ZeroArray
|
||||
: null;
|
||||
/* c8 ignore stop */
|
||||
class ZeroArray extends Array {
|
||||
constructor(size) {
|
||||
super(size);
|
||||
this.fill(0);
|
||||
}
|
||||
}
|
||||
class Stack {
|
||||
heap;
|
||||
length;
|
||||
// private constructor
|
||||
static #constructing = false;
|
||||
static create(max) {
|
||||
const HeapCls = getUintArray(max);
|
||||
if (!HeapCls)
|
||||
return [];
|
||||
Stack.#constructing = true;
|
||||
const s = new Stack(max, HeapCls);
|
||||
Stack.#constructing = false;
|
||||
return s;
|
||||
}
|
||||
constructor(max, HeapCls) {
|
||||
/* c8 ignore start */
|
||||
if (!Stack.#constructing) {
|
||||
throw new TypeError('instantiate Stack using Stack.create(n)');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
this.heap = new HeapCls(max);
|
||||
this.length = 0;
|
||||
}
|
||||
push(n) {
|
||||
this.heap[this.length++] = n;
|
||||
}
|
||||
pop() {
|
||||
return this.heap[--this.length];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Default export, the thing you're using this module to get.
|
||||
*
|
||||
* All properties from the options object (with the exception of
|
||||
* {@link OptionsBase.max} and {@link OptionsBase.maxSize}) are added as
|
||||
* normal public members. (`max` and `maxBase` are read-only getters.)
|
||||
* Changing any of these will alter the defaults for subsequent method calls,
|
||||
* but is otherwise safe.
|
||||
*/
|
||||
class LRUCache {
|
||||
// properties coming in from the options of these, only max and maxSize
|
||||
// really *need* to be protected. The rest can be modified, as they just
|
||||
// set defaults for various methods.
|
||||
#max;
|
||||
#maxSize;
|
||||
#dispose;
|
||||
#disposeAfter;
|
||||
#fetchMethod;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.ttl}
|
||||
*/
|
||||
ttl;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.ttlResolution}
|
||||
*/
|
||||
ttlResolution;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.ttlAutopurge}
|
||||
*/
|
||||
ttlAutopurge;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.updateAgeOnGet}
|
||||
*/
|
||||
updateAgeOnGet;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.updateAgeOnHas}
|
||||
*/
|
||||
updateAgeOnHas;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.allowStale}
|
||||
*/
|
||||
allowStale;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.noDisposeOnSet}
|
||||
*/
|
||||
noDisposeOnSet;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.noUpdateTTL}
|
||||
*/
|
||||
noUpdateTTL;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.maxEntrySize}
|
||||
*/
|
||||
maxEntrySize;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.sizeCalculation}
|
||||
*/
|
||||
sizeCalculation;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
|
||||
*/
|
||||
noDeleteOnFetchRejection;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
|
||||
*/
|
||||
noDeleteOnStaleGet;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
|
||||
*/
|
||||
allowStaleOnFetchAbort;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
|
||||
*/
|
||||
allowStaleOnFetchRejection;
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
|
||||
*/
|
||||
ignoreFetchAbort;
|
||||
// computed properties
|
||||
#size;
|
||||
#calculatedSize;
|
||||
#keyMap;
|
||||
#keyList;
|
||||
#valList;
|
||||
#next;
|
||||
#prev;
|
||||
#head;
|
||||
#tail;
|
||||
#free;
|
||||
#disposed;
|
||||
#sizes;
|
||||
#starts;
|
||||
#ttls;
|
||||
#hasDispose;
|
||||
#hasFetchMethod;
|
||||
#hasDisposeAfter;
|
||||
/**
|
||||
* Do not call this method unless you need to inspect the
|
||||
* inner workings of the cache. If anything returned by this
|
||||
* object is modified in any way, strange breakage may occur.
|
||||
*
|
||||
* These fields are private for a reason!
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
static unsafeExposeInternals(c) {
|
||||
return {
|
||||
// properties
|
||||
starts: c.#starts,
|
||||
ttls: c.#ttls,
|
||||
sizes: c.#sizes,
|
||||
keyMap: c.#keyMap,
|
||||
keyList: c.#keyList,
|
||||
valList: c.#valList,
|
||||
next: c.#next,
|
||||
prev: c.#prev,
|
||||
get head() {
|
||||
return c.#head;
|
||||
},
|
||||
get tail() {
|
||||
return c.#tail;
|
||||
},
|
||||
free: c.#free,
|
||||
// methods
|
||||
isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
|
||||
backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
|
||||
moveToTail: (index) => c.#moveToTail(index),
|
||||
indexes: (options) => c.#indexes(options),
|
||||
rindexes: (options) => c.#rindexes(options),
|
||||
isStale: (index) => c.#isStale(index),
|
||||
};
|
||||
}
|
||||
// Protected read-only members
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.max} (read-only)
|
||||
*/
|
||||
get max() {
|
||||
return this.#max;
|
||||
}
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.maxSize} (read-only)
|
||||
*/
|
||||
get maxSize() {
|
||||
return this.#maxSize;
|
||||
}
|
||||
/**
|
||||
* The total computed size of items in the cache (read-only)
|
||||
*/
|
||||
get calculatedSize() {
|
||||
return this.#calculatedSize;
|
||||
}
|
||||
/**
|
||||
* The number of items stored in the cache (read-only)
|
||||
*/
|
||||
get size() {
|
||||
return this.#size;
|
||||
}
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
|
||||
*/
|
||||
get fetchMethod() {
|
||||
return this.#fetchMethod;
|
||||
}
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.dispose} (read-only)
|
||||
*/
|
||||
get dispose() {
|
||||
return this.#dispose;
|
||||
}
|
||||
/**
|
||||
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
|
||||
*/
|
||||
get disposeAfter() {
|
||||
return this.#disposeAfter;
|
||||
}
|
||||
constructor(options) {
|
||||
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, } = options;
|
||||
if (max !== 0 && !isPosInt(max)) {
|
||||
throw new TypeError('max option must be a nonnegative integer');
|
||||
}
|
||||
const UintArray = max ? getUintArray(max) : Array;
|
||||
if (!UintArray) {
|
||||
throw new Error('invalid max value: ' + max);
|
||||
}
|
||||
this.#max = max;
|
||||
this.#maxSize = maxSize;
|
||||
this.maxEntrySize = maxEntrySize || this.#maxSize;
|
||||
this.sizeCalculation = sizeCalculation;
|
||||
if (this.sizeCalculation) {
|
||||
if (!this.#maxSize && !this.maxEntrySize) {
|
||||
throw new TypeError('cannot set sizeCalculation without setting maxSize or maxEntrySize');
|
||||
}
|
||||
if (typeof this.sizeCalculation !== 'function') {
|
||||
throw new TypeError('sizeCalculation set to non-function');
|
||||
}
|
||||
}
|
||||
if (fetchMethod !== undefined &&
|
||||
typeof fetchMethod !== 'function') {
|
||||
throw new TypeError('fetchMethod must be a function if specified');
|
||||
}
|
||||
this.#fetchMethod = fetchMethod;
|
||||
this.#hasFetchMethod = !!fetchMethod;
|
||||
this.#keyMap = new Map();
|
||||
this.#keyList = new Array(max).fill(undefined);
|
||||
this.#valList = new Array(max).fill(undefined);
|
||||
this.#next = new UintArray(max);
|
||||
this.#prev = new UintArray(max);
|
||||
this.#head = 0;
|
||||
this.#tail = 0;
|
||||
this.#free = Stack.create(max);
|
||||
this.#size = 0;
|
||||
this.#calculatedSize = 0;
|
||||
if (typeof dispose === 'function') {
|
||||
this.#dispose = dispose;
|
||||
}
|
||||
if (typeof disposeAfter === 'function') {
|
||||
this.#disposeAfter = disposeAfter;
|
||||
this.#disposed = [];
|
||||
}
|
||||
else {
|
||||
this.#disposeAfter = undefined;
|
||||
this.#disposed = undefined;
|
||||
}
|
||||
this.#hasDispose = !!this.#dispose;
|
||||
this.#hasDisposeAfter = !!this.#disposeAfter;
|
||||
this.noDisposeOnSet = !!noDisposeOnSet;
|
||||
this.noUpdateTTL = !!noUpdateTTL;
|
||||
this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
|
||||
this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
|
||||
this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
|
||||
this.ignoreFetchAbort = !!ignoreFetchAbort;
|
||||
// NB: maxEntrySize is set to maxSize if it's set
|
||||
if (this.maxEntrySize !== 0) {
|
||||
if (this.#maxSize !== 0) {
|
||||
if (!isPosInt(this.#maxSize)) {
|
||||
throw new TypeError('maxSize must be a positive integer if specified');
|
||||
}
|
||||
}
|
||||
if (!isPosInt(this.maxEntrySize)) {
|
||||
throw new TypeError('maxEntrySize must be a positive integer if specified');
|
||||
}
|
||||
this.#initializeSizeTracking();
|
||||
}
|
||||
this.allowStale = !!allowStale;
|
||||
this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
|
||||
this.updateAgeOnGet = !!updateAgeOnGet;
|
||||
this.updateAgeOnHas = !!updateAgeOnHas;
|
||||
this.ttlResolution =
|
||||
isPosInt(ttlResolution) || ttlResolution === 0
|
||||
? ttlResolution
|
||||
: 1;
|
||||
this.ttlAutopurge = !!ttlAutopurge;
|
||||
this.ttl = ttl || 0;
|
||||
if (this.ttl) {
|
||||
if (!isPosInt(this.ttl)) {
|
||||
throw new TypeError('ttl must be a positive integer if specified');
|
||||
}
|
||||
this.#initializeTTLTracking();
|
||||
}
|
||||
// do not allow completely unbounded caches
|
||||
if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) {
|
||||
throw new TypeError('At least one of max, maxSize, or ttl is required');
|
||||
}
|
||||
if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
|
||||
const code = 'LRU_CACHE_UNBOUNDED';
|
||||
if (shouldWarn(code)) {
|
||||
warned.add(code);
|
||||
const msg = 'TTL caching without ttlAutopurge, max, or maxSize can ' +
|
||||
'result in unbounded memory consumption.';
|
||||
emitWarning(msg, 'UnboundedCacheWarning', code, LRUCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return the remaining TTL time for a given entry key
|
||||
*/
|
||||
getRemainingTTL(key) {
|
||||
return this.#keyMap.has(key) ? Infinity : 0;
|
||||
}
|
||||
#initializeTTLTracking() {
|
||||
const ttls = new ZeroArray(this.#max);
|
||||
const starts = new ZeroArray(this.#max);
|
||||
this.#ttls = ttls;
|
||||
this.#starts = starts;
|
||||
this.#setItemTTL = (index, ttl, start = perf.now()) => {
|
||||
starts[index] = ttl !== 0 ? start : 0;
|
||||
ttls[index] = ttl;
|
||||
if (ttl !== 0 && this.ttlAutopurge) {
|
||||
const t = setTimeout(() => {
|
||||
if (this.#isStale(index)) {
|
||||
this.delete(this.#keyList[index]);
|
||||
}
|
||||
}, ttl + 1);
|
||||
// unref() not supported on all platforms
|
||||
/* c8 ignore start */
|
||||
if (t.unref) {
|
||||
t.unref();
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
};
|
||||
this.#updateItemAge = index => {
|
||||
starts[index] = ttls[index] !== 0 ? perf.now() : 0;
|
||||
};
|
||||
this.#statusTTL = (status, index) => {
|
||||
if (ttls[index]) {
|
||||
const ttl = ttls[index];
|
||||
const start = starts[index];
|
||||
/* c8 ignore next */
|
||||
if (!ttl || !start)
|
||||
return;
|
||||
status.ttl = ttl;
|
||||
status.start = start;
|
||||
status.now = cachedNow || getNow();
|
||||
const age = status.now - start;
|
||||
status.remainingTTL = ttl - age;
|
||||
}
|
||||
};
|
||||
// debounce calls to perf.now() to 1s so we're not hitting
|
||||
// that costly call repeatedly.
|
||||
let cachedNow = 0;
|
||||
const getNow = () => {
|
||||
const n = perf.now();
|
||||
if (this.ttlResolution > 0) {
|
||||
cachedNow = n;
|
||||
const t = setTimeout(() => (cachedNow = 0), this.ttlResolution);
|
||||
// not available on all platforms
|
||||
/* c8 ignore start */
|
||||
if (t.unref) {
|
||||
t.unref();
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
return n;
|
||||
};
|
||||
this.getRemainingTTL = key => {
|
||||
const index = this.#keyMap.get(key);
|
||||
if (index === undefined) {
|
||||
return 0;
|
||||
}
|
||||
const ttl = ttls[index];
|
||||
const start = starts[index];
|
||||
if (!ttl || !start) {
|
||||
return Infinity;
|
||||
}
|
||||
const age = (cachedNow || getNow()) - start;
|
||||
return ttl - age;
|
||||
};
|
||||
this.#isStale = index => {
|
||||
const s = starts[index];
|
||||
const t = ttls[index];
|
||||
return !!t && !!s && (cachedNow || getNow()) - s > t;
|
||||
};
|
||||
}
|
||||
// conditionally set private methods related to TTL
|
||||
#updateItemAge = () => { };
|
||||
#statusTTL = () => { };
|
||||
#setItemTTL = () => { };
|
||||
/* c8 ignore stop */
|
||||
#isStale = () => false;
|
||||
#initializeSizeTracking() {
|
||||
const sizes = new ZeroArray(this.#max);
|
||||
this.#calculatedSize = 0;
|
||||
this.#sizes = sizes;
|
||||
this.#removeItemSize = index => {
|
||||
this.#calculatedSize -= sizes[index];
|
||||
sizes[index] = 0;
|
||||
};
|
||||
this.#requireSize = (k, v, size, sizeCalculation) => {
|
||||
// provisionally accept background fetches.
|
||||
// actual value size will be checked when they return.
|
||||
if (this.#isBackgroundFetch(v)) {
|
||||
return 0;
|
||||
}
|
||||
if (!isPosInt(size)) {
|
||||
if (sizeCalculation) {
|
||||
if (typeof sizeCalculation !== 'function') {
|
||||
throw new TypeError('sizeCalculation must be a function');
|
||||
}
|
||||
size = sizeCalculation(v, k);
|
||||
if (!isPosInt(size)) {
|
||||
throw new TypeError('sizeCalculation return invalid (expect positive integer)');
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new TypeError('invalid size value (must be positive integer). ' +
|
||||
'When maxSize or maxEntrySize is used, sizeCalculation ' +
|
||||
'or size must be set.');
|
||||
}
|
||||
}
|
||||
return size;
|
||||
};
|
||||
this.#addItemSize = (index, size, status) => {
|
||||
sizes[index] = size;
|
||||
if (this.#maxSize) {
|
||||
const maxSize = this.#maxSize - sizes[index];
|
||||
while (this.#calculatedSize > maxSize) {
|
||||
this.#evict(true);
|
||||
}
|
||||
}
|
||||
this.#calculatedSize += sizes[index];
|
||||
if (status) {
|
||||
status.entrySize = size;
|
||||
status.totalCalculatedSize = this.#calculatedSize;
|
||||
}
|
||||
};
|
||||
}
|
||||
#removeItemSize = _i => { };
|
||||
#addItemSize = (_i, _s, _st) => { };
|
||||
#requireSize = (_k, _v, size, sizeCalculation) => {
|
||||
if (size || sizeCalculation) {
|
||||
throw new TypeError('cannot set size without setting maxSize or maxEntrySize on cache');
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
*#indexes({ allowStale = this.allowStale } = {}) {
|
||||
if (this.#size) {
|
||||
for (let i = this.#tail; true;) {
|
||||
if (!this.#isValidIndex(i)) {
|
||||
break;
|
||||
}
|
||||
if (allowStale || !this.#isStale(i)) {
|
||||
yield i;
|
||||
}
|
||||
if (i === this.#head) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
i = this.#prev[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*#rindexes({ allowStale = this.allowStale } = {}) {
|
||||
if (this.#size) {
|
||||
for (let i = this.#head; true;) {
|
||||
if (!this.#isValidIndex(i)) {
|
||||
break;
|
||||
}
|
||||
if (allowStale || !this.#isStale(i)) {
|
||||
yield i;
|
||||
}
|
||||
if (i === this.#tail) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
i = this.#next[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#isValidIndex(index) {
|
||||
return (index !== undefined &&
|
||||
this.#keyMap.get(this.#keyList[index]) === index);
|
||||
}
|
||||
/**
|
||||
* Return a generator yielding `[key, value]` pairs,
|
||||
* in order from most recently used to least recently used.
|
||||
*/
|
||||
*entries() {
|
||||
for (const i of this.#indexes()) {
|
||||
if (this.#valList[i] !== undefined &&
|
||||
this.#keyList[i] !== undefined &&
|
||||
!this.#isBackgroundFetch(this.#valList[i])) {
|
||||
yield [this.#keyList[i], this.#valList[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Inverse order version of {@link LRUCache.entries}
|
||||
*
|
||||
* Return a generator yielding `[key, value]` pairs,
|
||||
* in order from least recently used to most recently used.
|
||||
*/
|
||||
*rentries() {
|
||||
for (const i of this.#rindexes()) {
|
||||
if (this.#valList[i] !== undefined &&
|
||||
this.#keyList[i] !== undefined &&
|
||||
!this.#isBackgroundFetch(this.#valList[i])) {
|
||||
yield [this.#keyList[i], this.#valList[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return a generator yielding the keys in the cache,
|
||||
* in order from most recently used to least recently used.
|
||||
*/
|
||||
*keys() {
|
||||
for (const i of this.#indexes()) {
|
||||
const k = this.#keyList[i];
|
||||
if (k !== undefined &&
|
||||
!this.#isBackgroundFetch(this.#valList[i])) {
|
||||
yield k;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Inverse order version of {@link LRUCache.keys}
|
||||
*
|
||||
* Return a generator yielding the keys in the cache,
|
||||
* in order from least recently used to most recently used.
|
||||
*/
|
||||
*rkeys() {
|
||||
for (const i of this.#rindexes()) {
|
||||
const k = this.#keyList[i];
|
||||
if (k !== undefined &&
|
||||
!this.#isBackgroundFetch(this.#valList[i])) {
|
||||
yield k;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return a generator yielding the values in the cache,
|
||||
* in order from most recently used to least recently used.
|
||||
*/
|
||||
*values() {
|
||||
for (const i of this.#indexes()) {
|
||||
const v = this.#valList[i];
|
||||
if (v !== undefined &&
|
||||
!this.#isBackgroundFetch(this.#valList[i])) {
|
||||
yield this.#valList[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Inverse order version of {@link LRUCache.values}
|
||||
*
|
||||
* Return a generator yielding the values in the cache,
|
||||
* in order from least recently used to most recently used.
|
||||
*/
|
||||
*rvalues() {
|
||||
for (const i of this.#rindexes()) {
|
||||
const v = this.#valList[i];
|
||||
if (v !== undefined &&
|
||||
!this.#isBackgroundFetch(this.#valList[i])) {
|
||||
yield this.#valList[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Iterating over the cache itself yields the same results as
|
||||
* {@link LRUCache.entries}
|
||||
*/
|
||||
[Symbol.iterator]() {
|
||||
return this.entries();
|
||||
}
|
||||
/**
|
||||
* Find a value for which the supplied fn method returns a truthy value,
|
||||
* similar to Array.find(). fn is called as fn(value, key, cache).
|
||||
*/
|
||||
find(fn, getOptions = {}) {
|
||||
for (const i of this.#indexes()) {
|
||||
const v = this.#valList[i];
|
||||
const value = this.#isBackgroundFetch(v)
|
||||
? v.__staleWhileFetching
|
||||
: v;
|
||||
if (value === undefined)
|
||||
continue;
|
||||
if (fn(value, this.#keyList[i], this)) {
|
||||
return this.get(this.#keyList[i], getOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call the supplied function on each item in the cache, in order from
|
||||
* most recently used to least recently used. fn is called as
|
||||
* fn(value, key, cache). Does not update age or recenty of use.
|
||||
* Does not iterate over stale values.
|
||||
*/
|
||||
forEach(fn, thisp = this) {
|
||||
for (const i of this.#indexes()) {
|
||||
const v = this.#valList[i];
|
||||
const value = this.#isBackgroundFetch(v)
|
||||
? v.__staleWhileFetching
|
||||
: v;
|
||||
if (value === undefined)
|
||||
continue;
|
||||
fn.call(thisp, value, this.#keyList[i], this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The same as {@link LRUCache.forEach} but items are iterated over in
|
||||
* reverse order. (ie, less recently used items are iterated over first.)
|
||||
*/
|
||||
rforEach(fn, thisp = this) {
|
||||
for (const i of this.#rindexes()) {
|
||||
const v = this.#valList[i];
|
||||
const value = this.#isBackgroundFetch(v)
|
||||
? v.__staleWhileFetching
|
||||
: v;
|
||||
if (value === undefined)
|
||||
continue;
|
||||
fn.call(thisp, value, this.#keyList[i], this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Delete any stale entries. Returns true if anything was removed,
|
||||
* false otherwise.
|
||||
*/
|
||||
purgeStale() {
|
||||
let deleted = false;
|
||||
for (const i of this.#rindexes({ allowStale: true })) {
|
||||
if (this.#isStale(i)) {
|
||||
this.delete(this.#keyList[i]);
|
||||
deleted = true;
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
/**
|
||||
* Get the extended info about a given entry, to get its value, size, and
|
||||
* TTL info simultaneously. Like {@link LRUCache#dump}, but just for a
|
||||
* single key. Always returns stale values, if their info is found in the
|
||||
* cache, so be sure to check for expired TTLs if relevant.
|
||||
*/
|
||||
info(key) {
|
||||
const i = this.#keyMap.get(key);
|
||||
if (i === undefined)
|
||||
return undefined;
|
||||
const v = this.#valList[i];
|
||||
const value = this.#isBackgroundFetch(v)
|
||||
? v.__staleWhileFetching
|
||||
: v;
|
||||
if (value === undefined)
|
||||
return undefined;
|
||||
const entry = { value };
|
||||
if (this.#ttls && this.#starts) {
|
||||
const ttl = this.#ttls[i];
|
||||
const start = this.#starts[i];
|
||||
if (ttl && start) {
|
||||
const remain = ttl - (perf.now() - start);
|
||||
entry.ttl = remain;
|
||||
entry.start = Date.now();
|
||||
}
|
||||
}
|
||||
if (this.#sizes) {
|
||||
entry.size = this.#sizes[i];
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
/**
|
||||
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
|
||||
* passed to cache.load()
|
||||
*/
|
||||
dump() {
|
||||
const arr = [];
|
||||
for (const i of this.#indexes({ allowStale: true })) {
|
||||
const key = this.#keyList[i];
|
||||
const v = this.#valList[i];
|
||||
const value = this.#isBackgroundFetch(v)
|
||||
? v.__staleWhileFetching
|
||||
: v;
|
||||
if (value === undefined || key === undefined)
|
||||
continue;
|
||||
const entry = { value };
|
||||
if (this.#ttls && this.#starts) {
|
||||
entry.ttl = this.#ttls[i];
|
||||
// always dump the start relative to a portable timestamp
|
||||
// it's ok for this to be a bit slow, it's a rare operation.
|
||||
const age = perf.now() - this.#starts[i];
|
||||
entry.start = Math.floor(Date.now() - age);
|
||||
}
|
||||
if (this.#sizes) {
|
||||
entry.size = this.#sizes[i];
|
||||
}
|
||||
arr.unshift([key, entry]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
/**
|
||||
* Reset the cache and load in the items in entries in the order listed.
|
||||
* Note that the shape of the resulting cache may be different if the
|
||||
* same options are not used in both caches.
|
||||
*/
|
||||
load(arr) {
|
||||
this.clear();
|
||||
for (const [key, entry] of arr) {
|
||||
if (entry.start) {
|
||||
// entry.start is a portable timestamp, but we may be using
|
||||
// node's performance.now(), so calculate the offset, so that
|
||||
// we get the intended remaining TTL, no matter how long it's
|
||||
// been on ice.
|
||||
//
|
||||
// it's ok for this to be a bit slow, it's a rare operation.
|
||||
const age = Date.now() - entry.start;
|
||||
entry.start = perf.now() - age;
|
||||
}
|
||||
this.set(key, entry.value, entry);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add a value to the cache.
|
||||
*
|
||||
* Note: if `undefined` is specified as a value, this is an alias for
|
||||
* {@link LRUCache#delete}
|
||||
*/
|
||||
set(k, v, setOptions = {}) {
|
||||
if (v === undefined) {
|
||||
this.delete(k);
|
||||
return this;
|
||||
}
|
||||
const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status, } = setOptions;
|
||||
let { noUpdateTTL = this.noUpdateTTL } = setOptions;
|
||||
const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation);
|
||||
// if the item doesn't fit, don't do anything
|
||||
// NB: maxEntrySize set to maxSize by default
|
||||
if (this.maxEntrySize && size > this.maxEntrySize) {
|
||||
if (status) {
|
||||
status.set = 'miss';
|
||||
status.maxEntrySizeExceeded = true;
|
||||
}
|
||||
// have to delete, in case something is there already.
|
||||
this.delete(k);
|
||||
return this;
|
||||
}
|
||||
let index = this.#size === 0 ? undefined : this.#keyMap.get(k);
|
||||
if (index === undefined) {
|
||||
// addition
|
||||
index = (this.#size === 0
|
||||
? this.#tail
|
||||
: this.#free.length !== 0
|
||||
? this.#free.pop()
|
||||
: this.#size === this.#max
|
||||
? this.#evict(false)
|
||||
: this.#size);
|
||||
this.#keyList[index] = k;
|
||||
this.#valList[index] = v;
|
||||
this.#keyMap.set(k, index);
|
||||
this.#next[this.#tail] = index;
|
||||
this.#prev[index] = this.#tail;
|
||||
this.#tail = index;
|
||||
this.#size++;
|
||||
this.#addItemSize(index, size, status);
|
||||
if (status)
|
||||
status.set = 'add';
|
||||
noUpdateTTL = false;
|
||||
}
|
||||
else {
|
||||
// update
|
||||
this.#moveToTail(index);
|
||||
const oldVal = this.#valList[index];
|
||||
if (v !== oldVal) {
|
||||
if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
|
||||
oldVal.__abortController.abort(new Error('replaced'));
|
||||
const { __staleWhileFetching: s } = oldVal;
|
||||
if (s !== undefined && !noDisposeOnSet) {
|
||||
if (this.#hasDispose) {
|
||||
this.#dispose?.(s, k, 'set');
|
||||
}
|
||||
if (this.#hasDisposeAfter) {
|
||||
this.#disposed?.push([s, k, 'set']);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!noDisposeOnSet) {
|
||||
if (this.#hasDispose) {
|
||||
this.#dispose?.(oldVal, k, 'set');
|
||||
}
|
||||
if (this.#hasDisposeAfter) {
|
||||
this.#disposed?.push([oldVal, k, 'set']);
|
||||
}
|
||||
}
|
||||
this.#removeItemSize(index);
|
||||
this.#addItemSize(index, size, status);
|
||||
this.#valList[index] = v;
|
||||
if (status) {
|
||||
status.set = 'replace';
|
||||
const oldValue = oldVal && this.#isBackgroundFetch(oldVal)
|
||||
? oldVal.__staleWhileFetching
|
||||
: oldVal;
|
||||
if (oldValue !== undefined)
|
||||
status.oldValue = oldValue;
|
||||
}
|
||||
}
|
||||
else if (status) {
|
||||
status.set = 'update';
|
||||
}
|
||||
}
|
||||
if (ttl !== 0 && !this.#ttls) {
|
||||
this.#initializeTTLTracking();
|
||||
}
|
||||
if (this.#ttls) {
|
||||
if (!noUpdateTTL) {
|
||||
this.#setItemTTL(index, ttl, start);
|
||||
}
|
||||
if (status)
|
||||
this.#statusTTL(status, index);
|
||||
}
|
||||
if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
|
||||
const dt = this.#disposed;
|
||||
let task;
|
||||
while ((task = dt?.shift())) {
|
||||
this.#disposeAfter?.(...task);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Evict the least recently used item, returning its value or
|
||||
* `undefined` if cache is empty.
|
||||
*/
|
||||
pop() {
|
||||
try {
|
||||
while (this.#size) {
|
||||
const val = this.#valList[this.#head];
|
||||
this.#evict(true);
|
||||
if (this.#isBackgroundFetch(val)) {
|
||||
if (val.__staleWhileFetching) {
|
||||
return val.__staleWhileFetching;
|
||||
}
|
||||
}
|
||||
else if (val !== undefined) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (this.#hasDisposeAfter && this.#disposed) {
|
||||
const dt = this.#disposed;
|
||||
let task;
|
||||
while ((task = dt?.shift())) {
|
||||
this.#disposeAfter?.(...task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#evict(free) {
|
||||
const head = this.#head;
|
||||
const k = this.#keyList[head];
|
||||
const v = this.#valList[head];
|
||||
if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) {
|
||||
v.__abortController.abort(new Error('evicted'));
|
||||
}
|
||||
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
||||
if (this.#hasDispose) {
|
||||
this.#dispose?.(v, k, 'evict');
|
||||
}
|
||||
if (this.#hasDisposeAfter) {
|
||||
this.#disposed?.push([v, k, 'evict']);
|
||||
}
|
||||
}
|
||||
this.#removeItemSize(head);
|
||||
// if we aren't about to use the index, then null these out
|
||||
if (free) {
|
||||
this.#keyList[head] = undefined;
|
||||
this.#valList[head] = undefined;
|
||||
this.#free.push(head);
|
||||
}
|
||||
if (this.#size === 1) {
|
||||
this.#head = this.#tail = 0;
|
||||
this.#free.length = 0;
|
||||
}
|
||||
else {
|
||||
this.#head = this.#next[head];
|
||||
}
|
||||
this.#keyMap.delete(k);
|
||||
this.#size--;
|
||||
return head;
|
||||
}
|
||||
/**
|
||||
* Check if a key is in the cache, without updating the recency of use.
|
||||
* Will return false if the item is stale, even though it is technically
|
||||
* in the cache.
|
||||
*
|
||||
* Will not update item age unless
|
||||
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
|
||||
*/
|
||||
has(k, hasOptions = {}) {
|
||||
const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
|
||||
const index = this.#keyMap.get(k);
|
||||
if (index !== undefined) {
|
||||
const v = this.#valList[index];
|
||||
if (this.#isBackgroundFetch(v) &&
|
||||
v.__staleWhileFetching === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (!this.#isStale(index)) {
|
||||
if (updateAgeOnHas) {
|
||||
this.#updateItemAge(index);
|
||||
}
|
||||
if (status) {
|
||||
status.has = 'hit';
|
||||
this.#statusTTL(status, index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (status) {
|
||||
status.has = 'stale';
|
||||
this.#statusTTL(status, index);
|
||||
}
|
||||
}
|
||||
else if (status) {
|
||||
status.has = 'miss';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Like {@link LRUCache#get} but doesn't update recency or delete stale
|
||||
* items.
|
||||
*
|
||||
* Returns `undefined` if the item is stale, unless
|
||||
* {@link LRUCache.OptionsBase.allowStale} is set.
|
||||
*/
|
||||
peek(k, peekOptions = {}) {
|
||||
const { allowStale = this.allowStale } = peekOptions;
|
||||
const index = this.#keyMap.get(k);
|
||||
if (index === undefined ||
|
||||
(!allowStale && this.#isStale(index))) {
|
||||
return;
|
||||
}
|
||||
const v = this.#valList[index];
|
||||
// either stale and allowed, or forcing a refresh of non-stale value
|
||||
return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
||||
}
|
||||
#backgroundFetch(k, index, options, context) {
|
||||
const v = index === undefined ? undefined : this.#valList[index];
|
||||
if (this.#isBackgroundFetch(v)) {
|
||||
return v;
|
||||
}
|
||||
const ac = new AC();
|
||||
const { signal } = options;
|
||||
// when/if our AC signals, then stop listening to theirs.
|
||||
signal?.addEventListener('abort', () => ac.abort(signal.reason), {
|
||||
signal: ac.signal,
|
||||
});
|
||||
const fetchOpts = {
|
||||
signal: ac.signal,
|
||||
options,
|
||||
context,
|
||||
};
|
||||
const cb = (v, updateCache = false) => {
|
||||
const { aborted } = ac.signal;
|
||||
const ignoreAbort = options.ignoreFetchAbort && v !== undefined;
|
||||
if (options.status) {
|
||||
if (aborted && !updateCache) {
|
||||
options.status.fetchAborted = true;
|
||||
options.status.fetchError = ac.signal.reason;
|
||||
if (ignoreAbort)
|
||||
options.status.fetchAbortIgnored = true;
|
||||
}
|
||||
else {
|
||||
options.status.fetchResolved = true;
|
||||
}
|
||||
}
|
||||
if (aborted && !ignoreAbort && !updateCache) {
|
||||
return fetchFail(ac.signal.reason);
|
||||
}
|
||||
// either we didn't abort, and are still here, or we did, and ignored
|
||||
const bf = p;
|
||||
if (this.#valList[index] === p) {
|
||||
if (v === undefined) {
|
||||
if (bf.__staleWhileFetching) {
|
||||
this.#valList[index] = bf.__staleWhileFetching;
|
||||
}
|
||||
else {
|
||||
this.delete(k);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (options.status)
|
||||
options.status.fetchUpdated = true;
|
||||
this.set(k, v, fetchOpts.options);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
};
|
||||
const eb = (er) => {
|
||||
if (options.status) {
|
||||
options.status.fetchRejected = true;
|
||||
options.status.fetchError = er;
|
||||
}
|
||||
return fetchFail(er);
|
||||
};
|
||||
const fetchFail = (er) => {
|
||||
const { aborted } = ac.signal;
|
||||
const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
|
||||
const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
|
||||
const noDelete = allowStale || options.noDeleteOnFetchRejection;
|
||||
const bf = p;
|
||||
if (this.#valList[index] === p) {
|
||||
// if we allow stale on fetch rejections, then we need to ensure that
|
||||
// the stale value is not removed from the cache when the fetch fails.
|
||||
const del = !noDelete || bf.__staleWhileFetching === undefined;
|
||||
if (del) {
|
||||
this.delete(k);
|
||||
}
|
||||
else if (!allowStaleAborted) {
|
||||
// still replace the *promise* with the stale value,
|
||||
// since we are done with the promise at this point.
|
||||
// leave it untouched if we're still waiting for an
|
||||
// aborted background fetch that hasn't yet returned.
|
||||
this.#valList[index] = bf.__staleWhileFetching;
|
||||
}
|
||||
}
|
||||
if (allowStale) {
|
||||
if (options.status && bf.__staleWhileFetching !== undefined) {
|
||||
options.status.returnedStale = true;
|
||||
}
|
||||
return bf.__staleWhileFetching;
|
||||
}
|
||||
else if (bf.__returned === bf) {
|
||||
throw er;
|
||||
}
|
||||
};
|
||||
const pcall = (res, rej) => {
|
||||
const fmp = this.#fetchMethod?.(k, v, fetchOpts);
|
||||
if (fmp && fmp instanceof Promise) {
|
||||
fmp.then(v => res(v === undefined ? undefined : v), rej);
|
||||
}
|
||||
// ignored, we go until we finish, regardless.
|
||||
// defer check until we are actually aborting,
|
||||
// so fetchMethod can override.
|
||||
ac.signal.addEventListener('abort', () => {
|
||||
if (!options.ignoreFetchAbort ||
|
||||
options.allowStaleOnFetchAbort) {
|
||||
res(undefined);
|
||||
// when it eventually resolves, update the cache.
|
||||
if (options.allowStaleOnFetchAbort) {
|
||||
res = v => cb(v, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
if (options.status)
|
||||
options.status.fetchDispatched = true;
|
||||
const p = new Promise(pcall).then(cb, eb);
|
||||
const bf = Object.assign(p, {
|
||||
__abortController: ac,
|
||||
__staleWhileFetching: v,
|
||||
__returned: undefined,
|
||||
});
|
||||
if (index === undefined) {
|
||||
// internal, don't expose status.
|
||||
this.set(k, bf, { ...fetchOpts.options, status: undefined });
|
||||
index = this.#keyMap.get(k);
|
||||
}
|
||||
else {
|
||||
this.#valList[index] = bf;
|
||||
}
|
||||
return bf;
|
||||
}
|
||||
#isBackgroundFetch(p) {
|
||||
if (!this.#hasFetchMethod)
|
||||
return false;
|
||||
const b = p;
|
||||
return (!!b &&
|
||||
b instanceof Promise &&
|
||||
b.hasOwnProperty('__staleWhileFetching') &&
|
||||
b.__abortController instanceof AC);
|
||||
}
|
||||
async fetch(k, fetchOptions = {}) {
|
||||
const {
|
||||
// get options
|
||||
allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet,
|
||||
// set options
|
||||
ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL,
|
||||
// fetch exclusive options
|
||||
noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal, } = fetchOptions;
|
||||
if (!this.#hasFetchMethod) {
|
||||
if (status)
|
||||
status.fetch = 'get';
|
||||
return this.get(k, {
|
||||
allowStale,
|
||||
updateAgeOnGet,
|
||||
noDeleteOnStaleGet,
|
||||
status,
|
||||
});
|
||||
}
|
||||
const options = {
|
||||
allowStale,
|
||||
updateAgeOnGet,
|
||||
noDeleteOnStaleGet,
|
||||
ttl,
|
||||
noDisposeOnSet,
|
||||
size,
|
||||
sizeCalculation,
|
||||
noUpdateTTL,
|
||||
noDeleteOnFetchRejection,
|
||||
allowStaleOnFetchRejection,
|
||||
allowStaleOnFetchAbort,
|
||||
ignoreFetchAbort,
|
||||
status,
|
||||
signal,
|
||||
};
|
||||
let index = this.#keyMap.get(k);
|
||||
if (index === undefined) {
|
||||
if (status)
|
||||
status.fetch = 'miss';
|
||||
const p = this.#backgroundFetch(k, index, options, context);
|
||||
return (p.__returned = p);
|
||||
}
|
||||
else {
|
||||
// in cache, maybe already fetching
|
||||
const v = this.#valList[index];
|
||||
if (this.#isBackgroundFetch(v)) {
|
||||
const stale = allowStale && v.__staleWhileFetching !== undefined;
|
||||
if (status) {
|
||||
status.fetch = 'inflight';
|
||||
if (stale)
|
||||
status.returnedStale = true;
|
||||
}
|
||||
return stale ? v.__staleWhileFetching : (v.__returned = v);
|
||||
}
|
||||
// if we force a refresh, that means do NOT serve the cached value,
|
||||
// unless we are already in the process of refreshing the cache.
|
||||
const isStale = this.#isStale(index);
|
||||
if (!forceRefresh && !isStale) {
|
||||
if (status)
|
||||
status.fetch = 'hit';
|
||||
this.#moveToTail(index);
|
||||
if (updateAgeOnGet) {
|
||||
this.#updateItemAge(index);
|
||||
}
|
||||
if (status)
|
||||
this.#statusTTL(status, index);
|
||||
return v;
|
||||
}
|
||||
// ok, it is stale or a forced refresh, and not already fetching.
|
||||
// refresh the cache.
|
||||
const p = this.#backgroundFetch(k, index, options, context);
|
||||
const hasStale = p.__staleWhileFetching !== undefined;
|
||||
const staleVal = hasStale && allowStale;
|
||||
if (status) {
|
||||
status.fetch = isStale ? 'stale' : 'refresh';
|
||||
if (staleVal && isStale)
|
||||
status.returnedStale = true;
|
||||
}
|
||||
return staleVal ? p.__staleWhileFetching : (p.__returned = p);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return a value from the cache. Will update the recency of the cache
|
||||
* entry found.
|
||||
*
|
||||
* If the key is not found, get() will return `undefined`.
|
||||
*/
|
||||
get(k, getOptions = {}) {
|
||||
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status, } = getOptions;
|
||||
const index = this.#keyMap.get(k);
|
||||
if (index !== undefined) {
|
||||
const value = this.#valList[index];
|
||||
const fetching = this.#isBackgroundFetch(value);
|
||||
if (status)
|
||||
this.#statusTTL(status, index);
|
||||
if (this.#isStale(index)) {
|
||||
if (status)
|
||||
status.get = 'stale';
|
||||
// delete only if not an in-flight background fetch
|
||||
if (!fetching) {
|
||||
if (!noDeleteOnStaleGet) {
|
||||
this.delete(k);
|
||||
}
|
||||
if (status && allowStale)
|
||||
status.returnedStale = true;
|
||||
return allowStale ? value : undefined;
|
||||
}
|
||||
else {
|
||||
if (status &&
|
||||
allowStale &&
|
||||
value.__staleWhileFetching !== undefined) {
|
||||
status.returnedStale = true;
|
||||
}
|
||||
return allowStale ? value.__staleWhileFetching : undefined;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (status)
|
||||
status.get = 'hit';
|
||||
// if we're currently fetching it, we don't actually have it yet
|
||||
// it's not stale, which means this isn't a staleWhileRefetching.
|
||||
// If it's not stale, and fetching, AND has a __staleWhileFetching
|
||||
// value, then that means the user fetched with {forceRefresh:true},
|
||||
// so it's safe to return that value.
|
||||
if (fetching) {
|
||||
return value.__staleWhileFetching;
|
||||
}
|
||||
this.#moveToTail(index);
|
||||
if (updateAgeOnGet) {
|
||||
this.#updateItemAge(index);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else if (status) {
|
||||
status.get = 'miss';
|
||||
}
|
||||
}
|
||||
#connect(p, n) {
|
||||
this.#prev[n] = p;
|
||||
this.#next[p] = n;
|
||||
}
|
||||
#moveToTail(index) {
|
||||
// if tail already, nothing to do
|
||||
// if head, move head to next[index]
|
||||
// else
|
||||
// move next[prev[index]] to next[index] (head has no prev)
|
||||
// move prev[next[index]] to prev[index]
|
||||
// prev[index] = tail
|
||||
// next[tail] = index
|
||||
// tail = index
|
||||
if (index !== this.#tail) {
|
||||
if (index === this.#head) {
|
||||
this.#head = this.#next[index];
|
||||
}
|
||||
else {
|
||||
this.#connect(this.#prev[index], this.#next[index]);
|
||||
}
|
||||
this.#connect(this.#tail, index);
|
||||
this.#tail = index;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deletes a key out of the cache.
|
||||
* Returns true if the key was deleted, false otherwise.
|
||||
*/
|
||||
delete(k) {
|
||||
let deleted = false;
|
||||
if (this.#size !== 0) {
|
||||
const index = this.#keyMap.get(k);
|
||||
if (index !== undefined) {
|
||||
deleted = true;
|
||||
if (this.#size === 1) {
|
||||
this.clear();
|
||||
}
|
||||
else {
|
||||
this.#removeItemSize(index);
|
||||
const v = this.#valList[index];
|
||||
if (this.#isBackgroundFetch(v)) {
|
||||
v.__abortController.abort(new Error('deleted'));
|
||||
}
|
||||
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
||||
if (this.#hasDispose) {
|
||||
this.#dispose?.(v, k, 'delete');
|
||||
}
|
||||
if (this.#hasDisposeAfter) {
|
||||
this.#disposed?.push([v, k, 'delete']);
|
||||
}
|
||||
}
|
||||
this.#keyMap.delete(k);
|
||||
this.#keyList[index] = undefined;
|
||||
this.#valList[index] = undefined;
|
||||
if (index === this.#tail) {
|
||||
this.#tail = this.#prev[index];
|
||||
}
|
||||
else if (index === this.#head) {
|
||||
this.#head = this.#next[index];
|
||||
}
|
||||
else {
|
||||
const pi = this.#prev[index];
|
||||
this.#next[pi] = this.#next[index];
|
||||
const ni = this.#next[index];
|
||||
this.#prev[ni] = this.#prev[index];
|
||||
}
|
||||
this.#size--;
|
||||
this.#free.push(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.#hasDisposeAfter && this.#disposed?.length) {
|
||||
const dt = this.#disposed;
|
||||
let task;
|
||||
while ((task = dt?.shift())) {
|
||||
this.#disposeAfter?.(...task);
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
/**
|
||||
* Clear the cache entirely, throwing away all values.
|
||||
*/
|
||||
clear() {
|
||||
for (const index of this.#rindexes({ allowStale: true })) {
|
||||
const v = this.#valList[index];
|
||||
if (this.#isBackgroundFetch(v)) {
|
||||
v.__abortController.abort(new Error('deleted'));
|
||||
}
|
||||
else {
|
||||
const k = this.#keyList[index];
|
||||
if (this.#hasDispose) {
|
||||
this.#dispose?.(v, k, 'delete');
|
||||
}
|
||||
if (this.#hasDisposeAfter) {
|
||||
this.#disposed?.push([v, k, 'delete']);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.#keyMap.clear();
|
||||
this.#valList.fill(undefined);
|
||||
this.#keyList.fill(undefined);
|
||||
if (this.#ttls && this.#starts) {
|
||||
this.#ttls.fill(0);
|
||||
this.#starts.fill(0);
|
||||
}
|
||||
if (this.#sizes) {
|
||||
this.#sizes.fill(0);
|
||||
}
|
||||
this.#head = 0;
|
||||
this.#tail = 0;
|
||||
this.#free.length = 0;
|
||||
this.#calculatedSize = 0;
|
||||
this.#size = 0;
|
||||
if (this.#hasDisposeAfter && this.#disposed) {
|
||||
const dt = this.#disposed;
|
||||
let task;
|
||||
while ((task = dt?.shift())) {
|
||||
this.#disposeAfter?.(...task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
// EXTERNAL MODULE: external "path"
|
||||
var external_path_ = __nccwpck_require__(1017);
|
||||
// EXTERNAL MODULE: external "url"
|
||||
var external_url_ = __nccwpck_require__(7310);
|
||||
;// CONCATENATED MODULE: external "fs/promises"
|
||||
const promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("fs/promises");
|
||||
// EXTERNAL MODULE: external "events"
|
||||
var external_events_ = __nccwpck_require__(2361);
|
||||
// EXTERNAL MODULE: external "stream"
|
||||
var external_stream_ = __nccwpck_require__(2781);
|
||||
// EXTERNAL MODULE: external "string_decoder"
|
||||
var external_string_decoder_ = __nccwpck_require__(1576);
|
||||
;// CONCATENATED MODULE: ./node_modules/minipass/dist/esm/index.js
|
||||
const proc = typeof process === 'object' && process
|
||||
? process
|
||||
: {
|
||||
stdout: null,
|
||||
stderr: null,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the argument is a Minipass stream, Node stream, or something
|
||||
* else that Minipass can interact with.
|
||||
*/
|
||||
const isStream = (s) => !!s &&
|
||||
typeof s === 'object' &&
|
||||
(s instanceof Minipass ||
|
||||
s instanceof external_stream_ ||
|
||||
isReadable(s) ||
|
||||
isWritable(s));
|
||||
/**
|
||||
* Return true if the argument is a valid {@link Minipass.Readable}
|
||||
*/
|
||||
const isReadable = (s) => !!s &&
|
||||
typeof s === 'object' &&
|
||||
s instanceof external_events_.EventEmitter &&
|
||||
typeof s.pipe === 'function' &&
|
||||
// node core Writable streams have a pipe() method, but it throws
|
||||
s.pipe !== external_stream_.Writable.prototype.pipe;
|
||||
/**
|
||||
* Return true if the argument is a valid {@link Minipass.Writable}
|
||||
*/
|
||||
const isWritable = (s) => !!s &&
|
||||
typeof s === 'object' &&
|
||||
s instanceof external_events_.EventEmitter &&
|
||||
typeof s.write === 'function' &&
|
||||
typeof s.end === 'function';
|
||||
const EOF = Symbol('EOF');
|
||||
const MAYBE_EMIT_END = Symbol('maybeEmitEnd');
|
||||
const EMITTED_END = Symbol('emittedEnd');
|
||||
const EMITTING_END = Symbol('emittingEnd');
|
||||
const EMITTED_ERROR = Symbol('emittedError');
|
||||
const CLOSED = Symbol('closed');
|
||||
const READ = Symbol('read');
|
||||
const FLUSH = Symbol('flush');
|
||||
const FLUSHCHUNK = Symbol('flushChunk');
|
||||
const ENCODING = Symbol('encoding');
|
||||
const DECODER = Symbol('decoder');
|
||||
const FLOWING = Symbol('flowing');
|
||||
const PAUSED = Symbol('paused');
|
||||
const RESUME = Symbol('resume');
|
||||
const BUFFER = Symbol('buffer');
|
||||
const PIPES = Symbol('pipes');
|
||||
const BUFFERLENGTH = Symbol('bufferLength');
|
||||
const BUFFERPUSH = Symbol('bufferPush');
|
||||
const BUFFERSHIFT = Symbol('bufferShift');
|
||||
const OBJECTMODE = Symbol('objectMode');
|
||||
// internal event when stream is destroyed
|
||||
const DESTROYED = Symbol('destroyed');
|
||||
// internal event when stream has an error
|
||||
const ERROR = Symbol('error');
|
||||
const EMITDATA = Symbol('emitData');
|
||||
const EMITEND = Symbol('emitEnd');
|
||||
const EMITEND2 = Symbol('emitEnd2');
|
||||
const ASYNC = Symbol('async');
|
||||
const ABORT = Symbol('abort');
|
||||
const ABORTED = Symbol('aborted');
|
||||
const SIGNAL = Symbol('signal');
|
||||
const DATALISTENERS = Symbol('dataListeners');
|
||||
const DISCARDED = Symbol('discarded');
|
||||
const defer = (fn) => Promise.resolve().then(fn);
|
||||
const nodefer = (fn) => fn();
|
||||
const isEndish = (ev) => ev === 'end' || ev === 'finish' || ev === 'prefinish';
|
||||
const isArrayBufferLike = (b) => b instanceof ArrayBuffer ||
|
||||
(!!b &&
|
||||
typeof b === 'object' &&
|
||||
b.constructor &&
|
||||
b.constructor.name === 'ArrayBuffer' &&
|
||||
b.byteLength >= 0);
|
||||
const isArrayBufferView = (b) => !Buffer.isBuffer(b) && ArrayBuffer.isView(b);
|
||||
/**
|
||||
* Internal class representing a pipe to a destination stream.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Pipe {
|
||||
src;
|
||||
dest;
|
||||
opts;
|
||||
ondrain;
|
||||
constructor(src, dest, opts) {
|
||||
this.src = src;
|
||||
this.dest = dest;
|
||||
this.opts = opts;
|
||||
this.ondrain = () => src[RESUME]();
|
||||
this.dest.on('drain', this.ondrain);
|
||||
}
|
||||
unpipe() {
|
||||
this.dest.removeListener('drain', this.ondrain);
|
||||
}
|
||||
// only here for the prototype
|
||||
/* c8 ignore start */
|
||||
proxyErrors(_er) { }
|
||||
/* c8 ignore stop */
|
||||
end() {
|
||||
this.unpipe();
|
||||
if (this.opts.end)
|
||||
this.dest.end();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Internal class representing a pipe to a destination stream where
|
||||
* errors are proxied.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PipeProxyErrors extends Pipe {
|
||||
unpipe() {
|
||||
this.src.removeListener('error', this.proxyErrors);
|
||||
super.unpipe();
|
||||
}
|
||||
constructor(src, dest, opts) {
|
||||
super(src, dest, opts);
|
||||
this.proxyErrors = er => dest.emit('error', er);
|
||||
src.on('error', this.proxyErrors);
|
||||
}
|
||||
}
|
||||
const isObjectModeOptions = (o) => !!o.objectMode;
|
||||
const isEncodingOptions = (o) => !o.objectMode && !!o.encoding && o.encoding !== 'buffer';
|
||||
/**
|
||||
* Main export, the Minipass class
|
||||
*
|
||||
* `RType` is the type of data emitted, defaults to Buffer
|
||||
*
|
||||
* `WType` is the type of data to be written, if RType is buffer or string,
|
||||
* then any {@link Minipass.ContiguousData} is allowed.
|
||||
*
|
||||
* `Events` is the set of event handler signatures that this object
|
||||
* will emit, see {@link Minipass.Events}
|
||||
*/
|
||||
class Minipass extends external_events_.EventEmitter {
|
||||
[FLOWING] = false;
|
||||
[PAUSED] = false;
|
||||
[PIPES] = [];
|
||||
[BUFFER] = [];
|
||||
[OBJECTMODE];
|
||||
[ENCODING];
|
||||
[ASYNC];
|
||||
[DECODER];
|
||||
[EOF] = false;
|
||||
[EMITTED_END] = false;
|
||||
[EMITTING_END] = false;
|
||||
[CLOSED] = false;
|
||||
[EMITTED_ERROR] = null;
|
||||
[BUFFERLENGTH] = 0;
|
||||
[DESTROYED] = false;
|
||||
[SIGNAL];
|
||||
[ABORTED] = false;
|
||||
[DATALISTENERS] = 0;
|
||||
[DISCARDED] = false;
|
||||
/**
|
||||
* true if the stream can be written
|
||||
*/
|
||||
writable = true;
|
||||
/**
|
||||
* true if the stream can be read
|
||||
*/
|
||||
readable = true;
|
||||
/**
|
||||
* If `RType` is Buffer, then options do not need to be provided.
|
||||
* Otherwise, an options object must be provided to specify either
|
||||
* {@link Minipass.SharedOptions.objectMode} or
|
||||
* {@link Minipass.SharedOptions.encoding}, as appropriate.
|
||||
*/
|
||||
constructor(...args) {
|
||||
const options = (args[0] ||
|
||||
{});
|
||||
super();
|
||||
if (options.objectMode && typeof options.encoding === 'string') {
|
||||
throw new TypeError('Encoding and objectMode may not be used together');
|
||||
}
|
||||
if (isObjectModeOptions(options)) {
|
||||
this[OBJECTMODE] = true;
|
||||
this[ENCODING] = null;
|
||||
}
|
||||
else if (isEncodingOptions(options)) {
|
||||
this[ENCODING] = options.encoding;
|
||||
this[OBJECTMODE] = false;
|
||||
}
|
||||
else {
|
||||
this[OBJECTMODE] = false;
|
||||
this[ENCODING] = null;
|
||||
}
|
||||
this[ASYNC] = !!options.async;
|
||||
this[DECODER] = this[ENCODING]
|
||||
? new external_string_decoder_.StringDecoder(this[ENCODING])
|
||||
: null;
|
||||
//@ts-ignore - private option for debugging and testing
|
||||
if (options && options.debugExposeBuffer === true) {
|
||||
Object.defineProperty(this, 'buffer', { get: () => this[BUFFER] });
|
||||
}
|
||||
//@ts-ignore - private option for debugging and testing
|
||||
if (options && options.debugExposePipes === true) {
|
||||
Object.defineProperty(this, 'pipes', { get: () => this[PIPES] });
|
||||
}
|
||||
const { signal } = options;
|
||||
if (signal) {
|
||||
this[SIGNAL] = signal;
|
||||
if (signal.aborted) {
|
||||
this[ABORT]();
|
||||
}
|
||||
else {
|
||||
signal.addEventListener('abort', () => this[ABORT]());
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The amount of data stored in the buffer waiting to be read.
|
||||
*
|
||||
* For Buffer strings, this will be the total byte length.
|
||||
* For string encoding streams, this will be the string character length,
|
||||
* according to JavaScript's `string.length` logic.
|
||||
* For objectMode streams, this is a count of the items waiting to be
|
||||
* emitted.
|
||||
*/
|
||||
get bufferLength() {
|
||||
return this[BUFFERLENGTH];
|
||||
}
|
||||
/**
|
||||
* The `BufferEncoding` currently in use, or `null`
|
||||
*/
|
||||
get encoding() {
|
||||
return this[ENCODING];
|
||||
}
|
||||
/**
|
||||
* @deprecated - This is a read only property
|
||||
*/
|
||||
set encoding(_enc) {
|
||||
throw new Error('Encoding must be set at instantiation time');
|
||||
}
|
||||
/**
|
||||
* @deprecated - Encoding may only be set at instantiation time
|
||||
*/
|
||||
setEncoding(_enc) {
|
||||
throw new Error('Encoding must be set at instantiation time');
|
||||
}
|
||||
/**
|
||||
* True if this is an objectMode stream
|
||||
*/
|
||||
get objectMode() {
|
||||
return this[OBJECTMODE];
|
||||
}
|
||||
/**
|
||||
* @deprecated - This is a read-only property
|
||||
*/
|
||||
set objectMode(_om) {
|
||||
throw new Error('objectMode must be set at instantiation time');
|
||||
}
|
||||
/**
|
||||
* true if this is an async stream
|
||||
*/
|
||||
get ['async']() {
|
||||
return this[ASYNC];
|
||||
}
|
||||
/**
|
||||
* Set to true to make this stream async.
|
||||
*
|
||||
* Once set, it cannot be unset, as this would potentially cause incorrect
|
||||
* behavior. Ie, a sync stream can be made async, but an async stream
|
||||
* cannot be safely made sync.
|
||||
*/
|
||||
set ['async'](a) {
|
||||
this[ASYNC] = this[ASYNC] || !!a;
|
||||
}
|
||||
// drop everything and get out of the flow completely
|
||||
[ABORT]() {
|
||||
this[ABORTED] = true;
|
||||
this.emit('abort', this[SIGNAL]?.reason);
|
||||
this.destroy(this[SIGNAL]?.reason);
|
||||
}
|
||||
/**
|
||||
* True if the stream has been aborted.
|
||||
*/
|
||||
get aborted() {
|
||||
return this[ABORTED];
|
||||
}
|
||||
/**
|
||||
* No-op setter. Stream aborted status is set via the AbortSignal provided
|
||||
* in the constructor options.
|
||||
*/
|
||||
set aborted(_) { }
|
||||
write(chunk, encoding, cb) {
|
||||
if (this[ABORTED])
|
||||
return false;
|
||||
if (this[EOF])
|
||||
throw new Error('write after end');
|
||||
if (this[DESTROYED]) {
|
||||
this.emit('error', Object.assign(new Error('Cannot call write after a stream was destroyed'), { code: 'ERR_STREAM_DESTROYED' }));
|
||||
return true;
|
||||
}
|
||||
if (typeof encoding === 'function') {
|
||||
cb = encoding;
|
||||
encoding = 'utf8';
|
||||
}
|
||||
if (!encoding)
|
||||
encoding = 'utf8';
|
||||
const fn = this[ASYNC] ? defer : nodefer;
|
||||
// convert array buffers and typed array views into buffers
|
||||
// at some point in the future, we may want to do the opposite!
|
||||
// leave strings and buffers as-is
|
||||
// anything is only allowed if in object mode, so throw
|
||||
if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) {
|
||||
if (isArrayBufferView(chunk)) {
|
||||
//@ts-ignore - sinful unsafe type changing
|
||||
chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
||||
}
|
||||
else if (isArrayBufferLike(chunk)) {
|
||||
//@ts-ignore - sinful unsafe type changing
|
||||
chunk = Buffer.from(chunk);
|
||||
}
|
||||
else if (typeof chunk !== 'string') {
|
||||
throw new Error('Non-contiguous data written to non-objectMode stream');
|
||||
}
|
||||
}
|
||||
// handle object mode up front, since it's simpler
|
||||
// this yields better performance, fewer checks later.
|
||||
if (this[OBJECTMODE]) {
|
||||
// maybe impossible?
|
||||
/* c8 ignore start */
|
||||
if (this[FLOWING] && this[BUFFERLENGTH] !== 0)
|
||||
this[FLUSH](true);
|
||||
/* c8 ignore stop */
|
||||
if (this[FLOWING])
|
||||
this.emit('data', chunk);
|
||||
else
|
||||
this[BUFFERPUSH](chunk);
|
||||
if (this[BUFFERLENGTH] !== 0)
|
||||
this.emit('readable');
|
||||
if (cb)
|
||||
fn(cb);
|
||||
return this[FLOWING];
|
||||
}
|
||||
// at this point the chunk is a buffer or string
|
||||
// don't buffer it up or send it to the decoder
|
||||
if (!chunk.length) {
|
||||
if (this[BUFFERLENGTH] !== 0)
|
||||
this.emit('readable');
|
||||
if (cb)
|
||||
fn(cb);
|
||||
return this[FLOWING];
|
||||
}
|
||||
// fast-path writing strings of same encoding to a stream with
|
||||
// an empty buffer, skipping the buffer/decoder dance
|
||||
if (typeof chunk === 'string' &&
|
||||
// unless it is a string already ready for us to use
|
||||
!(encoding === this[ENCODING] && !this[DECODER]?.lastNeed)) {
|
||||
//@ts-ignore - sinful unsafe type change
|
||||
chunk = Buffer.from(chunk, encoding);
|
||||
}
|
||||
if (Buffer.isBuffer(chunk) && this[ENCODING]) {
|
||||
//@ts-ignore - sinful unsafe type change
|
||||
chunk = this[DECODER].write(chunk);
|
||||
}
|
||||
// Note: flushing CAN potentially switch us into not-flowing mode
|
||||
if (this[FLOWING] && this[BUFFERLENGTH] !== 0)
|
||||
this[FLUSH](true);
|
||||
if (this[FLOWING])
|
||||
this.emit('data', chunk);
|
||||
else
|
||||
this[BUFFERPUSH](chunk);
|
||||
if (this[BUFFERLENGTH] !== 0)
|
||||
this.emit('readable');
|
||||
if (cb)
|
||||
fn(cb);
|
||||
return this[FLOWING];
|
||||
}
|
||||
/**
|
||||
* Low-level explicit read method.
|
||||
*
|
||||
* In objectMode, the argument is ignored, and one item is returned if
|
||||
* available.
|
||||
*
|
||||
* `n` is the number of bytes (or in the case of encoding streams,
|
||||
* characters) to consume. If `n` is not provided, then the entire buffer
|
||||
* is returned, or `null` is returned if no data is available.
|
||||
*
|
||||
* If `n` is greater that the amount of data in the internal buffer,
|
||||
* then `null` is returned.
|
||||
*/
|
||||
read(n) {
|
||||
if (this[DESTROYED])
|
||||
return null;
|
||||
this[DISCARDED] = false;
|
||||
if (this[BUFFERLENGTH] === 0 ||
|
||||
n === 0 ||
|
||||
(n && n > this[BUFFERLENGTH])) {
|
||||
this[MAYBE_EMIT_END]();
|
||||
return null;
|
||||
}
|
||||
if (this[OBJECTMODE])
|
||||
n = null;
|
||||
if (this[BUFFER].length > 1 && !this[OBJECTMODE]) {
|
||||
// not object mode, so if we have an encoding, then RType is string
|
||||
// otherwise, must be Buffer
|
||||
this[BUFFER] = [
|
||||
(this[ENCODING]
|
||||
? this[BUFFER].join('')
|
||||
: Buffer.concat(this[BUFFER], this[BUFFERLENGTH])),
|
||||
];
|
||||
}
|
||||
const ret = this[READ](n || null, this[BUFFER][0]);
|
||||
this[MAYBE_EMIT_END]();
|
||||
return ret;
|
||||
}
|
||||
[READ](n, chunk) {
|
||||
if (this[OBJECTMODE])
|
||||
this[BUFFERSHIFT]();
|
||||
else {
|
||||
const c = chunk;
|
||||
if (n === c.length || n === null)
|
||||
this[BUFFERSHIFT]();
|
||||
else if (typeof c === 'string') {
|
||||
this[BUFFER][0] = c.slice(n);
|
||||
chunk = c.slice(0, n);
|
||||
this[BUFFERLENGTH] -= n;
|
||||
}
|
||||
else {
|
||||
this[BUFFER][0] = c.subarray(n);
|
||||
chunk = c.subarray(0, n);
|
||||
this[BUFFERLENGTH] -= n;
|
||||
}
|
||||
}
|
||||
this.emit('data', chunk);
|
||||
if (!this[BUFFER].length && !this[EOF])
|
||||
this.emit('drain');
|
||||
return chunk;
|
||||
}
|
||||
end(chunk, encoding, cb) {
|
||||
if (typeof chunk === 'function') {
|
||||
cb = chunk;
|
||||
chunk = undefined;
|
||||
}
|
||||
if (typeof encoding === 'function') {
|
||||
cb = encoding;
|
||||
encoding = 'utf8';
|
||||
}
|
||||
if (chunk !== undefined)
|
||||
this.write(chunk, encoding);
|
||||
if (cb)
|
||||
this.once('end', cb);
|
||||
this[EOF] = true;
|
||||
this.writable = false;
|
||||
// if we haven't written anything, then go ahead and emit,
|
||||
// even if we're not reading.
|
||||
// we'll re-emit if a new 'end' listener is added anyway.
|
||||
// This makes MP more suitable to write-only use cases.
|
||||
if (this[FLOWING] || !this[PAUSED])
|
||||
this[MAYBE_EMIT_END]();
|
||||
return this;
|
||||
}
|
||||
// don't let the internal resume be overwritten
|
||||
[RESUME]() {
|
||||
if (this[DESTROYED])
|
||||
return;
|
||||
if (!this[DATALISTENERS] && !this[PIPES].length) {
|
||||
this[DISCARDED] = true;
|
||||
}
|
||||
this[PAUSED] = false;
|
||||
this[FLOWING] = true;
|
||||
this.emit('resume');
|
||||
if (this[BUFFER].length)
|
||||
this[FLUSH]();
|
||||
else if (this[EOF])
|
||||
this[MAYBE_EMIT_END]();
|
||||
else
|
||||
this.emit('drain');
|
||||
}
|
||||
/**
|
||||
* Resume the stream if it is currently in a paused state
|
||||
*
|
||||
* If called when there are no pipe destinations or `data` event listeners,
|
||||
* this will place the stream in a "discarded" state, where all data will
|
||||
* be thrown away. The discarded state is removed if a pipe destination or
|
||||
* data handler is added, if pause() is called, or if any synchronous or
|
||||
* asynchronous iteration is started.
|
||||
*/
|
||||
resume() {
|
||||
return this[RESUME]();
|
||||
}
|
||||
/**
|
||||
* Pause the stream
|
||||
*/
|
||||
pause() {
|
||||
this[FLOWING] = false;
|
||||
this[PAUSED] = true;
|
||||
this[DISCARDED] = false;
|
||||
}
|
||||
/**
|
||||
* true if the stream has been forcibly destroyed
|
||||
*/
|
||||
get destroyed() {
|
||||
return this[DESTROYED];
|
||||
}
|
||||
/**
|
||||
* true if the stream is currently in a flowing state, meaning that
|
||||
* any writes will be immediately emitted.
|
||||
*/
|
||||
get flowing() {
|
||||
return this[FLOWING];
|
||||
}
|
||||
/**
|
||||
* true if the stream is currently in a paused state
|
||||
*/
|
||||
get paused() {
|
||||
return this[PAUSED];
|
||||
}
|
||||
[BUFFERPUSH](chunk) {
|
||||
if (this[OBJECTMODE])
|
||||
this[BUFFERLENGTH] += 1;
|
||||
else
|
||||
this[BUFFERLENGTH] += chunk.length;
|
||||
this[BUFFER].push(chunk);
|
||||
}
|
||||
[BUFFERSHIFT]() {
|
||||
if (this[OBJECTMODE])
|
||||
this[BUFFERLENGTH] -= 1;
|
||||
else
|
||||
this[BUFFERLENGTH] -= this[BUFFER][0].length;
|
||||
return this[BUFFER].shift();
|
||||
}
|
||||
[FLUSH](noDrain = false) {
|
||||
do { } while (this[FLUSHCHUNK](this[BUFFERSHIFT]()) &&
|
||||
this[BUFFER].length);
|
||||
if (!noDrain && !this[BUFFER].length && !this[EOF])
|
||||
this.emit('drain');
|
||||
}
|
||||
[FLUSHCHUNK](chunk) {
|
||||
this.emit('data', chunk);
|
||||
return this[FLOWING];
|
||||
}
|
||||
/**
|
||||
* Pipe all data emitted by this stream into the destination provided.
|
||||
*
|
||||
* Triggers the flow of data.
|
||||
*/
|
||||
pipe(dest, opts) {
|
||||
if (this[DESTROYED])
|
||||
return dest;
|
||||
this[DISCARDED] = false;
|
||||
const ended = this[EMITTED_END];
|
||||
opts = opts || {};
|
||||
if (dest === proc.stdout || dest === proc.stderr)
|
||||
opts.end = false;
|
||||
else
|
||||
opts.end = opts.end !== false;
|
||||
opts.proxyErrors = !!opts.proxyErrors;
|
||||
// piping an ended stream ends immediately
|
||||
if (ended) {
|
||||
if (opts.end)
|
||||
dest.end();
|
||||
}
|
||||
else {
|
||||
// "as" here just ignores the WType, which pipes don't care about,
|
||||
// since they're only consuming from us, and writing to the dest
|
||||
this[PIPES].push(!opts.proxyErrors
|
||||
? new Pipe(this, dest, opts)
|
||||
: new PipeProxyErrors(this, dest, opts));
|
||||
if (this[ASYNC])
|
||||
defer(() => this[RESUME]());
|
||||
else
|
||||
this[RESUME]();
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
/**
|
||||
* Fully unhook a piped destination stream.
|
||||
*
|
||||
* If the destination stream was the only consumer of this stream (ie,
|
||||
* there are no other piped destinations or `'data'` event listeners)
|
||||
* then the flow of data will stop until there is another consumer or
|
||||
* {@link Minipass#resume} is explicitly called.
|
||||
*/
|
||||
unpipe(dest) {
|
||||
const p = this[PIPES].find(p => p.dest === dest);
|
||||
if (p) {
|
||||
if (this[PIPES].length === 1) {
|
||||
if (this[FLOWING] && this[DATALISTENERS] === 0) {
|
||||
this[FLOWING] = false;
|
||||
}
|
||||
this[PIPES] = [];
|
||||
}
|
||||
else
|
||||
this[PIPES].splice(this[PIPES].indexOf(p), 1);
|
||||
p.unpipe();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Alias for {@link Minipass#on}
|
||||
*/
|
||||
addListener(ev, handler) {
|
||||
return this.on(ev, handler);
|
||||
}
|
||||
/**
|
||||
* Mostly identical to `EventEmitter.on`, with the following
|
||||
* behavior differences to prevent data loss and unnecessary hangs:
|
||||
*
|
||||
* - Adding a 'data' event handler will trigger the flow of data
|
||||
*
|
||||
* - Adding a 'readable' event handler when there is data waiting to be read
|
||||
* will cause 'readable' to be emitted immediately.
|
||||
*
|
||||
* - Adding an 'endish' event handler ('end', 'finish', etc.) which has
|
||||
* already passed will cause the event to be emitted immediately and all
|
||||
* handlers removed.
|
||||
*
|
||||
* - Adding an 'error' event handler after an error has been emitted will
|
||||
* cause the event to be re-emitted immediately with the error previously
|
||||
* raised.
|
||||
*/
|
||||
on(ev, handler) {
|
||||
const ret = super.on(ev, handler);
|
||||
if (ev === 'data') {
|
||||
this[DISCARDED] = false;
|
||||
this[DATALISTENERS]++;
|
||||
if (!this[PIPES].length && !this[FLOWING]) {
|
||||
this[RESUME]();
|
||||
}
|
||||
}
|
||||
else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) {
|
||||
super.emit('readable');
|
||||
}
|
||||
else if (isEndish(ev) && this[EMITTED_END]) {
|
||||
super.emit(ev);
|
||||
this.removeAllListeners(ev);
|
||||
}
|
||||
else if (ev === 'error' && this[EMITTED_ERROR]) {
|
||||
const h = handler;
|
||||
if (this[ASYNC])
|
||||
defer(() => h.call(this, this[EMITTED_ERROR]));
|
||||
else
|
||||
h.call(this, this[EMITTED_ERROR]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Alias for {@link Minipass#off}
|
||||
*/
|
||||
removeListener(ev, handler) {
|
||||
return this.off(ev, handler);
|
||||
}
|
||||
/**
|
||||
* Mostly identical to `EventEmitter.off`
|
||||
*
|
||||
* If a 'data' event handler is removed, and it was the last consumer
|
||||
* (ie, there are no pipe destinations or other 'data' event listeners),
|
||||
* then the flow of data will stop until there is another consumer or
|
||||
* {@link Minipass#resume} is explicitly called.
|
||||
*/
|
||||
off(ev, handler) {
|
||||
const ret = super.off(ev, handler);
|
||||
// if we previously had listeners, and now we don't, and we don't
|
||||
// have any pipes, then stop the flow, unless it's been explicitly
|
||||
// put in a discarded flowing state via stream.resume().
|
||||
if (ev === 'data') {
|
||||
this[DATALISTENERS] = this.listeners('data').length;
|
||||
if (this[DATALISTENERS] === 0 &&
|
||||
!this[DISCARDED] &&
|
||||
!this[PIPES].length) {
|
||||
this[FLOWING] = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Mostly identical to `EventEmitter.removeAllListeners`
|
||||
*
|
||||
* If all 'data' event handlers are removed, and they were the last consumer
|
||||
* (ie, there are no pipe destinations), then the flow of data will stop
|
||||
* until there is another consumer or {@link Minipass#resume} is explicitly
|
||||
* called.
|
||||
*/
|
||||
removeAllListeners(ev) {
|
||||
const ret = super.removeAllListeners(ev);
|
||||
if (ev === 'data' || ev === undefined) {
|
||||
this[DATALISTENERS] = 0;
|
||||
if (!this[DISCARDED] && !this[PIPES].length) {
|
||||
this[FLOWING] = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* true if the 'end' event has been emitted
|
||||
*/
|
||||
get emittedEnd() {
|
||||
return this[EMITTED_END];
|
||||
}
|
||||
[MAYBE_EMIT_END]() {
|
||||
if (!this[EMITTING_END] &&
|
||||
!this[EMITTED_END] &&
|
||||
!this[DESTROYED] &&
|
||||
this[BUFFER].length === 0 &&
|
||||
this[EOF]) {
|
||||
this[EMITTING_END] = true;
|
||||
this.emit('end');
|
||||
this.emit('prefinish');
|
||||
this.emit('finish');
|
||||
if (this[CLOSED])
|
||||
this.emit('close');
|
||||
this[EMITTING_END] = false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Mostly identical to `EventEmitter.emit`, with the following
|
||||
* behavior differences to prevent data loss and unnecessary hangs:
|
||||
*
|
||||
* If the stream has been destroyed, and the event is something other
|
||||
* than 'close' or 'error', then `false` is returned and no handlers
|
||||
* are called.
|
||||
*
|
||||
* If the event is 'end', and has already been emitted, then the event
|
||||
* is ignored. If the stream is in a paused or non-flowing state, then
|
||||
* the event will be deferred until data flow resumes. If the stream is
|
||||
* async, then handlers will be called on the next tick rather than
|
||||
* immediately.
|
||||
*
|
||||
* If the event is 'close', and 'end' has not yet been emitted, then
|
||||
* the event will be deferred until after 'end' is emitted.
|
||||
*
|
||||
* If the event is 'error', and an AbortSignal was provided for the stream,
|
||||
* and there are no listeners, then the event is ignored, matching the
|
||||
* behavior of node core streams in the presense of an AbortSignal.
|
||||
*
|
||||
* If the event is 'finish' or 'prefinish', then all listeners will be
|
||||
* removed after emitting the event, to prevent double-firing.
|
||||
*/
|
||||
emit(ev, ...args) {
|
||||
const data = args[0];
|
||||
// error and close are only events allowed after calling destroy()
|
||||
if (ev !== 'error' &&
|
||||
ev !== 'close' &&
|
||||
ev !== DESTROYED &&
|
||||
this[DESTROYED]) {
|
||||
return false;
|
||||
}
|
||||
else if (ev === 'data') {
|
||||
return !this[OBJECTMODE] && !data
|
||||
? false
|
||||
: this[ASYNC]
|
||||
? (defer(() => this[EMITDATA](data)), true)
|
||||
: this[EMITDATA](data);
|
||||
}
|
||||
else if (ev === 'end') {
|
||||
return this[EMITEND]();
|
||||
}
|
||||
else if (ev === 'close') {
|
||||
this[CLOSED] = true;
|
||||
// don't emit close before 'end' and 'finish'
|
||||
if (!this[EMITTED_END] && !this[DESTROYED])
|
||||
return false;
|
||||
const ret = super.emit('close');
|
||||
this.removeAllListeners('close');
|
||||
return ret;
|
||||
}
|
||||
else if (ev === 'error') {
|
||||
this[EMITTED_ERROR] = data;
|
||||
super.emit(ERROR, data);
|
||||
const ret = !this[SIGNAL] || this.listeners('error').length
|
||||
? super.emit('error', data)
|
||||
: false;
|
||||
this[MAYBE_EMIT_END]();
|
||||
return ret;
|
||||
}
|
||||
else if (ev === 'resume') {
|
||||
const ret = super.emit('resume');
|
||||
this[MAYBE_EMIT_END]();
|
||||
return ret;
|
||||
}
|
||||
else if (ev === 'finish' || ev === 'prefinish') {
|
||||
const ret = super.emit(ev);
|
||||
this.removeAllListeners(ev);
|
||||
return ret;
|
||||
}
|
||||
// Some other unknown event
|
||||
const ret = super.emit(ev, ...args);
|
||||
this[MAYBE_EMIT_END]();
|
||||
return ret;
|
||||
}
|
||||
[EMITDATA](data) {
|
||||
for (const p of this[PIPES]) {
|
||||
if (p.dest.write(data) === false)
|
||||
this.pause();
|
||||
}
|
||||
const ret = this[DISCARDED] ? false : super.emit('data', data);
|
||||
this[MAYBE_EMIT_END]();
|
||||
return ret;
|
||||
}
|
||||
[EMITEND]() {
|
||||
if (this[EMITTED_END])
|
||||
return false;
|
||||
this[EMITTED_END] = true;
|
||||
this.readable = false;
|
||||
return this[ASYNC]
|
||||
? (defer(() => this[EMITEND2]()), true)
|
||||
: this[EMITEND2]();
|
||||
}
|
||||
[EMITEND2]() {
|
||||
if (this[DECODER]) {
|
||||
const data = this[DECODER].end();
|
||||
if (data) {
|
||||
for (const p of this[PIPES]) {
|
||||
p.dest.write(data);
|
||||
}
|
||||
if (!this[DISCARDED])
|
||||
super.emit('data', data);
|
||||
}
|
||||
}
|
||||
for (const p of this[PIPES]) {
|
||||
p.end();
|
||||
}
|
||||
const ret = super.emit('end');
|
||||
this.removeAllListeners('end');
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Return a Promise that resolves to an array of all emitted data once
|
||||
* the stream ends.
|
||||
*/
|
||||
async collect() {
|
||||
const buf = Object.assign([], {
|
||||
dataLength: 0,
|
||||
});
|
||||
if (!this[OBJECTMODE])
|
||||
buf.dataLength = 0;
|
||||
// set the promise first, in case an error is raised
|
||||
// by triggering the flow here.
|
||||
const p = this.promise();
|
||||
this.on('data', c => {
|
||||
buf.push(c);
|
||||
if (!this[OBJECTMODE])
|
||||
buf.dataLength += c.length;
|
||||
});
|
||||
await p;
|
||||
return buf;
|
||||
}
|
||||
/**
|
||||
* Return a Promise that resolves to the concatenation of all emitted data
|
||||
* once the stream ends.
|
||||
*
|
||||
* Not allowed on objectMode streams.
|
||||
*/
|
||||
async concat() {
|
||||
if (this[OBJECTMODE]) {
|
||||
throw new Error('cannot concat in objectMode');
|
||||
}
|
||||
const buf = await this.collect();
|
||||
return (this[ENCODING]
|
||||
? buf.join('')
|
||||
: Buffer.concat(buf, buf.dataLength));
|
||||
}
|
||||
/**
|
||||
* Return a void Promise that resolves once the stream ends.
|
||||
*/
|
||||
async promise() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.on(DESTROYED, () => reject(new Error('stream destroyed')));
|
||||
this.on('error', er => reject(er));
|
||||
this.on('end', () => resolve());
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Asynchronous `for await of` iteration.
|
||||
*
|
||||
* This will continue emitting all chunks until the stream terminates.
|
||||
*/
|
||||
[Symbol.asyncIterator]() {
|
||||
// set this up front, in case the consumer doesn't call next()
|
||||
// right away.
|
||||
this[DISCARDED] = false;
|
||||
let stopped = false;
|
||||
const stop = async () => {
|
||||
this.pause();
|
||||
stopped = true;
|
||||
return { value: undefined, done: true };
|
||||
};
|
||||
const next = () => {
|
||||
if (stopped)
|
||||
return stop();
|
||||
const res = this.read();
|
||||
if (res !== null)
|
||||
return Promise.resolve({ done: false, value: res });
|
||||
if (this[EOF])
|
||||
return stop();
|
||||
let resolve;
|
||||
let reject;
|
||||
const onerr = (er) => {
|
||||
this.off('data', ondata);
|
||||
this.off('end', onend);
|
||||
this.off(DESTROYED, ondestroy);
|
||||
stop();
|
||||
reject(er);
|
||||
};
|
||||
const ondata = (value) => {
|
||||
this.off('error', onerr);
|
||||
this.off('end', onend);
|
||||
this.off(DESTROYED, ondestroy);
|
||||
this.pause();
|
||||
resolve({ value, done: !!this[EOF] });
|
||||
};
|
||||
const onend = () => {
|
||||
this.off('error', onerr);
|
||||
this.off('data', ondata);
|
||||
this.off(DESTROYED, ondestroy);
|
||||
stop();
|
||||
resolve({ done: true, value: undefined });
|
||||
};
|
||||
const ondestroy = () => onerr(new Error('stream destroyed'));
|
||||
return new Promise((res, rej) => {
|
||||
reject = rej;
|
||||
resolve = res;
|
||||
this.once(DESTROYED, ondestroy);
|
||||
this.once('error', onerr);
|
||||
this.once('end', onend);
|
||||
this.once('data', ondata);
|
||||
});
|
||||
};
|
||||
return {
|
||||
next,
|
||||
throw: stop,
|
||||
return: stop,
|
||||
[Symbol.asyncIterator]() {
|
||||
return this;
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Synchronous `for of` iteration.
|
||||
*
|
||||
* The iteration will terminate when the internal buffer runs out, even
|
||||
* if the stream has not yet terminated.
|
||||
*/
|
||||
[Symbol.iterator]() {
|
||||
// set this up front, in case the consumer doesn't call next()
|
||||
// right away.
|
||||
this[DISCARDED] = false;
|
||||
let stopped = false;
|
||||
const stop = () => {
|
||||
this.pause();
|
||||
this.off(ERROR, stop);
|
||||
this.off(DESTROYED, stop);
|
||||
this.off('end', stop);
|
||||
stopped = true;
|
||||
return { done: true, value: undefined };
|
||||
};
|
||||
const next = () => {
|
||||
if (stopped)
|
||||
return stop();
|
||||
const value = this.read();
|
||||
return value === null ? stop() : { done: false, value };
|
||||
};
|
||||
this.once('end', stop);
|
||||
this.once(ERROR, stop);
|
||||
this.once(DESTROYED, stop);
|
||||
return {
|
||||
next,
|
||||
throw: stop,
|
||||
return: stop,
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Destroy a stream, preventing it from being used for any further purpose.
|
||||
*
|
||||
* If the stream has a `close()` method, then it will be called on
|
||||
* destruction.
|
||||
*
|
||||
* After destruction, any attempt to write data, read data, or emit most
|
||||
* events will be ignored.
|
||||
*
|
||||
* If an error argument is provided, then it will be emitted in an
|
||||
* 'error' event.
|
||||
*/
|
||||
destroy(er) {
|
||||
if (this[DESTROYED]) {
|
||||
if (er)
|
||||
this.emit('error', er);
|
||||
else
|
||||
this.emit(DESTROYED);
|
||||
return this;
|
||||
}
|
||||
this[DESTROYED] = true;
|
||||
this[DISCARDED] = true;
|
||||
// throw away all buffered data, it's never coming out
|
||||
this[BUFFER].length = 0;
|
||||
this[BUFFERLENGTH] = 0;
|
||||
const wc = this;
|
||||
if (typeof wc.close === 'function' && !this[CLOSED])
|
||||
wc.close();
|
||||
if (er)
|
||||
this.emit('error', er);
|
||||
// if no error to emit, still reject pending promises
|
||||
else
|
||||
this.emit(DESTROYED);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Alias for {@link isStream}
|
||||
*
|
||||
* Former export location, maintained for backwards compatibility.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
static get isStream() {
|
||||
return isStream;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/path-scurry/dist/mjs/index.js
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const realpathSync = external_fs_.realpathSync.native;
|
||||
// TODO: test perf of fs/promises realpath vs realpathCB,
|
||||
// since the promises one uses realpath.native
|
||||
|
||||
|
||||
const defaultFS = {
|
||||
lstatSync: external_fs_.lstatSync,
|
||||
readdir: external_fs_.readdir,
|
||||
readdirSync: external_fs_.readdirSync,
|
||||
readlinkSync: external_fs_.readlinkSync,
|
||||
realpathSync,
|
||||
promises: {
|
||||
lstat: promises_namespaceObject.lstat,
|
||||
readdir: promises_namespaceObject.readdir,
|
||||
readlink: promises_namespaceObject.readlink,
|
||||
realpath: promises_namespaceObject.realpath,
|
||||
},
|
||||
};
|
||||
// if they just gave us require('fs') then use our default
|
||||
const fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === external_fs_namespaceObject
|
||||
? defaultFS
|
||||
: {
|
||||
...defaultFS,
|
||||
...fsOption,
|
||||
promises: {
|
||||
...defaultFS.promises,
|
||||
...(fsOption.promises || {}),
|
||||
},
|
||||
};
|
||||
// turn something like //?/c:/ into c:\
|
||||
const uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
|
||||
const uncToDrive = (rootPath) => rootPath.replace(/\//g, '\\').replace(uncDriveRegexp, '$1\\');
|
||||
// windows paths are separated by either / or \
|
||||
const eitherSep = /[\\\/]/;
|
||||
const UNKNOWN = 0; // may not even exist, for all we know
|
||||
const IFIFO = 0b0001;
|
||||
const IFCHR = 0b0010;
|
||||
const IFDIR = 0b0100;
|
||||
const IFBLK = 0b0110;
|
||||
const IFREG = 0b1000;
|
||||
const IFLNK = 0b1010;
|
||||
const IFSOCK = 0b1100;
|
||||
const IFMT = 0b1111;
|
||||
// mask to unset low 4 bits
|
||||
const IFMT_UNKNOWN = ~IFMT;
|
||||
// set after successfully calling readdir() and getting entries.
|
||||
const READDIR_CALLED = 16;
|
||||
// set after a successful lstat()
|
||||
const LSTAT_CALLED = 32;
|
||||
// set if an entry (or one of its parents) is definitely not a dir
|
||||
const ENOTDIR = 64;
|
||||
// set if an entry (or one of its parents) does not exist
|
||||
// (can also be set on lstat errors like EACCES or ENAMETOOLONG)
|
||||
const ENOENT = 128;
|
||||
// cannot have child entries -- also verify &IFMT is either IFDIR or IFLNK
|
||||
// set if we fail to readlink
|
||||
const ENOREADLINK = 256;
|
||||
// set if we know realpath() will fail
|
||||
const ENOREALPATH = 512;
|
||||
const ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
|
||||
const TYPEMASK = 1023;
|
||||
const entToType = (s) => s.isFile()
|
||||
? IFREG
|
||||
: s.isDirectory()
|
||||
? IFDIR
|
||||
: s.isSymbolicLink()
|
||||
? IFLNK
|
||||
: s.isCharacterDevice()
|
||||
? IFCHR
|
||||
: s.isBlockDevice()
|
||||
? IFBLK
|
||||
: s.isSocket()
|
||||
? IFSOCK
|
||||
: s.isFIFO()
|
||||
? IFIFO
|
||||
: UNKNOWN;
|
||||
// normalize unicode path names
|
||||
const normalizeCache = new Map();
|
||||
const normalize = (s) => {
|
||||
const c = normalizeCache.get(s);
|
||||
if (c)
|
||||
return c;
|
||||
const n = s.normalize('NFKD');
|
||||
normalizeCache.set(s, n);
|
||||
return n;
|
||||
};
|
||||
const normalizeNocaseCache = new Map();
|
||||
const normalizeNocase = (s) => {
|
||||
const c = normalizeNocaseCache.get(s);
|
||||
if (c)
|
||||
return c;
|
||||
const n = normalize(s.toLowerCase());
|
||||
normalizeNocaseCache.set(s, n);
|
||||
return n;
|
||||
};
|
||||
/**
|
||||
* An LRUCache for storing resolved path strings or Path objects.
|
||||
* @internal
|
||||
*/
|
||||
class ResolveCache extends LRUCache {
|
||||
constructor() {
|
||||
super({ max: 256 });
|
||||
}
|
||||
}
|
||||
// In order to prevent blowing out the js heap by allocating hundreds of
|
||||
// thousands of Path entries when walking extremely large trees, the "children"
|
||||
// in this tree are represented by storing an array of Path entries in an
|
||||
// LRUCache, indexed by the parent. At any time, Path.children() may return an
|
||||
// empty array, indicating that it doesn't know about any of its children, and
|
||||
// thus has to rebuild that cache. This is fine, it just means that we don't
|
||||
// benefit as much from having the cached entries, but huge directory walks
|
||||
// don't blow out the stack, and smaller ones are still as fast as possible.
|
||||
//
|
||||
//It does impose some complexity when building up the readdir data, because we
|
||||
//need to pass a reference to the children array that we started with.
|
||||
/**
|
||||
* an LRUCache for storing child entries.
|
||||
* @internal
|
||||
*/
|
||||
class ChildrenCache extends LRUCache {
|
||||
constructor(maxSize = 16 * 1024) {
|
||||
super({
|
||||
maxSize,
|
||||
// parent + children
|
||||
sizeCalculation: a => a.length + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
const setAsCwd = Symbol('PathScurry setAsCwd');
|
||||
/**
|
||||
* Path objects are sort of like a super-powered
|
||||
* {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}
|
||||
*
|
||||
* Each one represents a single filesystem entry on disk, which may or may not
|
||||
* exist. It includes methods for reading various types of information via
|
||||
* lstat, readlink, and readdir, and caches all information to the greatest
|
||||
* degree possible.
|
||||
*
|
||||
* Note that fs operations that would normally throw will instead return an
|
||||
* "empty" value. This is in order to prevent excessive overhead from error
|
||||
* stack traces.
|
||||
*/
|
||||
class PathBase {
|
||||
/**
|
||||
* the basename of this path
|
||||
*
|
||||
* **Important**: *always* test the path name against any test string
|
||||
* usingthe {@link isNamed} method, and not by directly comparing this
|
||||
* string. Otherwise, unicode path strings that the system sees as identical
|
||||
* will not be properly treated as the same path, leading to incorrect
|
||||
* behavior and possible security issues.
|
||||
*/
|
||||
name;
|
||||
/**
|
||||
* the Path entry corresponding to the path root.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
root;
|
||||
/**
|
||||
* All roots found within the current PathScurry family
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
roots;
|
||||
/**
|
||||
* a reference to the parent path, or undefined in the case of root entries
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
parent;
|
||||
/**
|
||||
* boolean indicating whether paths are compared case-insensitively
|
||||
* @internal
|
||||
*/
|
||||
nocase;
|
||||
// potential default fs override
|
||||
#fs;
|
||||
// Stats fields
|
||||
#dev;
|
||||
get dev() {
|
||||
return this.#dev;
|
||||
}
|
||||
#mode;
|
||||
get mode() {
|
||||
return this.#mode;
|
||||
}
|
||||
#nlink;
|
||||
get nlink() {
|
||||
return this.#nlink;
|
||||
}
|
||||
#uid;
|
||||
get uid() {
|
||||
return this.#uid;
|
||||
}
|
||||
#gid;
|
||||
get gid() {
|
||||
return this.#gid;
|
||||
}
|
||||
#rdev;
|
||||
get rdev() {
|
||||
return this.#rdev;
|
||||
}
|
||||
#blksize;
|
||||
get blksize() {
|
||||
return this.#blksize;
|
||||
}
|
||||
#ino;
|
||||
get ino() {
|
||||
return this.#ino;
|
||||
}
|
||||
#size;
|
||||
get size() {
|
||||
return this.#size;
|
||||
}
|
||||
#blocks;
|
||||
get blocks() {
|
||||
return this.#blocks;
|
||||
}
|
||||
#atimeMs;
|
||||
get atimeMs() {
|
||||
return this.#atimeMs;
|
||||
}
|
||||
#mtimeMs;
|
||||
get mtimeMs() {
|
||||
return this.#mtimeMs;
|
||||
}
|
||||
#ctimeMs;
|
||||
get ctimeMs() {
|
||||
return this.#ctimeMs;
|
||||
}
|
||||
#birthtimeMs;
|
||||
get birthtimeMs() {
|
||||
return this.#birthtimeMs;
|
||||
}
|
||||
#atime;
|
||||
get atime() {
|
||||
return this.#atime;
|
||||
}
|
||||
#mtime;
|
||||
get mtime() {
|
||||
return this.#mtime;
|
||||
}
|
||||
#ctime;
|
||||
get ctime() {
|
||||
return this.#ctime;
|
||||
}
|
||||
#birthtime;
|
||||
get birthtime() {
|
||||
return this.#birthtime;
|
||||
}
|
||||
#matchName;
|
||||
#depth;
|
||||
#fullpath;
|
||||
#fullpathPosix;
|
||||
#relative;
|
||||
#relativePosix;
|
||||
#type;
|
||||
#children;
|
||||
#linkTarget;
|
||||
#realpath;
|
||||
/**
|
||||
* This property is for compatibility with the Dirent class as of
|
||||
* Node v20, where Dirent['path'] refers to the path of the directory
|
||||
* that was passed to readdir. So, somewhat counterintuitively, this
|
||||
* property refers to the *parent* path, not the path object itself.
|
||||
* For root entries, it's the path to the entry itself.
|
||||
*/
|
||||
get path() {
|
||||
return (this.parent || this).fullpath();
|
||||
}
|
||||
/**
|
||||
* Do not create new Path objects directly. They should always be accessed
|
||||
* via the PathScurry class or other methods on the Path class.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
||||
this.name = name;
|
||||
this.#matchName = nocase ? normalizeNocase(name) : normalize(name);
|
||||
this.#type = type & TYPEMASK;
|
||||
this.nocase = nocase;
|
||||
this.roots = roots;
|
||||
this.root = root || this;
|
||||
this.#children = children;
|
||||
this.#fullpath = opts.fullpath;
|
||||
this.#relative = opts.relative;
|
||||
this.#relativePosix = opts.relativePosix;
|
||||
this.parent = opts.parent;
|
||||
if (this.parent) {
|
||||
this.#fs = this.parent.#fs;
|
||||
}
|
||||
else {
|
||||
this.#fs = fsFromOption(opts.fs);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the depth of the Path object from its root.
|
||||
*
|
||||
* For example, a path at `/foo/bar` would have a depth of 2.
|
||||
*/
|
||||
depth() {
|
||||
if (this.#depth !== undefined)
|
||||
return this.#depth;
|
||||
if (!this.parent)
|
||||
return (this.#depth = 0);
|
||||
return (this.#depth = this.parent.depth() + 1);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
childrenCache() {
|
||||
return this.#children;
|
||||
}
|
||||
/**
|
||||
* Get the Path object referenced by the string path, resolved from this Path
|
||||
*/
|
||||
resolve(path) {
|
||||
if (!path) {
|
||||
return this;
|
||||
}
|
||||
const rootPath = this.getRootString(path);
|
||||
const dir = path.substring(rootPath.length);
|
||||
const dirParts = dir.split(this.splitSep);
|
||||
const result = rootPath
|
||||
? this.getRoot(rootPath).#resolveParts(dirParts)
|
||||
: this.#resolveParts(dirParts);
|
||||
return result;
|
||||
}
|
||||
#resolveParts(dirParts) {
|
||||
let p = this;
|
||||
for (const part of dirParts) {
|
||||
p = p.child(part);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
/**
|
||||
* Returns the cached children Path objects, if still available. If they
|
||||
* have fallen out of the cache, then returns an empty array, and resets the
|
||||
* READDIR_CALLED bit, so that future calls to readdir() will require an fs
|
||||
* lookup.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
children() {
|
||||
const cached = this.#children.get(this);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const children = Object.assign([], { provisional: 0 });
|
||||
this.#children.set(this, children);
|
||||
this.#type &= ~READDIR_CALLED;
|
||||
return children;
|
||||
}
|
||||
/**
|
||||
* Resolves a path portion and returns or creates the child Path.
|
||||
*
|
||||
* Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
|
||||
* `'..'`.
|
||||
*
|
||||
* This should not be called directly. If `pathPart` contains any path
|
||||
* separators, it will lead to unsafe undefined behavior.
|
||||
*
|
||||
* Use `Path.resolve()` instead.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
child(pathPart, opts) {
|
||||
if (pathPart === '' || pathPart === '.') {
|
||||
return this;
|
||||
}
|
||||
if (pathPart === '..') {
|
||||
return this.parent || this;
|
||||
}
|
||||
// find the child
|
||||
const children = this.children();
|
||||
const name = this.nocase
|
||||
? normalizeNocase(pathPart)
|
||||
: normalize(pathPart);
|
||||
for (const p of children) {
|
||||
if (p.#matchName === name) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
// didn't find it, create provisional child, since it might not
|
||||
// actually exist. If we know the parent isn't a dir, then
|
||||
// in fact it CAN'T exist.
|
||||
const s = this.parent ? this.sep : '';
|
||||
const fullpath = this.#fullpath
|
||||
? this.#fullpath + s + pathPart
|
||||
: undefined;
|
||||
const pchild = this.newChild(pathPart, UNKNOWN, {
|
||||
...opts,
|
||||
parent: this,
|
||||
fullpath,
|
||||
});
|
||||
if (!this.canReaddir()) {
|
||||
pchild.#type |= ENOENT;
|
||||
}
|
||||
// don't have to update provisional, because if we have real children,
|
||||
// then provisional is set to children.length, otherwise a lower number
|
||||
children.push(pchild);
|
||||
return pchild;
|
||||
}
|
||||
/**
|
||||
* The relative path from the cwd. If it does not share an ancestor with
|
||||
* the cwd, then this ends up being equivalent to the fullpath()
|
||||
*/
|
||||
relative() {
|
||||
if (this.#relative !== undefined) {
|
||||
return this.#relative;
|
||||
}
|
||||
const name = this.name;
|
||||
const p = this.parent;
|
||||
if (!p) {
|
||||
return (this.#relative = this.name);
|
||||
}
|
||||
const pv = p.relative();
|
||||
return pv + (!pv || !p.parent ? '' : this.sep) + name;
|
||||
}
|
||||
/**
|
||||
* The relative path from the cwd, using / as the path separator.
|
||||
* If it does not share an ancestor with
|
||||
* the cwd, then this ends up being equivalent to the fullpathPosix()
|
||||
* On posix systems, this is identical to relative().
|
||||
*/
|
||||
relativePosix() {
|
||||
if (this.sep === '/')
|
||||
return this.relative();
|
||||
if (this.#relativePosix !== undefined)
|
||||
return this.#relativePosix;
|
||||
const name = this.name;
|
||||
const p = this.parent;
|
||||
if (!p) {
|
||||
return (this.#relativePosix = this.fullpathPosix());
|
||||
}
|
||||
const pv = p.relativePosix();
|
||||
return pv + (!pv || !p.parent ? '' : '/') + name;
|
||||
}
|
||||
/**
|
||||
* The fully resolved path string for this Path entry
|
||||
*/
|
||||
fullpath() {
|
||||
if (this.#fullpath !== undefined) {
|
||||
return this.#fullpath;
|
||||
}
|
||||
const name = this.name;
|
||||
const p = this.parent;
|
||||
if (!p) {
|
||||
return (this.#fullpath = this.name);
|
||||
}
|
||||
const pv = p.fullpath();
|
||||
const fp = pv + (!p.parent ? '' : this.sep) + name;
|
||||
return (this.#fullpath = fp);
|
||||
}
|
||||
/**
|
||||
* On platforms other than windows, this is identical to fullpath.
|
||||
*
|
||||
* On windows, this is overridden to return the forward-slash form of the
|
||||
* full UNC path.
|
||||
*/
|
||||
fullpathPosix() {
|
||||
if (this.#fullpathPosix !== undefined)
|
||||
return this.#fullpathPosix;
|
||||
if (this.sep === '/')
|
||||
return (this.#fullpathPosix = this.fullpath());
|
||||
if (!this.parent) {
|
||||
const p = this.fullpath().replace(/\\/g, '/');
|
||||
if (/^[a-z]:\//i.test(p)) {
|
||||
return (this.#fullpathPosix = `//?/${p}`);
|
||||
}
|
||||
else {
|
||||
return (this.#fullpathPosix = p);
|
||||
}
|
||||
}
|
||||
const p = this.parent;
|
||||
const pfpp = p.fullpathPosix();
|
||||
const fpp = pfpp + (!pfpp || !p.parent ? '' : '/') + this.name;
|
||||
return (this.#fullpathPosix = fpp);
|
||||
}
|
||||
/**
|
||||
* Is the Path of an unknown type?
|
||||
*
|
||||
* Note that we might know *something* about it if there has been a previous
|
||||
* filesystem operation, for example that it does not exist, or is not a
|
||||
* link, or whether it has child entries.
|
||||
*/
|
||||
isUnknown() {
|
||||
return (this.#type & IFMT) === UNKNOWN;
|
||||
}
|
||||
isType(type) {
|
||||
return this[`is${type}`]();
|
||||
}
|
||||
getType() {
|
||||
return this.isUnknown()
|
||||
? 'Unknown'
|
||||
: this.isDirectory()
|
||||
? 'Directory'
|
||||
: this.isFile()
|
||||
? 'File'
|
||||
: this.isSymbolicLink()
|
||||
? 'SymbolicLink'
|
||||
: this.isFIFO()
|
||||
? 'FIFO'
|
||||
: this.isCharacterDevice()
|
||||
? 'CharacterDevice'
|
||||
: this.isBlockDevice()
|
||||
? 'BlockDevice'
|
||||
: /* c8 ignore start */ this.isSocket()
|
||||
? 'Socket'
|
||||
: 'Unknown';
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
/**
|
||||
* Is the Path a regular file?
|
||||
*/
|
||||
isFile() {
|
||||
return (this.#type & IFMT) === IFREG;
|
||||
}
|
||||
/**
|
||||
* Is the Path a directory?
|
||||
*/
|
||||
isDirectory() {
|
||||
return (this.#type & IFMT) === IFDIR;
|
||||
}
|
||||
/**
|
||||
* Is the path a character device?
|
||||
*/
|
||||
isCharacterDevice() {
|
||||
return (this.#type & IFMT) === IFCHR;
|
||||
}
|
||||
/**
|
||||
* Is the path a block device?
|
||||
*/
|
||||
isBlockDevice() {
|
||||
return (this.#type & IFMT) === IFBLK;
|
||||
}
|
||||
/**
|
||||
* Is the path a FIFO pipe?
|
||||
*/
|
||||
isFIFO() {
|
||||
return (this.#type & IFMT) === IFIFO;
|
||||
}
|
||||
/**
|
||||
* Is the path a socket?
|
||||
*/
|
||||
isSocket() {
|
||||
return (this.#type & IFMT) === IFSOCK;
|
||||
}
|
||||
/**
|
||||
* Is the path a symbolic link?
|
||||
*/
|
||||
isSymbolicLink() {
|
||||
return (this.#type & IFLNK) === IFLNK;
|
||||
}
|
||||
/**
|
||||
* Return the entry if it has been subject of a successful lstat, or
|
||||
* undefined otherwise.
|
||||
*
|
||||
* Does not read the filesystem, so an undefined result *could* simply
|
||||
* mean that we haven't called lstat on it.
|
||||
*/
|
||||
lstatCached() {
|
||||
return this.#type & LSTAT_CALLED ? this : undefined;
|
||||
}
|
||||
/**
|
||||
* Return the cached link target if the entry has been the subject of a
|
||||
* successful readlink, or undefined otherwise.
|
||||
*
|
||||
* Does not read the filesystem, so an undefined result *could* just mean we
|
||||
* don't have any cached data. Only use it if you are very sure that a
|
||||
* readlink() has been called at some point.
|
||||
*/
|
||||
readlinkCached() {
|
||||
return this.#linkTarget;
|
||||
}
|
||||
/**
|
||||
* Returns the cached realpath target if the entry has been the subject
|
||||
* of a successful realpath, or undefined otherwise.
|
||||
*
|
||||
* Does not read the filesystem, so an undefined result *could* just mean we
|
||||
* don't have any cached data. Only use it if you are very sure that a
|
||||
* realpath() has been called at some point.
|
||||
*/
|
||||
realpathCached() {
|
||||
return this.#realpath;
|
||||
}
|
||||
/**
|
||||
* Returns the cached child Path entries array if the entry has been the
|
||||
* subject of a successful readdir(), or [] otherwise.
|
||||
*
|
||||
* Does not read the filesystem, so an empty array *could* just mean we
|
||||
* don't have any cached data. Only use it if you are very sure that a
|
||||
* readdir() has been called recently enough to still be valid.
|
||||
*/
|
||||
readdirCached() {
|
||||
const children = this.children();
|
||||
return children.slice(0, children.provisional);
|
||||
}
|
||||
/**
|
||||
* Return true if it's worth trying to readlink. Ie, we don't (yet) have
|
||||
* any indication that readlink will definitely fail.
|
||||
*
|
||||
* Returns false if the path is known to not be a symlink, if a previous
|
||||
* readlink failed, or if the entry does not exist.
|
||||
*/
|
||||
canReadlink() {
|
||||
if (this.#linkTarget)
|
||||
return true;
|
||||
if (!this.parent)
|
||||
return false;
|
||||
// cases where it cannot possibly succeed
|
||||
const ifmt = this.#type & IFMT;
|
||||
return !((ifmt !== UNKNOWN && ifmt !== IFLNK) ||
|
||||
this.#type & ENOREADLINK ||
|
||||
this.#type & ENOENT);
|
||||
}
|
||||
/**
|
||||
* Return true if readdir has previously been successfully called on this
|
||||
* path, indicating that cachedReaddir() is likely valid.
|
||||
*/
|
||||
calledReaddir() {
|
||||
return !!(this.#type & READDIR_CALLED);
|
||||
}
|
||||
/**
|
||||
* Returns true if the path is known to not exist. That is, a previous lstat
|
||||
* or readdir failed to verify its existence when that would have been
|
||||
* expected, or a parent entry was marked either enoent or enotdir.
|
||||
*/
|
||||
isENOENT() {
|
||||
return !!(this.#type & ENOENT);
|
||||
}
|
||||
/**
|
||||
* Return true if the path is a match for the given path name. This handles
|
||||
* case sensitivity and unicode normalization.
|
||||
*
|
||||
* Note: even on case-sensitive systems, it is **not** safe to test the
|
||||
* equality of the `.name` property to determine whether a given pathname
|
||||
* matches, due to unicode normalization mismatches.
|
||||
*
|
||||
* Always use this method instead of testing the `path.name` property
|
||||
* directly.
|
||||
*/
|
||||
isNamed(n) {
|
||||
return !this.nocase
|
||||
? this.#matchName === normalize(n)
|
||||
: this.#matchName === normalizeNocase(n);
|
||||
}
|
||||
/**
|
||||
* Return the Path object corresponding to the target of a symbolic link.
|
||||
*
|
||||
* If the Path is not a symbolic link, or if the readlink call fails for any
|
||||
* reason, `undefined` is returned.
|
||||
*
|
||||
* Result is cached, and thus may be outdated if the filesystem is mutated.
|
||||
*/
|
||||
async readlink() {
|
||||
const target = this.#linkTarget;
|
||||
if (target) {
|
||||
return target;
|
||||
}
|
||||
if (!this.canReadlink()) {
|
||||
return undefined;
|
||||
}
|
||||
/* c8 ignore start */
|
||||
// already covered by the canReadlink test, here for ts grumples
|
||||
if (!this.parent) {
|
||||
return undefined;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
try {
|
||||
const read = await this.#fs.promises.readlink(this.fullpath());
|
||||
const linkTarget = this.parent.resolve(read);
|
||||
if (linkTarget) {
|
||||
return (this.#linkTarget = linkTarget);
|
||||
}
|
||||
}
|
||||
catch (er) {
|
||||
this.#readlinkFail(er.code);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Synchronous {@link PathBase.readlink}
|
||||
*/
|
||||
readlinkSync() {
|
||||
const target = this.#linkTarget;
|
||||
if (target) {
|
||||
return target;
|
||||
}
|
||||
if (!this.canReadlink()) {
|
||||
return undefined;
|
||||
}
|
||||
/* c8 ignore start */
|
||||
// already covered by the canReadlink test, here for ts grumples
|
||||
if (!this.parent) {
|
||||
return undefined;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
try {
|
||||
const read = this.#fs.readlinkSync(this.fullpath());
|
||||
const linkTarget = this.parent.resolve(read);
|
||||
if (linkTarget) {
|
||||
return (this.#linkTarget = linkTarget);
|
||||
}
|
||||
}
|
||||
catch (er) {
|
||||
this.#readlinkFail(er.code);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
#readdirSuccess(children) {
|
||||
// succeeded, mark readdir called bit
|
||||
this.#type |= READDIR_CALLED;
|
||||
// mark all remaining provisional children as ENOENT
|
||||
for (let p = children.provisional; p < children.length; p++) {
|
||||
children[p].#markENOENT();
|
||||
}
|
||||
}
|
||||
#markENOENT() {
|
||||
// mark as UNKNOWN and ENOENT
|
||||
if (this.#type & ENOENT)
|
||||
return;
|
||||
this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
|
||||
this.#markChildrenENOENT();
|
||||
}
|
||||
#markChildrenENOENT() {
|
||||
// all children are provisional and do not exist
|
||||
const children = this.children();
|
||||
children.provisional = 0;
|
||||
for (const p of children) {
|
||||
p.#markENOENT();
|
||||
}
|
||||
}
|
||||
#markENOREALPATH() {
|
||||
this.#type |= ENOREALPATH;
|
||||
this.#markENOTDIR();
|
||||
}
|
||||
// save the information when we know the entry is not a dir
|
||||
#markENOTDIR() {
|
||||
// entry is not a directory, so any children can't exist.
|
||||
// this *should* be impossible, since any children created
|
||||
// after it's been marked ENOTDIR should be marked ENOENT,
|
||||
// so it won't even get to this point.
|
||||
/* c8 ignore start */
|
||||
if (this.#type & ENOTDIR)
|
||||
return;
|
||||
/* c8 ignore stop */
|
||||
let t = this.#type;
|
||||
// this could happen if we stat a dir, then delete it,
|
||||
// then try to read it or one of its children.
|
||||
if ((t & IFMT) === IFDIR)
|
||||
t &= IFMT_UNKNOWN;
|
||||
this.#type = t | ENOTDIR;
|
||||
this.#markChildrenENOENT();
|
||||
}
|
||||
#readdirFail(code = '') {
|
||||
// markENOTDIR and markENOENT also set provisional=0
|
||||
if (code === 'ENOTDIR' || code === 'EPERM') {
|
||||
this.#markENOTDIR();
|
||||
}
|
||||
else if (code === 'ENOENT') {
|
||||
this.#markENOENT();
|
||||
}
|
||||
else {
|
||||
this.children().provisional = 0;
|
||||
}
|
||||
}
|
||||
#lstatFail(code = '') {
|
||||
// Windows just raises ENOENT in this case, disable for win CI
|
||||
/* c8 ignore start */
|
||||
if (code === 'ENOTDIR') {
|
||||
// already know it has a parent by this point
|
||||
const p = this.parent;
|
||||
p.#markENOTDIR();
|
||||
}
|
||||
else if (code === 'ENOENT') {
|
||||
/* c8 ignore stop */
|
||||
this.#markENOENT();
|
||||
}
|
||||
}
|
||||
#readlinkFail(code = '') {
|
||||
let ter = this.#type;
|
||||
ter |= ENOREADLINK;
|
||||
if (code === 'ENOENT')
|
||||
ter |= ENOENT;
|
||||
// windows gets a weird error when you try to readlink a file
|
||||
if (code === 'EINVAL' || code === 'UNKNOWN') {
|
||||
// exists, but not a symlink, we don't know WHAT it is, so remove
|
||||
// all IFMT bits.
|
||||
ter &= IFMT_UNKNOWN;
|
||||
}
|
||||
this.#type = ter;
|
||||
// windows just gets ENOENT in this case. We do cover the case,
|
||||
// just disabled because it's impossible on Windows CI
|
||||
/* c8 ignore start */
|
||||
if (code === 'ENOTDIR' && this.parent) {
|
||||
this.parent.#markENOTDIR();
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
}
|
||||
#readdirAddChild(e, c) {
|
||||
return (this.#readdirMaybePromoteChild(e, c) ||
|
||||
this.#readdirAddNewChild(e, c));
|
||||
}
|
||||
#readdirAddNewChild(e, c) {
|
||||
// alloc new entry at head, so it's never provisional
|
||||
const type = entToType(e);
|
||||
const child = this.newChild(e.name, type, { parent: this });
|
||||
const ifmt = child.#type & IFMT;
|
||||
if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) {
|
||||
child.#type |= ENOTDIR;
|
||||
}
|
||||
c.unshift(child);
|
||||
c.provisional++;
|
||||
return child;
|
||||
}
|
||||
#readdirMaybePromoteChild(e, c) {
|
||||
for (let p = c.provisional; p < c.length; p++) {
|
||||
const pchild = c[p];
|
||||
const name = this.nocase
|
||||
? normalizeNocase(e.name)
|
||||
: normalize(e.name);
|
||||
if (name !== pchild.#matchName) {
|
||||
continue;
|
||||
}
|
||||
return this.#readdirPromoteChild(e, pchild, p, c);
|
||||
}
|
||||
}
|
||||
#readdirPromoteChild(e, p, index, c) {
|
||||
const v = p.name;
|
||||
// retain any other flags, but set ifmt from dirent
|
||||
p.#type = (p.#type & IFMT_UNKNOWN) | entToType(e);
|
||||
// case sensitivity fixing when we learn the true name.
|
||||
if (v !== e.name)
|
||||
p.name = e.name;
|
||||
// just advance provisional index (potentially off the list),
|
||||
// otherwise we have to splice/pop it out and re-insert at head
|
||||
if (index !== c.provisional) {
|
||||
if (index === c.length - 1)
|
||||
c.pop();
|
||||
else
|
||||
c.splice(index, 1);
|
||||
c.unshift(p);
|
||||
}
|
||||
c.provisional++;
|
||||
return p;
|
||||
}
|
||||
/**
|
||||
* Call lstat() on this Path, and update all known information that can be
|
||||
* determined.
|
||||
*
|
||||
* Note that unlike `fs.lstat()`, the returned value does not contain some
|
||||
* information, such as `mode`, `dev`, `nlink`, and `ino`. If that
|
||||
* information is required, you will need to call `fs.lstat` yourself.
|
||||
*
|
||||
* If the Path refers to a nonexistent file, or if the lstat call fails for
|
||||
* any reason, `undefined` is returned. Otherwise the updated Path object is
|
||||
* returned.
|
||||
*
|
||||
* Results are cached, and thus may be out of date if the filesystem is
|
||||
* mutated.
|
||||
*/
|
||||
async lstat() {
|
||||
if ((this.#type & ENOENT) === 0) {
|
||||
try {
|
||||
this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
|
||||
return this;
|
||||
}
|
||||
catch (er) {
|
||||
this.#lstatFail(er.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* synchronous {@link PathBase.lstat}
|
||||
*/
|
||||
lstatSync() {
|
||||
if ((this.#type & ENOENT) === 0) {
|
||||
try {
|
||||
this.#applyStat(this.#fs.lstatSync(this.fullpath()));
|
||||
return this;
|
||||
}
|
||||
catch (er) {
|
||||
this.#lstatFail(er.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
#applyStat(st) {
|
||||
const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid, } = st;
|
||||
this.#atime = atime;
|
||||
this.#atimeMs = atimeMs;
|
||||
this.#birthtime = birthtime;
|
||||
this.#birthtimeMs = birthtimeMs;
|
||||
this.#blksize = blksize;
|
||||
this.#blocks = blocks;
|
||||
this.#ctime = ctime;
|
||||
this.#ctimeMs = ctimeMs;
|
||||
this.#dev = dev;
|
||||
this.#gid = gid;
|
||||
this.#ino = ino;
|
||||
this.#mode = mode;
|
||||
this.#mtime = mtime;
|
||||
this.#mtimeMs = mtimeMs;
|
||||
this.#nlink = nlink;
|
||||
this.#rdev = rdev;
|
||||
this.#size = size;
|
||||
this.#uid = uid;
|
||||
const ifmt = entToType(st);
|
||||
// retain any other flags, but set the ifmt
|
||||
this.#type = (this.#type & IFMT_UNKNOWN) | ifmt | LSTAT_CALLED;
|
||||
if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) {
|
||||
this.#type |= ENOTDIR;
|
||||
}
|
||||
}
|
||||
#onReaddirCB = [];
|
||||
#readdirCBInFlight = false;
|
||||
#callOnReaddirCB(children) {
|
||||
this.#readdirCBInFlight = false;
|
||||
const cbs = this.#onReaddirCB.slice();
|
||||
this.#onReaddirCB.length = 0;
|
||||
cbs.forEach(cb => cb(null, children));
|
||||
}
|
||||
/**
|
||||
* Standard node-style callback interface to get list of directory entries.
|
||||
*
|
||||
* If the Path cannot or does not contain any children, then an empty array
|
||||
* is returned.
|
||||
*
|
||||
* Results are cached, and thus may be out of date if the filesystem is
|
||||
* mutated.
|
||||
*
|
||||
* @param cb The callback called with (er, entries). Note that the `er`
|
||||
* param is somewhat extraneous, as all readdir() errors are handled and
|
||||
* simply result in an empty set of entries being returned.
|
||||
* @param allowZalgo Boolean indicating that immediately known results should
|
||||
* *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
|
||||
* zalgo at your peril, the dark pony lord is devious and unforgiving.
|
||||
*/
|
||||
readdirCB(cb, allowZalgo = false) {
|
||||
if (!this.canReaddir()) {
|
||||
if (allowZalgo)
|
||||
cb(null, []);
|
||||
else
|
||||
queueMicrotask(() => cb(null, []));
|
||||
return;
|
||||
}
|
||||
const children = this.children();
|
||||
if (this.calledReaddir()) {
|
||||
const c = children.slice(0, children.provisional);
|
||||
if (allowZalgo)
|
||||
cb(null, c);
|
||||
else
|
||||
queueMicrotask(() => cb(null, c));
|
||||
return;
|
||||
}
|
||||
// don't have to worry about zalgo at this point.
|
||||
this.#onReaddirCB.push(cb);
|
||||
if (this.#readdirCBInFlight) {
|
||||
return;
|
||||
}
|
||||
this.#readdirCBInFlight = true;
|
||||
// else read the directory, fill up children
|
||||
// de-provisionalize any provisional children.
|
||||
const fullpath = this.fullpath();
|
||||
this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
|
||||
if (er) {
|
||||
this.#readdirFail(er.code);
|
||||
children.provisional = 0;
|
||||
}
|
||||
else {
|
||||
// if we didn't get an error, we always get entries.
|
||||
//@ts-ignore
|
||||
for (const e of entries) {
|
||||
this.#readdirAddChild(e, children);
|
||||
}
|
||||
this.#readdirSuccess(children);
|
||||
}
|
||||
this.#callOnReaddirCB(children.slice(0, children.provisional));
|
||||
return;
|
||||
});
|
||||
}
|
||||
#asyncReaddirInFlight;
|
||||
/**
|
||||
* Return an array of known child entries.
|
||||
*
|
||||
* If the Path cannot or does not contain any children, then an empty array
|
||||
* is returned.
|
||||
*
|
||||
* Results are cached, and thus may be out of date if the filesystem is
|
||||
* mutated.
|
||||
*/
|
||||
async readdir() {
|
||||
if (!this.canReaddir()) {
|
||||
return [];
|
||||
}
|
||||
const children = this.children();
|
||||
if (this.calledReaddir()) {
|
||||
return children.slice(0, children.provisional);
|
||||
}
|
||||
// else read the directory, fill up children
|
||||
// de-provisionalize any provisional children.
|
||||
const fullpath = this.fullpath();
|
||||
if (this.#asyncReaddirInFlight) {
|
||||
await this.#asyncReaddirInFlight;
|
||||
}
|
||||
else {
|
||||
/* c8 ignore start */
|
||||
let resolve = () => { };
|
||||
/* c8 ignore stop */
|
||||
this.#asyncReaddirInFlight = new Promise(res => (resolve = res));
|
||||
try {
|
||||
for (const e of await this.#fs.promises.readdir(fullpath, {
|
||||
withFileTypes: true,
|
||||
})) {
|
||||
this.#readdirAddChild(e, children);
|
||||
}
|
||||
this.#readdirSuccess(children);
|
||||
}
|
||||
catch (er) {
|
||||
this.#readdirFail(er.code);
|
||||
children.provisional = 0;
|
||||
}
|
||||
this.#asyncReaddirInFlight = undefined;
|
||||
resolve();
|
||||
}
|
||||
return children.slice(0, children.provisional);
|
||||
}
|
||||
/**
|
||||
* synchronous {@link PathBase.readdir}
|
||||
*/
|
||||
readdirSync() {
|
||||
if (!this.canReaddir()) {
|
||||
return [];
|
||||
}
|
||||
const children = this.children();
|
||||
if (this.calledReaddir()) {
|
||||
return children.slice(0, children.provisional);
|
||||
}
|
||||
// else read the directory, fill up children
|
||||
// de-provisionalize any provisional children.
|
||||
const fullpath = this.fullpath();
|
||||
try {
|
||||
for (const e of this.#fs.readdirSync(fullpath, {
|
||||
withFileTypes: true,
|
||||
})) {
|
||||
this.#readdirAddChild(e, children);
|
||||
}
|
||||
this.#readdirSuccess(children);
|
||||
}
|
||||
catch (er) {
|
||||
this.#readdirFail(er.code);
|
||||
children.provisional = 0;
|
||||
}
|
||||
return children.slice(0, children.provisional);
|
||||
}
|
||||
canReaddir() {
|
||||
if (this.#type & ENOCHILD)
|
||||
return false;
|
||||
const ifmt = IFMT & this.#type;
|
||||
// we always set ENOTDIR when setting IFMT, so should be impossible
|
||||
/* c8 ignore start */
|
||||
if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) {
|
||||
return false;
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return true;
|
||||
}
|
||||
shouldWalk(dirs, walkFilter) {
|
||||
return ((this.#type & IFDIR) === IFDIR &&
|
||||
!(this.#type & ENOCHILD) &&
|
||||
!dirs.has(this) &&
|
||||
(!walkFilter || walkFilter(this)));
|
||||
}
|
||||
/**
|
||||
* Return the Path object corresponding to path as resolved
|
||||
* by realpath(3).
|
||||
*
|
||||
* If the realpath call fails for any reason, `undefined` is returned.
|
||||
*
|
||||
* Result is cached, and thus may be outdated if the filesystem is mutated.
|
||||
* On success, returns a Path object.
|
||||
*/
|
||||
async realpath() {
|
||||
if (this.#realpath)
|
||||
return this.#realpath;
|
||||
if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
|
||||
return undefined;
|
||||
try {
|
||||
const rp = await this.#fs.promises.realpath(this.fullpath());
|
||||
return (this.#realpath = this.resolve(rp));
|
||||
}
|
||||
catch (_) {
|
||||
this.#markENOREALPATH();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Synchronous {@link realpath}
|
||||
*/
|
||||
realpathSync() {
|
||||
if (this.#realpath)
|
||||
return this.#realpath;
|
||||
if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type)
|
||||
return undefined;
|
||||
try {
|
||||
const rp = this.#fs.realpathSync(this.fullpath());
|
||||
return (this.#realpath = this.resolve(rp));
|
||||
}
|
||||
catch (_) {
|
||||
this.#markENOREALPATH();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Internal method to mark this Path object as the scurry cwd,
|
||||
* called by {@link PathScurry#chdir}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
[setAsCwd](oldCwd) {
|
||||
if (oldCwd === this)
|
||||
return;
|
||||
const changed = new Set([]);
|
||||
let rp = [];
|
||||
let p = this;
|
||||
while (p && p.parent) {
|
||||
changed.add(p);
|
||||
p.#relative = rp.join(this.sep);
|
||||
p.#relativePosix = rp.join('/');
|
||||
p = p.parent;
|
||||
rp.push('..');
|
||||
}
|
||||
// now un-memoize parents of old cwd
|
||||
p = oldCwd;
|
||||
while (p && p.parent && !changed.has(p)) {
|
||||
p.#relative = undefined;
|
||||
p.#relativePosix = undefined;
|
||||
p = p.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Path class used on win32 systems
|
||||
*
|
||||
* Uses `'\\'` as the path separator for returned paths, either `'\\'` or `'/'`
|
||||
* as the path separator for parsing paths.
|
||||
*/
|
||||
class PathWin32 extends PathBase {
|
||||
/**
|
||||
* Separator for generating path strings.
|
||||
*/
|
||||
sep = '\\';
|
||||
/**
|
||||
* Separator for parsing path strings.
|
||||
*/
|
||||
splitSep = eitherSep;
|
||||
/**
|
||||
* Do not create new Path objects directly. They should always be accessed
|
||||
* via the PathScurry class or other methods on the Path class.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
||||
super(name, type, root, roots, nocase, children, opts);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
newChild(name, type = UNKNOWN, opts = {}) {
|
||||
return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getRootString(path) {
|
||||
return external_path_.win32.parse(path).root;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getRoot(rootPath) {
|
||||
rootPath = uncToDrive(rootPath.toUpperCase());
|
||||
if (rootPath === this.root.name) {
|
||||
return this.root;
|
||||
}
|
||||
// ok, not that one, check if it matches another we know about
|
||||
for (const [compare, root] of Object.entries(this.roots)) {
|
||||
if (this.sameRoot(rootPath, compare)) {
|
||||
return (this.roots[rootPath] = root);
|
||||
}
|
||||
}
|
||||
// otherwise, have to create a new one.
|
||||
return (this.roots[rootPath] = new PathScurryWin32(rootPath, this).root);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
sameRoot(rootPath, compare = this.root.name) {
|
||||
// windows can (rarely) have case-sensitive filesystem, but
|
||||
// UNC and drive letters are always case-insensitive, and canonically
|
||||
// represented uppercase.
|
||||
rootPath = rootPath
|
||||
.toUpperCase()
|
||||
.replace(/\//g, '\\')
|
||||
.replace(uncDriveRegexp, '$1\\');
|
||||
return rootPath === compare;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Path class used on all posix systems.
|
||||
*
|
||||
* Uses `'/'` as the path separator.
|
||||
*/
|
||||
class PathPosix extends PathBase {
|
||||
/**
|
||||
* separator for parsing path strings
|
||||
*/
|
||||
splitSep = '/';
|
||||
/**
|
||||
* separator for generating path strings
|
||||
*/
|
||||
sep = '/';
|
||||
/**
|
||||
* Do not create new Path objects directly. They should always be accessed
|
||||
* via the PathScurry class or other methods on the Path class.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
||||
super(name, type, root, roots, nocase, children, opts);
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getRootString(path) {
|
||||
return path.startsWith('/') ? '/' : '';
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getRoot(_rootPath) {
|
||||
return this.root;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
newChild(name, type = UNKNOWN, opts = {}) {
|
||||
return new PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The base class for all PathScurry classes, providing the interface for path
|
||||
* resolution and filesystem operations.
|
||||
*
|
||||
* Typically, you should *not* instantiate this class directly, but rather one
|
||||
* of the platform-specific classes, or the exported {@link PathScurry} which
|
||||
* defaults to the current platform.
|
||||
*/
|
||||
class PathScurryBase {
|
||||
/**
|
||||
* The root Path entry for the current working directory of this Scurry
|
||||
*/
|
||||
root;
|
||||
/**
|
||||
* The string path for the root of this Scurry's current working directory
|
||||
*/
|
||||
rootPath;
|
||||
/**
|
||||
* A collection of all roots encountered, referenced by rootPath
|
||||
*/
|
||||
roots;
|
||||
/**
|
||||
* The Path entry corresponding to this PathScurry's current working directory.
|
||||
*/
|
||||
cwd;
|
||||
#resolveCache;
|
||||
#resolvePosixCache;
|
||||
#children;
|
||||
/**
|
||||
* Perform path comparisons case-insensitively.
|
||||
*
|
||||
* Defaults true on Darwin and Windows systems, false elsewhere.
|
||||
*/
|
||||
nocase;
|
||||
#fs;
|
||||
/**
|
||||
* This class should not be instantiated directly.
|
||||
*
|
||||
* Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS, } = {}) {
|
||||
this.#fs = fsFromOption(fs);
|
||||
if (cwd instanceof URL || cwd.startsWith('file://')) {
|
||||
cwd = (0,external_url_.fileURLToPath)(cwd);
|
||||
}
|
||||
// resolve and split root, and then add to the store.
|
||||
// this is the only time we call path.resolve()
|
||||
const cwdPath = pathImpl.resolve(cwd);
|
||||
this.roots = Object.create(null);
|
||||
this.rootPath = this.parseRootPath(cwdPath);
|
||||
this.#resolveCache = new ResolveCache();
|
||||
this.#resolvePosixCache = new ResolveCache();
|
||||
this.#children = new ChildrenCache(childrenCacheSize);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep);
|
||||
// resolve('/') leaves '', splits to [''], we don't want that.
|
||||
if (split.length === 1 && !split[0]) {
|
||||
split.pop();
|
||||
}
|
||||
/* c8 ignore start */
|
||||
if (nocase === undefined) {
|
||||
throw new TypeError('must provide nocase setting to PathScurryBase ctor');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
this.nocase = nocase;
|
||||
this.root = this.newRoot(this.#fs);
|
||||
this.roots[this.rootPath] = this.root;
|
||||
let prev = this.root;
|
||||
let len = split.length - 1;
|
||||
const joinSep = pathImpl.sep;
|
||||
let abs = this.rootPath;
|
||||
let sawFirst = false;
|
||||
for (const part of split) {
|
||||
const l = len--;
|
||||
prev = prev.child(part, {
|
||||
relative: new Array(l).fill('..').join(joinSep),
|
||||
relativePosix: new Array(l).fill('..').join('/'),
|
||||
fullpath: (abs += (sawFirst ? '' : joinSep) + part),
|
||||
});
|
||||
sawFirst = true;
|
||||
}
|
||||
this.cwd = prev;
|
||||
}
|
||||
/**
|
||||
* Get the depth of a provided path, string, or the cwd
|
||||
*/
|
||||
depth(path = this.cwd) {
|
||||
if (typeof path === 'string') {
|
||||
path = this.cwd.resolve(path);
|
||||
}
|
||||
return path.depth();
|
||||
}
|
||||
/**
|
||||
* Return the cache of child entries. Exposed so subclasses can create
|
||||
* child Path objects in a platform-specific way.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
childrenCache() {
|
||||
return this.#children;
|
||||
}
|
||||
/**
|
||||
* Resolve one or more path strings to a resolved string
|
||||
*
|
||||
* Same interface as require('path').resolve.
|
||||
*
|
||||
* Much faster than path.resolve() when called multiple times for the same
|
||||
* path, because the resolved Path objects are cached. Much slower
|
||||
* otherwise.
|
||||
*/
|
||||
resolve(...paths) {
|
||||
// first figure out the minimum number of paths we have to test
|
||||
// we always start at cwd, but any absolutes will bump the start
|
||||
let r = '';
|
||||
for (let i = paths.length - 1; i >= 0; i--) {
|
||||
const p = paths[i];
|
||||
if (!p || p === '.')
|
||||
continue;
|
||||
r = r ? `${p}/${r}` : p;
|
||||
if (this.isAbsolute(p)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const cached = this.#resolveCache.get(r);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
const result = this.cwd.resolve(r).fullpath();
|
||||
this.#resolveCache.set(r, result);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Resolve one or more path strings to a resolved string, returning
|
||||
* the posix path. Identical to .resolve() on posix systems, but on
|
||||
* windows will return a forward-slash separated UNC path.
|
||||
*
|
||||
* Same interface as require('path').resolve.
|
||||
*
|
||||
* Much faster than path.resolve() when called multiple times for the same
|
||||
* path, because the resolved Path objects are cached. Much slower
|
||||
* otherwise.
|
||||
*/
|
||||
resolvePosix(...paths) {
|
||||
// first figure out the minimum number of paths we have to test
|
||||
// we always start at cwd, but any absolutes will bump the start
|
||||
let r = '';
|
||||
for (let i = paths.length - 1; i >= 0; i--) {
|
||||
const p = paths[i];
|
||||
if (!p || p === '.')
|
||||
continue;
|
||||
r = r ? `${p}/${r}` : p;
|
||||
if (this.isAbsolute(p)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const cached = this.#resolvePosixCache.get(r);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
const result = this.cwd.resolve(r).fullpathPosix();
|
||||
this.#resolvePosixCache.set(r, result);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* find the relative path from the cwd to the supplied path string or entry
|
||||
*/
|
||||
relative(entry = this.cwd) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
return entry.relative();
|
||||
}
|
||||
/**
|
||||
* find the relative path from the cwd to the supplied path string or
|
||||
* entry, using / as the path delimiter, even on Windows.
|
||||
*/
|
||||
relativePosix(entry = this.cwd) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
return entry.relativePosix();
|
||||
}
|
||||
/**
|
||||
* Return the basename for the provided string or Path object
|
||||
*/
|
||||
basename(entry = this.cwd) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
return entry.name;
|
||||
}
|
||||
/**
|
||||
* Return the dirname for the provided string or Path object
|
||||
*/
|
||||
dirname(entry = this.cwd) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
return (entry.parent || entry).fullpath();
|
||||
}
|
||||
async readdir(entry = this.cwd, opts = {
|
||||
withFileTypes: true,
|
||||
}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes } = opts;
|
||||
if (!entry.canReaddir()) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
const p = await entry.readdir();
|
||||
return withFileTypes ? p : p.map(e => e.name);
|
||||
}
|
||||
}
|
||||
readdirSync(entry = this.cwd, opts = {
|
||||
withFileTypes: true,
|
||||
}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes = true } = opts;
|
||||
if (!entry.canReaddir()) {
|
||||
return [];
|
||||
}
|
||||
else if (withFileTypes) {
|
||||
return entry.readdirSync();
|
||||
}
|
||||
else {
|
||||
return entry.readdirSync().map(e => e.name);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call lstat() on the string or Path object, and update all known
|
||||
* information that can be determined.
|
||||
*
|
||||
* Note that unlike `fs.lstat()`, the returned value does not contain some
|
||||
* information, such as `mode`, `dev`, `nlink`, and `ino`. If that
|
||||
* information is required, you will need to call `fs.lstat` yourself.
|
||||
*
|
||||
* If the Path refers to a nonexistent file, or if the lstat call fails for
|
||||
* any reason, `undefined` is returned. Otherwise the updated Path object is
|
||||
* returned.
|
||||
*
|
||||
* Results are cached, and thus may be out of date if the filesystem is
|
||||
* mutated.
|
||||
*/
|
||||
async lstat(entry = this.cwd) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
return entry.lstat();
|
||||
}
|
||||
/**
|
||||
* synchronous {@link PathScurryBase.lstat}
|
||||
*/
|
||||
lstatSync(entry = this.cwd) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
return entry.lstatSync();
|
||||
}
|
||||
async readlink(entry = this.cwd, { withFileTypes } = {
|
||||
withFileTypes: false,
|
||||
}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
withFileTypes = entry.withFileTypes;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const e = await entry.readlink();
|
||||
return withFileTypes ? e : e?.fullpath();
|
||||
}
|
||||
readlinkSync(entry = this.cwd, { withFileTypes } = {
|
||||
withFileTypes: false,
|
||||
}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
withFileTypes = entry.withFileTypes;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const e = entry.readlinkSync();
|
||||
return withFileTypes ? e : e?.fullpath();
|
||||
}
|
||||
async realpath(entry = this.cwd, { withFileTypes } = {
|
||||
withFileTypes: false,
|
||||
}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
withFileTypes = entry.withFileTypes;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const e = await entry.realpath();
|
||||
return withFileTypes ? e : e?.fullpath();
|
||||
}
|
||||
realpathSync(entry = this.cwd, { withFileTypes } = {
|
||||
withFileTypes: false,
|
||||
}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
withFileTypes = entry.withFileTypes;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const e = entry.realpathSync();
|
||||
return withFileTypes ? e : e?.fullpath();
|
||||
}
|
||||
async walk(entry = this.cwd, opts = {}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
|
||||
const results = [];
|
||||
if (!filter || filter(entry)) {
|
||||
results.push(withFileTypes ? entry : entry.fullpath());
|
||||
}
|
||||
const dirs = new Set();
|
||||
const walk = (dir, cb) => {
|
||||
dirs.add(dir);
|
||||
dir.readdirCB((er, entries) => {
|
||||
/* c8 ignore start */
|
||||
if (er) {
|
||||
return cb(er);
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
let len = entries.length;
|
||||
if (!len)
|
||||
return cb();
|
||||
const next = () => {
|
||||
if (--len === 0) {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
for (const e of entries) {
|
||||
if (!filter || filter(e)) {
|
||||
results.push(withFileTypes ? e : e.fullpath());
|
||||
}
|
||||
if (follow && e.isSymbolicLink()) {
|
||||
e.realpath()
|
||||
.then(r => (r?.isUnknown() ? r.lstat() : r))
|
||||
.then(r => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
|
||||
}
|
||||
else {
|
||||
if (e.shouldWalk(dirs, walkFilter)) {
|
||||
walk(e, next);
|
||||
}
|
||||
else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true); // zalgooooooo
|
||||
};
|
||||
const start = entry;
|
||||
return new Promise((res, rej) => {
|
||||
walk(start, er => {
|
||||
/* c8 ignore start */
|
||||
if (er)
|
||||
return rej(er);
|
||||
/* c8 ignore stop */
|
||||
res(results);
|
||||
});
|
||||
});
|
||||
}
|
||||
walkSync(entry = this.cwd, opts = {}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
|
||||
const results = [];
|
||||
if (!filter || filter(entry)) {
|
||||
results.push(withFileTypes ? entry : entry.fullpath());
|
||||
}
|
||||
const dirs = new Set([entry]);
|
||||
for (const dir of dirs) {
|
||||
const entries = dir.readdirSync();
|
||||
for (const e of entries) {
|
||||
if (!filter || filter(e)) {
|
||||
results.push(withFileTypes ? e : e.fullpath());
|
||||
}
|
||||
let r = e;
|
||||
if (e.isSymbolicLink()) {
|
||||
if (!(follow && (r = e.realpathSync())))
|
||||
continue;
|
||||
if (r.isUnknown())
|
||||
r.lstatSync();
|
||||
}
|
||||
if (r.shouldWalk(dirs, walkFilter)) {
|
||||
dirs.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
/**
|
||||
* Support for `for await`
|
||||
*
|
||||
* Alias for {@link PathScurryBase.iterate}
|
||||
*
|
||||
* Note: As of Node 19, this is very slow, compared to other methods of
|
||||
* walking. Consider using {@link PathScurryBase.stream} if memory overhead
|
||||
* and backpressure are concerns, or {@link PathScurryBase.walk} if not.
|
||||
*/
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.iterate();
|
||||
}
|
||||
iterate(entry = this.cwd, options = {}) {
|
||||
// iterating async over the stream is significantly more performant,
|
||||
// especially in the warm-cache scenario, because it buffers up directory
|
||||
// entries in the background instead of waiting for a yield for each one.
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
options = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
return this.stream(entry, options)[Symbol.asyncIterator]();
|
||||
}
|
||||
/**
|
||||
* Iterating over a PathScurry performs a synchronous walk.
|
||||
*
|
||||
* Alias for {@link PathScurryBase.iterateSync}
|
||||
*/
|
||||
[Symbol.iterator]() {
|
||||
return this.iterateSync();
|
||||
}
|
||||
*iterateSync(entry = this.cwd, opts = {}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
|
||||
if (!filter || filter(entry)) {
|
||||
yield withFileTypes ? entry : entry.fullpath();
|
||||
}
|
||||
const dirs = new Set([entry]);
|
||||
for (const dir of dirs) {
|
||||
const entries = dir.readdirSync();
|
||||
for (const e of entries) {
|
||||
if (!filter || filter(e)) {
|
||||
yield withFileTypes ? e : e.fullpath();
|
||||
}
|
||||
let r = e;
|
||||
if (e.isSymbolicLink()) {
|
||||
if (!(follow && (r = e.realpathSync())))
|
||||
continue;
|
||||
if (r.isUnknown())
|
||||
r.lstatSync();
|
||||
}
|
||||
if (r.shouldWalk(dirs, walkFilter)) {
|
||||
dirs.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stream(entry = this.cwd, opts = {}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
|
||||
const results = new Minipass({ objectMode: true });
|
||||
if (!filter || filter(entry)) {
|
||||
results.write(withFileTypes ? entry : entry.fullpath());
|
||||
}
|
||||
const dirs = new Set();
|
||||
const queue = [entry];
|
||||
let processing = 0;
|
||||
const process = () => {
|
||||
let paused = false;
|
||||
while (!paused) {
|
||||
const dir = queue.shift();
|
||||
if (!dir) {
|
||||
if (processing === 0)
|
||||
results.end();
|
||||
return;
|
||||
}
|
||||
processing++;
|
||||
dirs.add(dir);
|
||||
const onReaddir = (er, entries, didRealpaths = false) => {
|
||||
/* c8 ignore start */
|
||||
if (er)
|
||||
return results.emit('error', er);
|
||||
/* c8 ignore stop */
|
||||
if (follow && !didRealpaths) {
|
||||
const promises = [];
|
||||
for (const e of entries) {
|
||||
if (e.isSymbolicLink()) {
|
||||
promises.push(e
|
||||
.realpath()
|
||||
.then((r) => r?.isUnknown() ? r.lstat() : r));
|
||||
}
|
||||
}
|
||||
if (promises.length) {
|
||||
Promise.all(promises).then(() => onReaddir(null, entries, true));
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const e of entries) {
|
||||
if (e && (!filter || filter(e))) {
|
||||
if (!results.write(withFileTypes ? e : e.fullpath())) {
|
||||
paused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
processing--;
|
||||
for (const e of entries) {
|
||||
const r = e.realpathCached() || e;
|
||||
if (r.shouldWalk(dirs, walkFilter)) {
|
||||
queue.push(r);
|
||||
}
|
||||
}
|
||||
if (paused && !results.flowing) {
|
||||
results.once('drain', process);
|
||||
}
|
||||
else if (!sync) {
|
||||
process();
|
||||
}
|
||||
};
|
||||
// zalgo containment
|
||||
let sync = true;
|
||||
dir.readdirCB(onReaddir, true);
|
||||
sync = false;
|
||||
}
|
||||
};
|
||||
process();
|
||||
return results;
|
||||
}
|
||||
streamSync(entry = this.cwd, opts = {}) {
|
||||
if (typeof entry === 'string') {
|
||||
entry = this.cwd.resolve(entry);
|
||||
}
|
||||
else if (!(entry instanceof PathBase)) {
|
||||
opts = entry;
|
||||
entry = this.cwd;
|
||||
}
|
||||
const { withFileTypes = true, follow = false, filter, walkFilter, } = opts;
|
||||
const results = new Minipass({ objectMode: true });
|
||||
const dirs = new Set();
|
||||
if (!filter || filter(entry)) {
|
||||
results.write(withFileTypes ? entry : entry.fullpath());
|
||||
}
|
||||
const queue = [entry];
|
||||
let processing = 0;
|
||||
const process = () => {
|
||||
let paused = false;
|
||||
while (!paused) {
|
||||
const dir = queue.shift();
|
||||
if (!dir) {
|
||||
if (processing === 0)
|
||||
results.end();
|
||||
return;
|
||||
}
|
||||
processing++;
|
||||
dirs.add(dir);
|
||||
const entries = dir.readdirSync();
|
||||
for (const e of entries) {
|
||||
if (!filter || filter(e)) {
|
||||
if (!results.write(withFileTypes ? e : e.fullpath())) {
|
||||
paused = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
processing--;
|
||||
for (const e of entries) {
|
||||
let r = e;
|
||||
if (e.isSymbolicLink()) {
|
||||
if (!(follow && (r = e.realpathSync())))
|
||||
continue;
|
||||
if (r.isUnknown())
|
||||
r.lstatSync();
|
||||
}
|
||||
if (r.shouldWalk(dirs, walkFilter)) {
|
||||
queue.push(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paused && !results.flowing)
|
||||
results.once('drain', process);
|
||||
};
|
||||
process();
|
||||
return results;
|
||||
}
|
||||
chdir(path = this.cwd) {
|
||||
const oldCwd = this.cwd;
|
||||
this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path;
|
||||
this.cwd[setAsCwd](oldCwd);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Windows implementation of {@link PathScurryBase}
|
||||
*
|
||||
* Defaults to case insensitve, uses `'\\'` to generate path strings. Uses
|
||||
* {@link PathWin32} for Path objects.
|
||||
*/
|
||||
class PathScurryWin32 extends PathScurryBase {
|
||||
/**
|
||||
* separator for generating path strings
|
||||
*/
|
||||
sep = '\\';
|
||||
constructor(cwd = process.cwd(), opts = {}) {
|
||||
const { nocase = true } = opts;
|
||||
super(cwd, external_path_.win32, '\\', { ...opts, nocase });
|
||||
this.nocase = nocase;
|
||||
for (let p = this.cwd; p; p = p.parent) {
|
||||
p.nocase = this.nocase;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
parseRootPath(dir) {
|
||||
// if the path starts with a single separator, it's not a UNC, and we'll
|
||||
// just get separator as the root, and driveFromUNC will return \
|
||||
// In that case, mount \ on the root from the cwd.
|
||||
return external_path_.win32.parse(dir).root.toUpperCase();
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
newRoot(fs) {
|
||||
return new PathWin32(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
|
||||
}
|
||||
/**
|
||||
* Return true if the provided path string is an absolute path
|
||||
*/
|
||||
isAbsolute(p) {
|
||||
return (p.startsWith('/') || p.startsWith('\\') || /^[a-z]:(\/|\\)/i.test(p));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@link PathScurryBase} implementation for all posix systems other than Darwin.
|
||||
*
|
||||
* Defaults to case-sensitive matching, uses `'/'` to generate path strings.
|
||||
*
|
||||
* Uses {@link PathPosix} for Path objects.
|
||||
*/
|
||||
class PathScurryPosix extends PathScurryBase {
|
||||
/**
|
||||
* separator for generating path strings
|
||||
*/
|
||||
sep = '/';
|
||||
constructor(cwd = process.cwd(), opts = {}) {
|
||||
const { nocase = false } = opts;
|
||||
super(cwd, external_path_.posix, '/', { ...opts, nocase });
|
||||
this.nocase = nocase;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
parseRootPath(_dir) {
|
||||
return '/';
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
newRoot(fs) {
|
||||
return new PathPosix(this.rootPath, IFDIR, undefined, this.roots, this.nocase, this.childrenCache(), { fs });
|
||||
}
|
||||
/**
|
||||
* Return true if the provided path string is an absolute path
|
||||
*/
|
||||
isAbsolute(p) {
|
||||
return p.startsWith('/');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@link PathScurryBase} implementation for Darwin (macOS) systems.
|
||||
*
|
||||
* Defaults to case-insensitive matching, uses `'/'` for generating path
|
||||
* strings.
|
||||
*
|
||||
* Uses {@link PathPosix} for Path objects.
|
||||
*/
|
||||
class PathScurryDarwin extends PathScurryPosix {
|
||||
constructor(cwd = process.cwd(), opts = {}) {
|
||||
const { nocase = true } = opts;
|
||||
super(cwd, { ...opts, nocase });
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Default {@link PathBase} implementation for the current platform.
|
||||
*
|
||||
* {@link PathWin32} on Windows systems, {@link PathPosix} on all others.
|
||||
*/
|
||||
const Path = process.platform === 'win32' ? PathWin32 : PathPosix;
|
||||
/**
|
||||
* Default {@link PathScurryBase} implementation for the current platform.
|
||||
*
|
||||
* {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on
|
||||
* Darwin (macOS) systems, {@link PathScurryPosix} on all others.
|
||||
*/
|
||||
const PathScurry = process.platform === 'win32'
|
||||
? PathScurryWin32
|
||||
: process.platform === 'darwin'
|
||||
? PathScurryDarwin
|
||||
: PathScurryPosix;
|
||||
//# sourceMappingURL=index.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/pattern.js
|
||||
// this is just a very light wrapper around 2 arrays with an offset index
|
||||
|
||||
const isPatternList = (pl) => pl.length >= 1;
|
||||
const isGlobList = (gl) => gl.length >= 1;
|
||||
/**
|
||||
* An immutable-ish view on an array of glob parts and their parsed
|
||||
* results
|
||||
*/
|
||||
class Pattern {
|
||||
#patternList;
|
||||
#globList;
|
||||
#index;
|
||||
length;
|
||||
#platform;
|
||||
#rest;
|
||||
#globString;
|
||||
#isDrive;
|
||||
#isUNC;
|
||||
#isAbsolute;
|
||||
#followGlobstar = true;
|
||||
constructor(patternList, globList, index, platform) {
|
||||
if (!isPatternList(patternList)) {
|
||||
throw new TypeError('empty pattern list');
|
||||
}
|
||||
if (!isGlobList(globList)) {
|
||||
throw new TypeError('empty glob list');
|
||||
}
|
||||
if (globList.length !== patternList.length) {
|
||||
throw new TypeError('mismatched pattern list and glob list lengths');
|
||||
}
|
||||
this.length = patternList.length;
|
||||
if (index < 0 || index >= this.length) {
|
||||
throw new TypeError('index out of range');
|
||||
}
|
||||
this.#patternList = patternList;
|
||||
this.#globList = globList;
|
||||
this.#index = index;
|
||||
this.#platform = platform;
|
||||
// normalize root entries of absolute patterns on initial creation.
|
||||
if (this.#index === 0) {
|
||||
// c: => ['c:/']
|
||||
// C:/ => ['C:/']
|
||||
// C:/x => ['C:/', 'x']
|
||||
// //host/share => ['//host/share/']
|
||||
// //host/share/ => ['//host/share/']
|
||||
// //host/share/x => ['//host/share/', 'x']
|
||||
// /etc => ['/', 'etc']
|
||||
// / => ['/']
|
||||
if (this.isUNC()) {
|
||||
// '' / '' / 'host' / 'share'
|
||||
const [p0, p1, p2, p3, ...prest] = this.#patternList;
|
||||
const [g0, g1, g2, g3, ...grest] = this.#globList;
|
||||
if (prest[0] === '') {
|
||||
// ends in /
|
||||
prest.shift();
|
||||
grest.shift();
|
||||
}
|
||||
const p = [p0, p1, p2, p3, ''].join('/');
|
||||
const g = [g0, g1, g2, g3, ''].join('/');
|
||||
this.#patternList = [p, ...prest];
|
||||
this.#globList = [g, ...grest];
|
||||
this.length = this.#patternList.length;
|
||||
}
|
||||
else if (this.isDrive() || this.isAbsolute()) {
|
||||
const [p1, ...prest] = this.#patternList;
|
||||
const [g1, ...grest] = this.#globList;
|
||||
if (prest[0] === '') {
|
||||
// ends in /
|
||||
prest.shift();
|
||||
grest.shift();
|
||||
}
|
||||
const p = p1 + '/';
|
||||
const g = g1 + '/';
|
||||
this.#patternList = [p, ...prest];
|
||||
this.#globList = [g, ...grest];
|
||||
this.length = this.#patternList.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The first entry in the parsed list of patterns
|
||||
*/
|
||||
pattern() {
|
||||
return this.#patternList[this.#index];
|
||||
}
|
||||
/**
|
||||
* true of if pattern() returns a string
|
||||
*/
|
||||
isString() {
|
||||
return typeof this.#patternList[this.#index] === 'string';
|
||||
}
|
||||
/**
|
||||
* true of if pattern() returns GLOBSTAR
|
||||
*/
|
||||
isGlobstar() {
|
||||
return this.#patternList[this.#index] === GLOBSTAR;
|
||||
}
|
||||
/**
|
||||
* true if pattern() returns a regexp
|
||||
*/
|
||||
isRegExp() {
|
||||
return this.#patternList[this.#index] instanceof RegExp;
|
||||
}
|
||||
/**
|
||||
* The /-joined set of glob parts that make up this pattern
|
||||
*/
|
||||
globString() {
|
||||
return (this.#globString =
|
||||
this.#globString ||
|
||||
(this.#index === 0
|
||||
? this.isAbsolute()
|
||||
? this.#globList[0] + this.#globList.slice(1).join('/')
|
||||
: this.#globList.join('/')
|
||||
: this.#globList.slice(this.#index).join('/')));
|
||||
}
|
||||
/**
|
||||
* true if there are more pattern parts after this one
|
||||
*/
|
||||
hasMore() {
|
||||
return this.length > this.#index + 1;
|
||||
}
|
||||
/**
|
||||
* The rest of the pattern after this part, or null if this is the end
|
||||
*/
|
||||
rest() {
|
||||
if (this.#rest !== undefined)
|
||||
return this.#rest;
|
||||
if (!this.hasMore())
|
||||
return (this.#rest = null);
|
||||
this.#rest = new Pattern(this.#patternList, this.#globList, this.#index + 1, this.#platform);
|
||||
this.#rest.#isAbsolute = this.#isAbsolute;
|
||||
this.#rest.#isUNC = this.#isUNC;
|
||||
this.#rest.#isDrive = this.#isDrive;
|
||||
return this.#rest;
|
||||
}
|
||||
/**
|
||||
* true if the pattern represents a //unc/path/ on windows
|
||||
*/
|
||||
isUNC() {
|
||||
const pl = this.#patternList;
|
||||
return this.#isUNC !== undefined
|
||||
? this.#isUNC
|
||||
: (this.#isUNC =
|
||||
this.#platform === 'win32' &&
|
||||
this.#index === 0 &&
|
||||
pl[0] === '' &&
|
||||
pl[1] === '' &&
|
||||
typeof pl[2] === 'string' &&
|
||||
!!pl[2] &&
|
||||
typeof pl[3] === 'string' &&
|
||||
!!pl[3]);
|
||||
}
|
||||
// pattern like C:/...
|
||||
// split = ['C:', ...]
|
||||
// XXX: would be nice to handle patterns like `c:*` to test the cwd
|
||||
// in c: for *, but I don't know of a way to even figure out what that
|
||||
// cwd is without actually chdir'ing into it?
|
||||
/**
|
||||
* True if the pattern starts with a drive letter on Windows
|
||||
*/
|
||||
isDrive() {
|
||||
const pl = this.#patternList;
|
||||
return this.#isDrive !== undefined
|
||||
? this.#isDrive
|
||||
: (this.#isDrive =
|
||||
this.#platform === 'win32' &&
|
||||
this.#index === 0 &&
|
||||
this.length > 1 &&
|
||||
typeof pl[0] === 'string' &&
|
||||
/^[a-z]:$/i.test(pl[0]));
|
||||
}
|
||||
// pattern = '/' or '/...' or '/x/...'
|
||||
// split = ['', ''] or ['', ...] or ['', 'x', ...]
|
||||
// Drive and UNC both considered absolute on windows
|
||||
/**
|
||||
* True if the pattern is rooted on an absolute path
|
||||
*/
|
||||
isAbsolute() {
|
||||
const pl = this.#patternList;
|
||||
return this.#isAbsolute !== undefined
|
||||
? this.#isAbsolute
|
||||
: (this.#isAbsolute =
|
||||
(pl[0] === '' && pl.length > 1) ||
|
||||
this.isDrive() ||
|
||||
this.isUNC());
|
||||
}
|
||||
/**
|
||||
* consume the root of the pattern, and return it
|
||||
*/
|
||||
root() {
|
||||
const p = this.#patternList[0];
|
||||
return typeof p === 'string' && this.isAbsolute() && this.#index === 0
|
||||
? p
|
||||
: '';
|
||||
}
|
||||
/**
|
||||
* Check to see if the current globstar pattern is allowed to follow
|
||||
* a symbolic link.
|
||||
*/
|
||||
checkFollowGlobstar() {
|
||||
return !(this.#index === 0 ||
|
||||
!this.isGlobstar() ||
|
||||
!this.#followGlobstar);
|
||||
}
|
||||
/**
|
||||
* Mark that the current globstar pattern is following a symbolic link
|
||||
*/
|
||||
markFollowGlobstar() {
|
||||
if (this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar)
|
||||
return false;
|
||||
this.#followGlobstar = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=pattern.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/ignore.js
|
||||
// give it a pattern, and it'll be able to tell you if
|
||||
// a given path should be ignored.
|
||||
// Ignoring a path ignores its children if the pattern ends in /**
|
||||
// Ignores are always parsed in dot:true mode
|
||||
|
||||
|
||||
const ignore_defaultPlatform = typeof process === 'object' &&
|
||||
process &&
|
||||
typeof process.platform === 'string'
|
||||
? process.platform
|
||||
: 'linux';
|
||||
/**
|
||||
* Class used to process ignored patterns
|
||||
*/
|
||||
class Ignore {
|
||||
relative;
|
||||
relativeChildren;
|
||||
absolute;
|
||||
absoluteChildren;
|
||||
constructor(ignored, { nobrace, nocase, noext, noglobstar, platform = ignore_defaultPlatform, }) {
|
||||
this.relative = [];
|
||||
this.absolute = [];
|
||||
this.relativeChildren = [];
|
||||
this.absoluteChildren = [];
|
||||
const mmopts = {
|
||||
dot: true,
|
||||
nobrace,
|
||||
nocase,
|
||||
noext,
|
||||
noglobstar,
|
||||
optimizationLevel: 2,
|
||||
platform,
|
||||
nocomment: true,
|
||||
nonegate: true,
|
||||
};
|
||||
// this is a little weird, but it gives us a clean set of optimized
|
||||
// minimatch matchers, without getting tripped up if one of them
|
||||
// ends in /** inside a brace section, and it's only inefficient at
|
||||
// the start of the walk, not along it.
|
||||
// It'd be nice if the Pattern class just had a .test() method, but
|
||||
// handling globstars is a bit of a pita, and that code already lives
|
||||
// in minimatch anyway.
|
||||
// Another way would be if maybe Minimatch could take its set/globParts
|
||||
// as an option, and then we could at least just use Pattern to test
|
||||
// for absolute-ness.
|
||||
// Yet another way, Minimatch could take an array of glob strings, and
|
||||
// a cwd option, and do the right thing.
|
||||
for (const ign of ignored) {
|
||||
const mm = new Minimatch(ign, mmopts);
|
||||
for (let i = 0; i < mm.set.length; i++) {
|
||||
const parsed = mm.set[i];
|
||||
const globParts = mm.globParts[i];
|
||||
/* c8 ignore start */
|
||||
if (!parsed || !globParts) {
|
||||
throw new Error('invalid pattern object');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
const p = new Pattern(parsed, globParts, 0, platform);
|
||||
const m = new Minimatch(p.globString(), mmopts);
|
||||
const children = globParts[globParts.length - 1] === '**';
|
||||
const absolute = p.isAbsolute();
|
||||
if (absolute)
|
||||
this.absolute.push(m);
|
||||
else
|
||||
this.relative.push(m);
|
||||
if (children) {
|
||||
if (absolute)
|
||||
this.absoluteChildren.push(m);
|
||||
else
|
||||
this.relativeChildren.push(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ignored(p) {
|
||||
const fullpath = p.fullpath();
|
||||
const fullpaths = `${fullpath}/`;
|
||||
const relative = p.relative() || '.';
|
||||
const relatives = `${relative}/`;
|
||||
for (const m of this.relative) {
|
||||
if (m.match(relative) || m.match(relatives))
|
||||
return true;
|
||||
}
|
||||
for (const m of this.absolute) {
|
||||
if (m.match(fullpath) || m.match(fullpaths))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
childrenIgnored(p) {
|
||||
const fullpath = p.fullpath() + '/';
|
||||
const relative = (p.relative() || '.') + '/';
|
||||
for (const m of this.relativeChildren) {
|
||||
if (m.match(relative))
|
||||
return true;
|
||||
}
|
||||
for (const m of this.absoluteChildren) {
|
||||
if (m.match(fullpath))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ignore.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/processor.js
|
||||
// synchronous utility for filtering entries and calculating subwalks
|
||||
|
||||
/**
|
||||
* A cache of which patterns have been processed for a given Path
|
||||
*/
|
||||
class HasWalkedCache {
|
||||
store;
|
||||
constructor(store = new Map()) {
|
||||
this.store = store;
|
||||
}
|
||||
copy() {
|
||||
return new HasWalkedCache(new Map(this.store));
|
||||
}
|
||||
hasWalked(target, pattern) {
|
||||
return this.store.get(target.fullpath())?.has(pattern.globString());
|
||||
}
|
||||
storeWalked(target, pattern) {
|
||||
const fullpath = target.fullpath();
|
||||
const cached = this.store.get(fullpath);
|
||||
if (cached)
|
||||
cached.add(pattern.globString());
|
||||
else
|
||||
this.store.set(fullpath, new Set([pattern.globString()]));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A record of which paths have been matched in a given walk step,
|
||||
* and whether they only are considered a match if they are a directory,
|
||||
* and whether their absolute or relative path should be returned.
|
||||
*/
|
||||
class MatchRecord {
|
||||
store = new Map();
|
||||
add(target, absolute, ifDir) {
|
||||
const n = (absolute ? 2 : 0) | (ifDir ? 1 : 0);
|
||||
const current = this.store.get(target);
|
||||
this.store.set(target, current === undefined ? n : n & current);
|
||||
}
|
||||
// match, absolute, ifdir
|
||||
entries() {
|
||||
return [...this.store.entries()].map(([path, n]) => [
|
||||
path,
|
||||
!!(n & 2),
|
||||
!!(n & 1),
|
||||
]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A collection of patterns that must be processed in a subsequent step
|
||||
* for a given path.
|
||||
*/
|
||||
class SubWalks {
|
||||
store = new Map();
|
||||
add(target, pattern) {
|
||||
if (!target.canReaddir()) {
|
||||
return;
|
||||
}
|
||||
const subs = this.store.get(target);
|
||||
if (subs) {
|
||||
if (!subs.find(p => p.globString() === pattern.globString())) {
|
||||
subs.push(pattern);
|
||||
}
|
||||
}
|
||||
else
|
||||
this.store.set(target, [pattern]);
|
||||
}
|
||||
get(target) {
|
||||
const subs = this.store.get(target);
|
||||
/* c8 ignore start */
|
||||
if (!subs) {
|
||||
throw new Error('attempting to walk unknown path');
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return subs;
|
||||
}
|
||||
entries() {
|
||||
return this.keys().map(k => [k, this.store.get(k)]);
|
||||
}
|
||||
keys() {
|
||||
return [...this.store.keys()].filter(t => t.canReaddir());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The class that processes patterns for a given path.
|
||||
*
|
||||
* Handles child entry filtering, and determining whether a path's
|
||||
* directory contents must be read.
|
||||
*/
|
||||
class Processor {
|
||||
hasWalkedCache;
|
||||
matches = new MatchRecord();
|
||||
subwalks = new SubWalks();
|
||||
patterns;
|
||||
follow;
|
||||
dot;
|
||||
opts;
|
||||
constructor(opts, hasWalkedCache) {
|
||||
this.opts = opts;
|
||||
this.follow = !!opts.follow;
|
||||
this.dot = !!opts.dot;
|
||||
this.hasWalkedCache = hasWalkedCache
|
||||
? hasWalkedCache.copy()
|
||||
: new HasWalkedCache();
|
||||
}
|
||||
processPatterns(target, patterns) {
|
||||
this.patterns = patterns;
|
||||
const processingSet = patterns.map(p => [target, p]);
|
||||
// map of paths to the magic-starting subwalks they need to walk
|
||||
// first item in patterns is the filter
|
||||
for (let [t, pattern] of processingSet) {
|
||||
this.hasWalkedCache.storeWalked(t, pattern);
|
||||
const root = pattern.root();
|
||||
const absolute = pattern.isAbsolute() && this.opts.absolute !== false;
|
||||
// start absolute patterns at root
|
||||
if (root) {
|
||||
t = t.resolve(root === '/' && this.opts.root !== undefined
|
||||
? this.opts.root
|
||||
: root);
|
||||
const rest = pattern.rest();
|
||||
if (!rest) {
|
||||
this.matches.add(t, true, false);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pattern = rest;
|
||||
}
|
||||
}
|
||||
if (t.isENOENT())
|
||||
continue;
|
||||
let p;
|
||||
let rest;
|
||||
let changed = false;
|
||||
while (typeof (p = pattern.pattern()) === 'string' &&
|
||||
(rest = pattern.rest())) {
|
||||
const c = t.resolve(p);
|
||||
t = c;
|
||||
pattern = rest;
|
||||
changed = true;
|
||||
}
|
||||
p = pattern.pattern();
|
||||
rest = pattern.rest();
|
||||
if (changed) {
|
||||
if (this.hasWalkedCache.hasWalked(t, pattern))
|
||||
continue;
|
||||
this.hasWalkedCache.storeWalked(t, pattern);
|
||||
}
|
||||
// now we have either a final string for a known entry,
|
||||
// more strings for an unknown entry,
|
||||
// or a pattern starting with magic, mounted on t.
|
||||
if (typeof p === 'string') {
|
||||
// must not be final entry, otherwise we would have
|
||||
// concatenated it earlier.
|
||||
const ifDir = p === '..' || p === '' || p === '.';
|
||||
this.matches.add(t.resolve(p), absolute, ifDir);
|
||||
continue;
|
||||
}
|
||||
else if (p === GLOBSTAR) {
|
||||
// if no rest, match and subwalk pattern
|
||||
// if rest, process rest and subwalk pattern
|
||||
// if it's a symlink, but we didn't get here by way of a
|
||||
// globstar match (meaning it's the first time THIS globstar
|
||||
// has traversed a symlink), then we follow it. Otherwise, stop.
|
||||
if (!t.isSymbolicLink() ||
|
||||
this.follow ||
|
||||
pattern.checkFollowGlobstar()) {
|
||||
this.subwalks.add(t, pattern);
|
||||
}
|
||||
const rp = rest?.pattern();
|
||||
const rrest = rest?.rest();
|
||||
if (!rest || ((rp === '' || rp === '.') && !rrest)) {
|
||||
// only HAS to be a dir if it ends in **/ or **/.
|
||||
// but ending in ** will match files as well.
|
||||
this.matches.add(t, absolute, rp === '' || rp === '.');
|
||||
}
|
||||
else {
|
||||
if (rp === '..') {
|
||||
// this would mean you're matching **/.. at the fs root,
|
||||
// and no thanks, I'm not gonna test that specific case.
|
||||
/* c8 ignore start */
|
||||
const tp = t.parent || t;
|
||||
/* c8 ignore stop */
|
||||
if (!rrest)
|
||||
this.matches.add(tp, absolute, true);
|
||||
else if (!this.hasWalkedCache.hasWalked(tp, rrest)) {
|
||||
this.subwalks.add(tp, rrest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (p instanceof RegExp) {
|
||||
this.subwalks.add(t, pattern);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
subwalkTargets() {
|
||||
return this.subwalks.keys();
|
||||
}
|
||||
child() {
|
||||
return new Processor(this.opts, this.hasWalkedCache);
|
||||
}
|
||||
// return a new Processor containing the subwalks for each
|
||||
// child entry, and a set of matches, and
|
||||
// a hasWalkedCache that's a copy of this one
|
||||
// then we're going to call
|
||||
filterEntries(parent, entries) {
|
||||
const patterns = this.subwalks.get(parent);
|
||||
// put matches and entry walks into the results processor
|
||||
const results = this.child();
|
||||
for (const e of entries) {
|
||||
for (const pattern of patterns) {
|
||||
const absolute = pattern.isAbsolute();
|
||||
const p = pattern.pattern();
|
||||
const rest = pattern.rest();
|
||||
if (p === GLOBSTAR) {
|
||||
results.testGlobstar(e, pattern, rest, absolute);
|
||||
}
|
||||
else if (p instanceof RegExp) {
|
||||
results.testRegExp(e, p, rest, absolute);
|
||||
}
|
||||
else {
|
||||
results.testString(e, p, rest, absolute);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
testGlobstar(e, pattern, rest, absolute) {
|
||||
if (this.dot || !e.name.startsWith('.')) {
|
||||
if (!pattern.hasMore()) {
|
||||
this.matches.add(e, absolute, false);
|
||||
}
|
||||
if (e.canReaddir()) {
|
||||
// if we're in follow mode or it's not a symlink, just keep
|
||||
// testing the same pattern. If there's more after the globstar,
|
||||
// then this symlink consumes the globstar. If not, then we can
|
||||
// follow at most ONE symlink along the way, so we mark it, which
|
||||
// also checks to ensure that it wasn't already marked.
|
||||
if (this.follow || !e.isSymbolicLink()) {
|
||||
this.subwalks.add(e, pattern);
|
||||
}
|
||||
else if (e.isSymbolicLink()) {
|
||||
if (rest && pattern.checkFollowGlobstar()) {
|
||||
this.subwalks.add(e, rest);
|
||||
}
|
||||
else if (pattern.markFollowGlobstar()) {
|
||||
this.subwalks.add(e, pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if the NEXT thing matches this entry, then also add
|
||||
// the rest.
|
||||
if (rest) {
|
||||
const rp = rest.pattern();
|
||||
if (typeof rp === 'string' &&
|
||||
// dots and empty were handled already
|
||||
rp !== '..' &&
|
||||
rp !== '' &&
|
||||
rp !== '.') {
|
||||
this.testString(e, rp, rest.rest(), absolute);
|
||||
}
|
||||
else if (rp === '..') {
|
||||
/* c8 ignore start */
|
||||
const ep = e.parent || e;
|
||||
/* c8 ignore stop */
|
||||
this.subwalks.add(ep, rest);
|
||||
}
|
||||
else if (rp instanceof RegExp) {
|
||||
this.testRegExp(e, rp, rest.rest(), absolute);
|
||||
}
|
||||
}
|
||||
}
|
||||
testRegExp(e, p, rest, absolute) {
|
||||
if (!p.test(e.name))
|
||||
return;
|
||||
if (!rest) {
|
||||
this.matches.add(e, absolute, false);
|
||||
}
|
||||
else {
|
||||
this.subwalks.add(e, rest);
|
||||
}
|
||||
}
|
||||
testString(e, p, rest, absolute) {
|
||||
// should never happen?
|
||||
if (!e.isNamed(p))
|
||||
return;
|
||||
if (!rest) {
|
||||
this.matches.add(e, absolute, false);
|
||||
}
|
||||
else {
|
||||
this.subwalks.add(e, rest);
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=processor.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/walker.js
|
||||
/**
|
||||
* Single-use utility classes to provide functionality to the {@link Glob}
|
||||
* methods.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
|
||||
|
||||
const makeIgnore = (ignore, opts) => typeof ignore === 'string'
|
||||
? new Ignore([ignore], opts)
|
||||
: Array.isArray(ignore)
|
||||
? new Ignore(ignore, opts)
|
||||
: ignore;
|
||||
/**
|
||||
* basic walking utilities that all the glob walker types use
|
||||
*/
|
||||
class GlobUtil {
|
||||
path;
|
||||
patterns;
|
||||
opts;
|
||||
seen = new Set();
|
||||
paused = false;
|
||||
aborted = false;
|
||||
#onResume = [];
|
||||
#ignore;
|
||||
#sep;
|
||||
signal;
|
||||
maxDepth;
|
||||
constructor(patterns, path, opts) {
|
||||
this.patterns = patterns;
|
||||
this.path = path;
|
||||
this.opts = opts;
|
||||
this.#sep = !opts.posix && opts.platform === 'win32' ? '\\' : '/';
|
||||
if (opts.ignore) {
|
||||
this.#ignore = makeIgnore(opts.ignore, opts);
|
||||
}
|
||||
// ignore, always set with maxDepth, but it's optional on the
|
||||
// GlobOptions type
|
||||
/* c8 ignore start */
|
||||
this.maxDepth = opts.maxDepth || Infinity;
|
||||
/* c8 ignore stop */
|
||||
if (opts.signal) {
|
||||
this.signal = opts.signal;
|
||||
this.signal.addEventListener('abort', () => {
|
||||
this.#onResume.length = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
#ignored(path) {
|
||||
return this.seen.has(path) || !!this.#ignore?.ignored?.(path);
|
||||
}
|
||||
#childrenIgnored(path) {
|
||||
return !!this.#ignore?.childrenIgnored?.(path);
|
||||
}
|
||||
// backpressure mechanism
|
||||
pause() {
|
||||
this.paused = true;
|
||||
}
|
||||
resume() {
|
||||
/* c8 ignore start */
|
||||
if (this.signal?.aborted)
|
||||
return;
|
||||
/* c8 ignore stop */
|
||||
this.paused = false;
|
||||
let fn = undefined;
|
||||
while (!this.paused && (fn = this.#onResume.shift())) {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
onResume(fn) {
|
||||
if (this.signal?.aborted)
|
||||
return;
|
||||
/* c8 ignore start */
|
||||
if (!this.paused) {
|
||||
fn();
|
||||
}
|
||||
else {
|
||||
/* c8 ignore stop */
|
||||
this.#onResume.push(fn);
|
||||
}
|
||||
}
|
||||
// do the requisite realpath/stat checking, and return the path
|
||||
// to add or undefined to filter it out.
|
||||
async matchCheck(e, ifDir) {
|
||||
if (ifDir && this.opts.nodir)
|
||||
return undefined;
|
||||
let rpc;
|
||||
if (this.opts.realpath) {
|
||||
rpc = e.realpathCached() || (await e.realpath());
|
||||
if (!rpc)
|
||||
return undefined;
|
||||
e = rpc;
|
||||
}
|
||||
const needStat = e.isUnknown() || this.opts.stat;
|
||||
return this.matchCheckTest(needStat ? await e.lstat() : e, ifDir);
|
||||
}
|
||||
matchCheckTest(e, ifDir) {
|
||||
return e &&
|
||||
(this.maxDepth === Infinity || e.depth() <= this.maxDepth) &&
|
||||
(!ifDir || e.canReaddir()) &&
|
||||
(!this.opts.nodir || !e.isDirectory()) &&
|
||||
!this.#ignored(e)
|
||||
? e
|
||||
: undefined;
|
||||
}
|
||||
matchCheckSync(e, ifDir) {
|
||||
if (ifDir && this.opts.nodir)
|
||||
return undefined;
|
||||
let rpc;
|
||||
if (this.opts.realpath) {
|
||||
rpc = e.realpathCached() || e.realpathSync();
|
||||
if (!rpc)
|
||||
return undefined;
|
||||
e = rpc;
|
||||
}
|
||||
const needStat = e.isUnknown() || this.opts.stat;
|
||||
return this.matchCheckTest(needStat ? e.lstatSync() : e, ifDir);
|
||||
}
|
||||
matchFinish(e, absolute) {
|
||||
if (this.#ignored(e))
|
||||
return;
|
||||
const abs = this.opts.absolute === undefined ? absolute : this.opts.absolute;
|
||||
this.seen.add(e);
|
||||
const mark = this.opts.mark && e.isDirectory() ? this.#sep : '';
|
||||
// ok, we have what we need!
|
||||
if (this.opts.withFileTypes) {
|
||||
this.matchEmit(e);
|
||||
}
|
||||
else if (abs) {
|
||||
const abs = this.opts.posix ? e.fullpathPosix() : e.fullpath();
|
||||
this.matchEmit(abs + mark);
|
||||
}
|
||||
else {
|
||||
const rel = this.opts.posix ? e.relativePosix() : e.relative();
|
||||
const pre = this.opts.dotRelative && !rel.startsWith('..' + this.#sep)
|
||||
? '.' + this.#sep
|
||||
: '';
|
||||
this.matchEmit(!rel ? '.' + mark : pre + rel + mark);
|
||||
}
|
||||
}
|
||||
async match(e, absolute, ifDir) {
|
||||
const p = await this.matchCheck(e, ifDir);
|
||||
if (p)
|
||||
this.matchFinish(p, absolute);
|
||||
}
|
||||
matchSync(e, absolute, ifDir) {
|
||||
const p = this.matchCheckSync(e, ifDir);
|
||||
if (p)
|
||||
this.matchFinish(p, absolute);
|
||||
}
|
||||
walkCB(target, patterns, cb) {
|
||||
/* c8 ignore start */
|
||||
if (this.signal?.aborted)
|
||||
cb();
|
||||
/* c8 ignore stop */
|
||||
this.walkCB2(target, patterns, new Processor(this.opts), cb);
|
||||
}
|
||||
walkCB2(target, patterns, processor, cb) {
|
||||
if (this.#childrenIgnored(target))
|
||||
return cb();
|
||||
if (this.signal?.aborted)
|
||||
cb();
|
||||
if (this.paused) {
|
||||
this.onResume(() => this.walkCB2(target, patterns, processor, cb));
|
||||
return;
|
||||
}
|
||||
processor.processPatterns(target, patterns);
|
||||
// done processing. all of the above is sync, can be abstracted out.
|
||||
// subwalks is a map of paths to the entry filters they need
|
||||
// matches is a map of paths to [absolute, ifDir] tuples.
|
||||
let tasks = 1;
|
||||
const next = () => {
|
||||
if (--tasks === 0)
|
||||
cb();
|
||||
};
|
||||
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
||||
if (this.#ignored(m))
|
||||
continue;
|
||||
tasks++;
|
||||
this.match(m, absolute, ifDir).then(() => next());
|
||||
}
|
||||
for (const t of processor.subwalkTargets()) {
|
||||
if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) {
|
||||
continue;
|
||||
}
|
||||
tasks++;
|
||||
const childrenCached = t.readdirCached();
|
||||
if (t.calledReaddir())
|
||||
this.walkCB3(t, childrenCached, processor, next);
|
||||
else {
|
||||
t.readdirCB((_, entries) => this.walkCB3(t, entries, processor, next), true);
|
||||
}
|
||||
}
|
||||
next();
|
||||
}
|
||||
walkCB3(target, entries, processor, cb) {
|
||||
processor = processor.filterEntries(target, entries);
|
||||
let tasks = 1;
|
||||
const next = () => {
|
||||
if (--tasks === 0)
|
||||
cb();
|
||||
};
|
||||
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
||||
if (this.#ignored(m))
|
||||
continue;
|
||||
tasks++;
|
||||
this.match(m, absolute, ifDir).then(() => next());
|
||||
}
|
||||
for (const [target, patterns] of processor.subwalks.entries()) {
|
||||
tasks++;
|
||||
this.walkCB2(target, patterns, processor.child(), next);
|
||||
}
|
||||
next();
|
||||
}
|
||||
walkCBSync(target, patterns, cb) {
|
||||
/* c8 ignore start */
|
||||
if (this.signal?.aborted)
|
||||
cb();
|
||||
/* c8 ignore stop */
|
||||
this.walkCB2Sync(target, patterns, new Processor(this.opts), cb);
|
||||
}
|
||||
walkCB2Sync(target, patterns, processor, cb) {
|
||||
if (this.#childrenIgnored(target))
|
||||
return cb();
|
||||
if (this.signal?.aborted)
|
||||
cb();
|
||||
if (this.paused) {
|
||||
this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb));
|
||||
return;
|
||||
}
|
||||
processor.processPatterns(target, patterns);
|
||||
// done processing. all of the above is sync, can be abstracted out.
|
||||
// subwalks is a map of paths to the entry filters they need
|
||||
// matches is a map of paths to [absolute, ifDir] tuples.
|
||||
let tasks = 1;
|
||||
const next = () => {
|
||||
if (--tasks === 0)
|
||||
cb();
|
||||
};
|
||||
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
||||
if (this.#ignored(m))
|
||||
continue;
|
||||
this.matchSync(m, absolute, ifDir);
|
||||
}
|
||||
for (const t of processor.subwalkTargets()) {
|
||||
if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) {
|
||||
continue;
|
||||
}
|
||||
tasks++;
|
||||
const children = t.readdirSync();
|
||||
this.walkCB3Sync(t, children, processor, next);
|
||||
}
|
||||
next();
|
||||
}
|
||||
walkCB3Sync(target, entries, processor, cb) {
|
||||
processor = processor.filterEntries(target, entries);
|
||||
let tasks = 1;
|
||||
const next = () => {
|
||||
if (--tasks === 0)
|
||||
cb();
|
||||
};
|
||||
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
||||
if (this.#ignored(m))
|
||||
continue;
|
||||
this.matchSync(m, absolute, ifDir);
|
||||
}
|
||||
for (const [target, patterns] of processor.subwalks.entries()) {
|
||||
tasks++;
|
||||
this.walkCB2Sync(target, patterns, processor.child(), next);
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
class GlobWalker extends GlobUtil {
|
||||
matches;
|
||||
constructor(patterns, path, opts) {
|
||||
super(patterns, path, opts);
|
||||
this.matches = new Set();
|
||||
}
|
||||
matchEmit(e) {
|
||||
this.matches.add(e);
|
||||
}
|
||||
async walk() {
|
||||
if (this.signal?.aborted)
|
||||
throw this.signal.reason;
|
||||
if (this.path.isUnknown()) {
|
||||
await this.path.lstat();
|
||||
}
|
||||
await new Promise((res, rej) => {
|
||||
this.walkCB(this.path, this.patterns, () => {
|
||||
if (this.signal?.aborted) {
|
||||
rej(this.signal.reason);
|
||||
}
|
||||
else {
|
||||
res(this.matches);
|
||||
}
|
||||
});
|
||||
});
|
||||
return this.matches;
|
||||
}
|
||||
walkSync() {
|
||||
if (this.signal?.aborted)
|
||||
throw this.signal.reason;
|
||||
if (this.path.isUnknown()) {
|
||||
this.path.lstatSync();
|
||||
}
|
||||
// nothing for the callback to do, because this never pauses
|
||||
this.walkCBSync(this.path, this.patterns, () => {
|
||||
if (this.signal?.aborted)
|
||||
throw this.signal.reason;
|
||||
});
|
||||
return this.matches;
|
||||
}
|
||||
}
|
||||
class GlobStream extends GlobUtil {
|
||||
results;
|
||||
constructor(patterns, path, opts) {
|
||||
super(patterns, path, opts);
|
||||
this.results = new Minipass({
|
||||
signal: this.signal,
|
||||
objectMode: true,
|
||||
});
|
||||
this.results.on('drain', () => this.resume());
|
||||
this.results.on('resume', () => this.resume());
|
||||
}
|
||||
matchEmit(e) {
|
||||
this.results.write(e);
|
||||
if (!this.results.flowing)
|
||||
this.pause();
|
||||
}
|
||||
stream() {
|
||||
const target = this.path;
|
||||
if (target.isUnknown()) {
|
||||
target.lstat().then(() => {
|
||||
this.walkCB(target, this.patterns, () => this.results.end());
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.walkCB(target, this.patterns, () => this.results.end());
|
||||
}
|
||||
return this.results;
|
||||
}
|
||||
streamSync() {
|
||||
if (this.path.isUnknown()) {
|
||||
this.path.lstatSync();
|
||||
}
|
||||
this.walkCBSync(this.path, this.patterns, () => this.results.end());
|
||||
return this.results;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=walker.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/glob.js
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// if no process global, just call it linux.
|
||||
// so we default to case-sensitive, / separators
|
||||
const glob_defaultPlatform = typeof process === 'object' &&
|
||||
process &&
|
||||
typeof process.platform === 'string'
|
||||
? process.platform
|
||||
: 'linux';
|
||||
/**
|
||||
* An object that can perform glob pattern traversals.
|
||||
*/
|
||||
class Glob {
|
||||
absolute;
|
||||
cwd;
|
||||
root;
|
||||
dot;
|
||||
dotRelative;
|
||||
follow;
|
||||
ignore;
|
||||
magicalBraces;
|
||||
mark;
|
||||
matchBase;
|
||||
maxDepth;
|
||||
nobrace;
|
||||
nocase;
|
||||
nodir;
|
||||
noext;
|
||||
noglobstar;
|
||||
pattern;
|
||||
platform;
|
||||
realpath;
|
||||
scurry;
|
||||
stat;
|
||||
signal;
|
||||
windowsPathsNoEscape;
|
||||
withFileTypes;
|
||||
/**
|
||||
* The options provided to the constructor.
|
||||
*/
|
||||
opts;
|
||||
/**
|
||||
* An array of parsed immutable {@link Pattern} objects.
|
||||
*/
|
||||
patterns;
|
||||
/**
|
||||
* All options are stored as properties on the `Glob` object.
|
||||
*
|
||||
* See {@link GlobOptions} for full options descriptions.
|
||||
*
|
||||
* Note that a previous `Glob` object can be passed as the
|
||||
* `GlobOptions` to another `Glob` instantiation to re-use settings
|
||||
* and caches with a new pattern.
|
||||
*
|
||||
* Traversal functions can be called multiple times to run the walk
|
||||
* again.
|
||||
*/
|
||||
constructor(pattern, opts) {
|
||||
/* c8 ignore start */
|
||||
if (!opts)
|
||||
throw new TypeError('glob options required');
|
||||
/* c8 ignore stop */
|
||||
this.withFileTypes = !!opts.withFileTypes;
|
||||
this.signal = opts.signal;
|
||||
this.follow = !!opts.follow;
|
||||
this.dot = !!opts.dot;
|
||||
this.dotRelative = !!opts.dotRelative;
|
||||
this.nodir = !!opts.nodir;
|
||||
this.mark = !!opts.mark;
|
||||
if (!opts.cwd) {
|
||||
this.cwd = '';
|
||||
}
|
||||
else if (opts.cwd instanceof URL || opts.cwd.startsWith('file://')) {
|
||||
opts.cwd = (0,external_url_.fileURLToPath)(opts.cwd);
|
||||
}
|
||||
this.cwd = opts.cwd || '';
|
||||
this.root = opts.root;
|
||||
this.magicalBraces = !!opts.magicalBraces;
|
||||
this.nobrace = !!opts.nobrace;
|
||||
this.noext = !!opts.noext;
|
||||
this.realpath = !!opts.realpath;
|
||||
this.absolute = opts.absolute;
|
||||
this.noglobstar = !!opts.noglobstar;
|
||||
this.matchBase = !!opts.matchBase;
|
||||
this.maxDepth =
|
||||
typeof opts.maxDepth === 'number' ? opts.maxDepth : Infinity;
|
||||
this.stat = !!opts.stat;
|
||||
this.ignore = opts.ignore;
|
||||
if (this.withFileTypes && this.absolute !== undefined) {
|
||||
throw new Error('cannot set absolute and withFileTypes:true');
|
||||
}
|
||||
if (typeof pattern === 'string') {
|
||||
pattern = [pattern];
|
||||
}
|
||||
this.windowsPathsNoEscape =
|
||||
!!opts.windowsPathsNoEscape ||
|
||||
opts.allowWindowsEscape === false;
|
||||
if (this.windowsPathsNoEscape) {
|
||||
pattern = pattern.map(p => p.replace(/\\/g, '/'));
|
||||
}
|
||||
if (this.matchBase) {
|
||||
if (opts.noglobstar) {
|
||||
throw new TypeError('base matching requires globstar');
|
||||
}
|
||||
pattern = pattern.map(p => (p.includes('/') ? p : `./**/${p}`));
|
||||
}
|
||||
this.pattern = pattern;
|
||||
this.platform = opts.platform || glob_defaultPlatform;
|
||||
this.opts = { ...opts, platform: this.platform };
|
||||
if (opts.scurry) {
|
||||
this.scurry = opts.scurry;
|
||||
if (opts.nocase !== undefined &&
|
||||
opts.nocase !== opts.scurry.nocase) {
|
||||
throw new Error('nocase option contradicts provided scurry option');
|
||||
}
|
||||
}
|
||||
else {
|
||||
const Scurry = opts.platform === 'win32'
|
||||
? PathScurryWin32
|
||||
: opts.platform === 'darwin'
|
||||
? PathScurryDarwin
|
||||
: opts.platform
|
||||
? PathScurryPosix
|
||||
: PathScurry;
|
||||
this.scurry = new Scurry(this.cwd, {
|
||||
nocase: opts.nocase,
|
||||
fs: opts.fs,
|
||||
});
|
||||
}
|
||||
this.nocase = this.scurry.nocase;
|
||||
// If you do nocase:true on a case-sensitive file system, then
|
||||
// we need to use regexps instead of strings for non-magic
|
||||
// path portions, because statting `aBc` won't return results
|
||||
// for the file `AbC` for example.
|
||||
const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32';
|
||||
const mmo = {
|
||||
// default nocase based on platform
|
||||
...opts,
|
||||
dot: this.dot,
|
||||
matchBase: this.matchBase,
|
||||
nobrace: this.nobrace,
|
||||
nocase: this.nocase,
|
||||
nocaseMagicOnly,
|
||||
nocomment: true,
|
||||
noext: this.noext,
|
||||
nonegate: true,
|
||||
optimizationLevel: 2,
|
||||
platform: this.platform,
|
||||
windowsPathsNoEscape: this.windowsPathsNoEscape,
|
||||
debug: !!this.opts.debug,
|
||||
};
|
||||
const mms = this.pattern.map(p => new Minimatch(p, mmo));
|
||||
const [matchSet, globParts] = mms.reduce((set, m) => {
|
||||
set[0].push(...m.set);
|
||||
set[1].push(...m.globParts);
|
||||
return set;
|
||||
}, [[], []]);
|
||||
this.patterns = matchSet.map((set, i) => {
|
||||
const g = globParts[i];
|
||||
/* c8 ignore start */
|
||||
if (!g)
|
||||
throw new Error('invalid pattern object');
|
||||
/* c8 ignore stop */
|
||||
return new Pattern(set, g, 0, this.platform);
|
||||
});
|
||||
}
|
||||
async walk() {
|
||||
// Walkers always return array of Path objects, so we just have to
|
||||
// coerce them into the right shape. It will have already called
|
||||
// realpath() if the option was set to do so, so we know that's cached.
|
||||
// start out knowing the cwd, at least
|
||||
return [
|
||||
...(await new GlobWalker(this.patterns, this.scurry.cwd, {
|
||||
...this.opts,
|
||||
maxDepth: this.maxDepth !== Infinity
|
||||
? this.maxDepth + this.scurry.cwd.depth()
|
||||
: Infinity,
|
||||
platform: this.platform,
|
||||
nocase: this.nocase,
|
||||
}).walk()),
|
||||
];
|
||||
}
|
||||
walkSync() {
|
||||
return [
|
||||
...new GlobWalker(this.patterns, this.scurry.cwd, {
|
||||
...this.opts,
|
||||
maxDepth: this.maxDepth !== Infinity
|
||||
? this.maxDepth + this.scurry.cwd.depth()
|
||||
: Infinity,
|
||||
platform: this.platform,
|
||||
nocase: this.nocase,
|
||||
}).walkSync(),
|
||||
];
|
||||
}
|
||||
stream() {
|
||||
return new GlobStream(this.patterns, this.scurry.cwd, {
|
||||
...this.opts,
|
||||
maxDepth: this.maxDepth !== Infinity
|
||||
? this.maxDepth + this.scurry.cwd.depth()
|
||||
: Infinity,
|
||||
platform: this.platform,
|
||||
nocase: this.nocase,
|
||||
}).stream();
|
||||
}
|
||||
streamSync() {
|
||||
return new GlobStream(this.patterns, this.scurry.cwd, {
|
||||
...this.opts,
|
||||
maxDepth: this.maxDepth !== Infinity
|
||||
? this.maxDepth + this.scurry.cwd.depth()
|
||||
: Infinity,
|
||||
platform: this.platform,
|
||||
nocase: this.nocase,
|
||||
}).streamSync();
|
||||
}
|
||||
/**
|
||||
* Default sync iteration function. Returns a Generator that
|
||||
* iterates over the results.
|
||||
*/
|
||||
iterateSync() {
|
||||
return this.streamSync()[Symbol.iterator]();
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.iterateSync();
|
||||
}
|
||||
/**
|
||||
* Default async iteration function. Returns an AsyncGenerator that
|
||||
* iterates over the results.
|
||||
*/
|
||||
iterate() {
|
||||
return this.stream()[Symbol.asyncIterator]();
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.iterate();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=glob.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/has-magic.js
|
||||
|
||||
/**
|
||||
* Return true if the patterns provided contain any magic glob characters,
|
||||
* given the options provided.
|
||||
*
|
||||
* Brace expansion is not considered "magic" unless the `magicalBraces` option
|
||||
* is set, as brace expansion just turns one string into an array of strings.
|
||||
* So a pattern like `'x{a,b}y'` would return `false`, because `'xay'` and
|
||||
* `'xby'` both do not contain any magic glob characters, and it's treated the
|
||||
* same as if you had called it on `['xay', 'xby']`. When `magicalBraces:true`
|
||||
* is in the options, brace expansion _is_ treated as a pattern having magic.
|
||||
*/
|
||||
const hasMagic = (pattern, options = {}) => {
|
||||
if (!Array.isArray(pattern)) {
|
||||
pattern = [pattern];
|
||||
}
|
||||
for (const p of pattern) {
|
||||
if (new Minimatch(p, options).hasMagic())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
//# sourceMappingURL=has-magic.js.map
|
||||
;// CONCATENATED MODULE: ./node_modules/glob/dist/esm/index.js
|
||||
|
||||
|
||||
|
||||
function globStreamSync(pattern, options = {}) {
|
||||
return new Glob(pattern, options).streamSync();
|
||||
}
|
||||
function globStream(pattern, options = {}) {
|
||||
return new Glob(pattern, options).stream();
|
||||
}
|
||||
function globSync(pattern, options = {}) {
|
||||
return new Glob(pattern, options).walkSync();
|
||||
}
|
||||
async function glob_(pattern, options = {}) {
|
||||
return new Glob(pattern, options).walk();
|
||||
}
|
||||
function globIterateSync(pattern, options = {}) {
|
||||
return new Glob(pattern, options).iterateSync();
|
||||
}
|
||||
function globIterate(pattern, options = {}) {
|
||||
return new Glob(pattern, options).iterate();
|
||||
}
|
||||
// aliases: glob.sync.stream() glob.stream.sync() glob.sync() etc
|
||||
const streamSync = globStreamSync;
|
||||
const stream = Object.assign(globStream, { sync: globStreamSync });
|
||||
const iterateSync = globIterateSync;
|
||||
const iterate = Object.assign(globIterate, {
|
||||
sync: globIterateSync,
|
||||
});
|
||||
const sync = Object.assign(globSync, {
|
||||
stream: globStreamSync,
|
||||
iterate: globIterateSync,
|
||||
});
|
||||
/* c8 ignore start */
|
||||
|
||||
|
||||
|
||||
/* c8 ignore stop */
|
||||
const glob = Object.assign(glob_, {
|
||||
glob: glob_,
|
||||
globSync,
|
||||
sync,
|
||||
globStream,
|
||||
stream,
|
||||
globStreamSync,
|
||||
streamSync,
|
||||
globIterate,
|
||||
iterate,
|
||||
globIterateSync,
|
||||
iterateSync,
|
||||
Glob: Glob,
|
||||
hasMagic: hasMagic,
|
||||
escape: escape_escape,
|
||||
unescape: unescape_unescape,
|
||||
});
|
||||
glob.glob = glob;
|
||||
//# sourceMappingURL=index.js.map
|
||||
// EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js
|
||||
var core = __nccwpck_require__(2186);
|
||||
// EXTERNAL MODULE: ./node_modules/gitea-api/dist/index.js
|
||||
var dist = __nccwpck_require__(5371);
|
||||
;// CONCATENATED MODULE: ./main.js
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33024,19 +40896,19 @@ var __webpack_exports__ = {};
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
const server_url = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("server_url")
|
||||
const name = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("name")
|
||||
const body = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("body")
|
||||
const tag_name = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("tag_name")
|
||||
const draft = Boolean(_actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("draft"))
|
||||
const prerelease = Boolean(_actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("prerelease"))
|
||||
const files = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("files")
|
||||
const repository = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("repository")
|
||||
const token = _actions_core__WEBPACK_IMPORTED_MODULE_2__.getInput("token")
|
||||
const server_url = core.getInput("server_url")
|
||||
const name = core.getInput("name")
|
||||
const body = core.getInput("body")
|
||||
const tag_name = core.getInput("tag_name")
|
||||
const draft = Boolean(core.getInput("draft"))
|
||||
const prerelease = Boolean(core.getInput("prerelease"))
|
||||
const files = core.getInput("files")
|
||||
const repository = core.getInput("repository")
|
||||
const token = core.getInput("token")
|
||||
|
||||
const [owner, repo] = (repository).split("/")
|
||||
|
||||
const gitea_client = new gitea_api__WEBPACK_IMPORTED_MODULE_3__/* .GiteaApi */ .D9({
|
||||
const gitea_client = new dist/* GiteaApi */.D9({
|
||||
BASE: `${server_url}/api/v1`,
|
||||
WITH_CREDENTIALS: true,
|
||||
TOKEN: token,
|
||||
@@ -33058,7 +40930,7 @@ async function run() {
|
||||
console.log(`🎉 Release ready at ${response.html_url}`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
_actions_core__WEBPACK_IMPORTED_MODULE_2__.setFailed(error.message);
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33079,7 +40951,7 @@ async function createOrGetRelease(client, owner, repo, body) {
|
||||
})
|
||||
return release
|
||||
} catch (error) {
|
||||
if (!(error instanceof gitea_api__WEBPACK_IMPORTED_MODULE_3__/* .ApiError */ .MS) || error.status !== 404) {
|
||||
if (!(error instanceof dist/* ApiError */.MS) || error.status !== 404) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -33099,7 +40971,7 @@ async function createOrGetRelease(client, owner, repo, body) {
|
||||
function paths(patterns) {
|
||||
return patterns.reduce((acc, pattern) => {
|
||||
return acc.concat(
|
||||
glob.sync(pattern).filter((path) => statSync(path).isFile())
|
||||
sync(pattern).filter((path) => statSync(path).isFile())
|
||||
);
|
||||
}, []);
|
||||
};
|
||||
@@ -33120,7 +40992,7 @@ async function uploadFiles(client, owner, repo, release_id, all_files) {
|
||||
})
|
||||
for (const filepath in all_files) {
|
||||
for (const attachment in attachments) {
|
||||
if (attachment.name === path__WEBPACK_IMPORTED_MODULE_4__.basename(filepath)) {
|
||||
if (attachment.name === external_path_.basename(filepath)) {
|
||||
await client.repository.repoDeleteReleaseAttachment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
@@ -33129,14 +41001,14 @@ async function uploadFiles(client, owner, repo, release_id, all_files) {
|
||||
})
|
||||
console.log(`Successfully deleted old release attachment ${attachment.name}`)
|
||||
}
|
||||
const content = fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(filepath);
|
||||
const blob = new buffer__WEBPACK_IMPORTED_MODULE_1__.Blob([content]);
|
||||
const content = external_fs_.readFileSync(filepath);
|
||||
const blob = new external_buffer_.Blob([content]);
|
||||
await client.repository.repoCreateReleaseAttachment({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
id: release_id,
|
||||
attachment: blob,
|
||||
name: path__WEBPACK_IMPORTED_MODULE_4__.basename(filepath),
|
||||
name: external_path_.basename(filepath),
|
||||
})
|
||||
console.log(`Successfully uploaded release attachment ${filepath}`)
|
||||
}
|
||||
|
||||
1
main.js
1
main.js
@@ -1,5 +1,6 @@
|
||||
import fs from "fs";
|
||||
import { Blob } from "buffer";
|
||||
import * as glob from "glob";
|
||||
|
||||
import core from "@actions/core";
|
||||
|
||||
|
||||
437
package-lock.json
generated
437
package-lock.json
generated
@@ -11,7 +11,8 @@
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^6.0.0",
|
||||
"gitea-api": "^1.17.3-1"
|
||||
"gitea-api": "^1.17.3-1",
|
||||
"glob": "^10.3.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.38.1"
|
||||
@@ -54,6 +55,22 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
"strip-ansi": "^7.0.1",
|
||||
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
|
||||
"wrap-ansi": "^8.1.0",
|
||||
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
|
||||
@@ -172,6 +189,15 @@
|
||||
"@octokit/openapi-types": "^19.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.38.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz",
|
||||
@@ -181,21 +207,191 @@
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
||||
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"signal-exit": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/gitea-api": {
|
||||
"version": "1.17.3-1",
|
||||
"resolved": "https://registry.npmjs.org/gitea-api/-/gitea-api-1.17.3-1.tgz",
|
||||
"integrity": "sha512-Tj2s8feRRXfO4k6MmPyxa0JDDFG+VMifchc6gchzob+puFJErIIWkElQgum8JYT9sLsAFzHE/IFcMUx0ctlAhQ=="
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.3.10",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
|
||||
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^2.3.5",
|
||||
"minimatch": "^9.0.1",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
|
||||
"path-scurry": "^1.10.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||
},
|
||||
"node_modules/jackspeak": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
|
||||
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz",
|
||||
"integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==",
|
||||
"engines": {
|
||||
"node": "14 || >=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
|
||||
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@@ -204,6 +400,147 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
|
||||
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^9.1.1 || ^10.0.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||
"dependencies": {
|
||||
"eastasianwidth": "^0.2.0",
|
||||
"emoji-regex": "^9.2.2",
|
||||
"strip-ansi": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs": {
|
||||
"name": "string-width",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi-cjs": {
|
||||
"name": "strip-ansi",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
@@ -236,6 +573,104 @@
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.1.0",
|
||||
"string-width": "^5.0.1",
|
||||
"strip-ansi": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs": {
|
||||
"name": "wrap-ansi",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/github": "^6.0.0",
|
||||
"gitea-api": "^1.17.3-1"
|
||||
"gitea-api": "^1.17.3-1",
|
||||
"glob": "^10.3.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.38.1"
|
||||
|
||||
Reference in New Issue
Block a user