-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.js
More file actions
256 lines (210 loc) · 11.9 KB
/
Copy pathutil.js
File metadata and controls
256 lines (210 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
function arrPFC(fname, _this, ...args) { return Array.prototype[fname]?.apply(isMap(_this) ? Array.from(_this) : _this, args) }
function filter() { return arrPFC("filter", ...arguments) }
function each() { arrPFC("forEach", ...arguments) }
function map() { return arrPFC("map", ...arguments) }
function find() { return arrPFC("find", ...arguments) }
function any() { return arrPFC("some", ...arguments) }
function isAll() { return arrPFC("every", ...arguments) }
function slice() { return arrPFC("slice", ...arguments) }
function noop(_) { return _ }
function noopThis() { return this }
function ensureArr(_) { return Array.isArray(_) ? _ : [_] }
function slicePart(arr, n) { return slice(arr, ...n > 0 ? [0, n] : [n]) }
function findResult(arr, fn) { let res; arr.find(a => res = fn(a)); return res }
function rearrange(arr, from, splLen, to/*after!*/) { arr.splice((from < to ? to - splLen : to) + 1, 0, ...arr.splice(from, splLen)); return arr }
function permuteContly(arr, pMap = [[1, 3], [2, 4]]) {
if (pMap[0][0] > pMap[1][0]) pMap.sort()
for (let i = 0; i < pMap.length - 1; ++i) {
for (let j = i + 1; j < pMap.length; ++j) {
for (let k = 0; k < 2; ++k) {
if (pMap[j][k] <= pMap[i][1]) pMap[j][k] -= pMap[i][2] ?? 1
}
}
}
pMap.forEach(([from, to, splLen = 1]) => rearrange(arr, from, splLen, to))
return arr
}
Object.defineProperties(Array.prototype, {
noop: { value: noopThis },
rearrange: { value() { return rearrange.apply(this, [this, ...arguments]) } },
noNull: { get() { return this.filter(_ => typeof _ !== "undefined") } },
rmNull: { value() { return this.replaceWith(...this.noNull) } },
noHole: { get() { return this.filter(() => true) } }, // Remove empty slots
noFalsy: { get() { return this.filter(Boolean) } },
replaceWith: { value() { this.splice(0, Infinity, ...arguments); return this } }
})
let retOfSW2D
function sortingWeights(arr1, arr2, dim = 2) { sortingWeights._baseDArr[dim].find(i => (retOfSW2D = sortingWeights._baseExpr(arr1, arr2, i)) !== 0); return retOfSW2D }
sortingWeights._baseExpr = (arr1, arr2, i) => arr1[i] < arr2[i] ? -1 : arr1[i] > arr2[i] ? 1 : 0
sortingWeights._baseDArr = { 2: [0, 1] }
function takeInnermost(_, idx) { return Array.isArray(_.at(idx)) ? takeInnermost(_.at(idx)) : _ }
function extraWrap(_, idx) { return _.flatMap(_ => Array.isArray(_.at(idx)) ? _ : [_]) }
function addToArrInMap(map, key, ...vals) { vals.forEach(val => map.has(key) ? map.get(key).push(val) : map.set(key, [val])) }
Object.defineProperty(HTMLElement.prototype, "_childrenList", { get() { return Array.prototype.slice.call(this.children) } })
function isSym(_) { return typeof _ === "symbol" }
function isNum(_) { return !isNaN(_ - parseFloat(_)) }
function isStr(_) { return typeof _ === "string" }
function isObj(_) { return _ && typeof _ === "object" }
function isMap(_) { return ["Map", "Set"].includes(_[Symbol.toStringTag]) }
function isStrReg(str, validate = true) { return isObjReg(str) || isStr(str) && /^\/.+\/\w*$/.test(str) && (isObjReg(str = tryEval(str)) || !validate && str === Symbol.for("MalformedRegExp")) }
function isObjReg(obj) { return Object.prototype.toString.call(obj) === "[object RegExp]" && obj }
const parseInt_withFixedRadix = _ => parseInt(_)
function allStartWithNum() { return isAll(arguments, parseInt_withFixedRadix) }
Object.defineProperty(Number.prototype, "_toPrecision", { value(maximumFractionDigits) { return +this.toLocaleString("en", { maximumFractionDigits, useGrouping: false }) } })
// XXNG: "not generic"
const regs = {
metaChars: RegExp("[$()*+.?[\\]^{|}]", "g"),
comment: /\/\*(.*?)\*\//,
comment_pure: /^\s*\/\*.*?\*\//,
comment_inArrLit/*XXNG*/: /(?<=^ *\[ *)(\/\*.*?\*\/)(.*?)(,)$/m,
$rplc_inArrLit/*XXNG*/: /^ *".*"(?:, *Y)? *\],?$/m
}
function escChars(str) { return str.replace(regs.metaChars, "\\$&") }
function escapeSpecialXMLChars(str) { return str.replace(/[<>&]/g, _ => `&${{ "<": "lt", ">": "gt", "&": "amp" }[_]};`) }
function pullLeadingComment(str) { return isStr(str) && regs.comment_pure.test(str) ? str.match(regs.comment) : "" }
function passLeadingComment/*XXNG*/(str) { return regs.comment_inArrLit.test(str) ? str.match(regs.comment)[0] : "" }
function $str(str) {
return JSON.stringify(str, null, 2)
?.replace(/"@re: (.+)"/g, (_, $1) => `${stripBsl($1)}`)
.replace(/(?<=<(raw|f)>": )"(.+)"/g, (_, $1, $2) => `${$1 === "f" ? "``" : "String.raw"}\`${stripBsl($2)}\`${$1 === "f" ? "``" : ""}`.replaceAll(/\\[n"]/g, evalToStr))
}
$str._decodeFence = function (str) { return str.replace(/(<f>": )```(.*?)```/gs, (_, $1, $2) => `${$1}"${dblBsl($2).replaceAll(/[\n"]/g, _ => reReprJSONL[_])}"`) }
const reReprJSONL = { "\n": "\\n", "\"": `\\"` }
RegExp.prototype.toJSON = function () { return `@re: ${this}` }
RegExp.prototype.toString = function () { return `${this._comment_ || ""}/${this.source}/${this.flags}` }
function regAddFlagsMod(reg, add) { return RegExp(reg, regAddFlags(reg, add)) }
function regAddFlags(origFlags, add = "") { if (isObjReg(origFlags)) origFlags = origFlags.flags; return [...new Set([...`${origFlags}${add}`])].join("") }
Object.assign(RegExp.prototype, {
_CGIA /*capturing group in assertions (approximate)*/: RegExp(trimS(/(?<!\\) \( (?=\?(?!:))/.source)),
_inclCGIA() { return this._CGIA.test(this.source) }
})
function mergeObj() { return mergeObjOptIn(...slicePart(arguments, 2), { arrayAppend: true }) }
function mergeObjOptIn(toMe, give, { key: { ignore = null, trimSpaces = false, equivalentPart = null } = {}, arrayAppend = false } = {}) {
if (toMe && isObj(give)) {
const $keys = () => $keys._ ??= Object.keys(toMe)
const myKeys = trimSpaces ? new Set($keys().map(trimS)) : null;
[ignore, equivalentPart] = [ignore, equivalentPart].map(_ => isObjReg(_) || null)
const eqRplc = equivalentPart && (key => key.replace(equivalentPart, ""))
const eqKeys = equivalentPart && Object.fromEntries($keys().map(_ => [eqRplc(_), _]))
Object.entries(give).forEach(([k, v]) => {
eqKeys && (k = eqKeys[eqRplc(k)] ?? k)
arrayAppend && (Array.isArray(v) || Array.isArray(toMe[k]))
? toMe[k] = Array.from(new Set(ensureArr(toMe[k]).concat(v)))
: ignore?.test(k) || !(toMe.hasOwnProperty(k) || myKeys?.has(trimS(k)))
? toMe[k] = v
: isObj(v) && mergeObjOptIn(toMe[k], v, ...slicePart(arguments, -1))
})
}
return toMe
}
function sortKeys(obj) { let v; isObj(obj) && Object.keys(obj).sort(localeCompare).forEach(k => { v = obj[k]; delete obj[k]; obj[k] = v; sortKeys(v) }) }
function localeCompare(a, b) { if (!isStr(a)) [a, b] = [a, b].map(String); return a.localeCompare(b, undefined, { numeric: true/*No need to actively check `allStartWithNum(a, b)` at all*/ }) }
function reduceSpacesToTryKeys(obj, lPKN/*"longest possible key name"*/, finalCut = /\$.*/) {
let _lPKN
do {
if (obj.hasOwnProperty(lPKN)) return obj[lPKN]
lPKN = (_lPKN = lPKN).replace(" ", "")
} while (_lPKN !== lPKN)
if (isObjReg(finalCut)) return obj[lPKN.replace(finalCut, "")]
}
function dblBsl(str, { revert } = {}) { return str.replaceAll(...["\\", "\\\\"][revert ? "reverse" : "noop"]()) }
function quadBsl(str) { return dblBsl(dblBsl(str)) }
function stripBsl(str) { return dblBsl(str, { revert: true }) }
function escQq(str) { return str.replaceAll(`"`, `\\"`) }
function dB_eQ(str) { return escQq(dblBsl(str)) }
function ensureStr(str, _throw) { if (_throw && !isStr(str)) throw TypeError(`str is ${str}`); return isStr(str) ? str : "" }
function trimS(str) { return ensureStr(str, true).replaceAll(" ", "") }
function tryEval(str) { try { return eval(str) } catch (err) { return err.message === "nothing to repeat" ? Symbol.for("MalformedRegExp") : false } }
function fnOrStringify(fn) { const fnS = tryEval(fn); return typeof fnS === "function" ? fnS : `"${ensureStr(fn) && escQq(fn)}"` }
function evalToStr(str) { return eval(`"${str}"`) }
function objPathToLastProp(obj, prop) { return prop.includes(".") ? [prop.replace(/\.[^.]+$/, "").split(".").reduce((obj, key) => obj[key], obj), prop.match(/[^.]+$/)[0]] : [obj, prop] }
function buildObjPath(obj, topName = "", f) {
const $k = k => /^[\w$]+$/.test(k) ? `.${k}` : `['${k.replaceAll("'", "\\'")}']`
const seen = new WeakSet
return build(obj, topName)
function build(o, k = "") {
const _o = {}; let _k, isInnermost
Object.keys(o).forEach(_ => {
isInnermost = false
_k = `${k}${$k(_)}`
_o[_k] = isNum(_)
? undefined
: o[_] && typeof o[_] === "object" && !Array.isArray(o[_])
? !seen.has(o[_])
? (seen.add(o[_]), build(o[_], _k))
: undefined
: isInnermost = typeof o[_]
isInnermost && f?.(_, o[_], _k)
})
return _o
}
}
function convertInitFnToReinit(fn) { return new Function("return " + fn.toString().replace(RegExp(/\s*fn\s*=.*(?=\}$)/.source.replace("fn", fn.name), "s"), "\n").replaceAll("_init", "_reinit"))() }
function loadScript(src = "", { async = true } = {}) { return document.head.appendChild(Object.assign(document.createElement("script"), { src, async })) }
function downloadText(filename, text) { Object.assign(document.createElement("a"), { href: `data:text;charset=utf-8,${encodeURIComponent(text)}`, download: filename }).click() }
Object.defineProperties(Object.getPrototypeOf(localStorage), {
_getItem: { value(key) { return JSON.parse(this.getItem(key)) || {} } },
_setItem: { value(key, val) { this.setItem(key, JSON.stringify(val)) } }
})
function isFollowedByAnother(node, otherNode) { return node.compareDocumentPosition(otherNode) & Node.DOCUMENT_POSITION_FOLLOWING }
function moveElem(drag, drop) { drop[isFollowedByAnother(drop, drag) ? "before" : "after"](drag) }
function swapElems(drag, drop) {
if (swapElems._tmpDiv?.nodeType !== Node.ELEMENT_NODE) swapElems._tmpDiv = document.createElement("div")
drag.replaceWith(swapElems._tmpDiv)
drop.replaceWith(drag)
swapElems._tmpDiv.replaceWith(drop)
}
function prevent(e) { e.preventDefault() }
const theSel = getSelection()
function isLandscape() { return isLandscape._ = matchMedia("(orientation: landscape)").matches }
Object.defineProperty(window, "isTouchDevice", { get() { return matchMedia("(any-pointer: coarse)").matches } })
// -----------------------------------------------------------------------------
function throttle(func, timeFrame = 200) {
let lastTime = 0, now, calling, tId, _this, _arguments
function call(force) { if (typeof force === "boolean" && force || !_this?._suppressed) return func.apply(_this, _arguments) }
function delayedTrailingCall(force) { clearTimeout(tId); tId = setTimeout(call, timeFrame, force) }
return function (force) {
[_this, _arguments] = [this, arguments]
let ret
calling || _this?._suppressedForDelay || (now = Date.now()) - lastTime < timeFrame
? ret = delayedTrailingCall(force)
: (calling = true, ret = call(force), lastTime = now, calling = false)
return ret
}
}
function disposableMutObs(target, options = {}) {
(
disposableMutObs._obs = new MutationObserver(function ([mutation]) {
(disposableMutObs._obs.callback?.(mutation) ?? true) && this.disconnect()
})
).observe(target, options)
return _ => {
const { callback, ...props } = typeof _ === "function" ? { callback: _ } : _ || {}
return Object.assign(disposableMutObs._obs, { callback, ...props })
}
}
function delegate(obj, key, callback) {
return obj[key] = new Proxy(obj[key], {
set() {
Reflect.set(...arguments)
callback(...arguments)
return true
}
})
}
class fixedLengthArray extends Array {
constructor(fixedLength) {
super()
this._fixedLength = fixedLength
return new Proxy(this, {
get: function (target, prop) {
return typeof target[prop] === "function" ? fn.bind(target, target, prop) : Reflect.get(...arguments)
}
})
function fn(target, prop, ...args) {
const result = target[prop](...args)
if (target.length > target._fixedLength) target.replaceWith(...target.splice(-target._fixedLength))
return result
}
}
}