mirror of
https://github.com/arthur-pbty/portfolio2023.git
synced 2026-06-06 14:20:42 +02:00
310 lines
6.3 KiB
JavaScript
310 lines
6.3 KiB
JavaScript
const hasOwnProperty = require('has-own-prop')
|
|
const {isObject, isArray} = require('core-util-is')
|
|
|
|
const PREFIX_BEFORE = 'before'
|
|
const PREFIX_AFTER_PROP = 'after-prop'
|
|
const PREFIX_AFTER_COLON = 'after-colon'
|
|
const PREFIX_AFTER_VALUE = 'after-value'
|
|
|
|
const SYMBOL_PREFIXES = [
|
|
PREFIX_BEFORE,
|
|
PREFIX_AFTER_PROP,
|
|
PREFIX_AFTER_COLON,
|
|
PREFIX_AFTER_VALUE
|
|
]
|
|
|
|
const COLON = ':'
|
|
const UNDEFINED = undefined
|
|
|
|
const symbol = (prefix, key) => Symbol.for(prefix + COLON + key)
|
|
|
|
const assign_comments = (
|
|
target, source, target_key, source_key, prefix, remove_source
|
|
) => {
|
|
const source_prop = symbol(prefix, source_key)
|
|
if (!hasOwnProperty(source, source_prop)) {
|
|
return
|
|
}
|
|
|
|
const target_prop = target_key === source_key
|
|
? source_prop
|
|
: symbol(prefix, target_key)
|
|
|
|
target[target_prop] = source[source_prop]
|
|
|
|
if (remove_source) {
|
|
delete source[source_prop]
|
|
}
|
|
}
|
|
|
|
// Assign keys and comments
|
|
const assign = (target, source, keys) => {
|
|
keys.forEach(key => {
|
|
if (!hasOwnProperty(source, key)) {
|
|
return
|
|
}
|
|
|
|
target[key] = source[key]
|
|
SYMBOL_PREFIXES.forEach(prefix => {
|
|
assign_comments(target, source, key, key, prefix)
|
|
})
|
|
})
|
|
|
|
return target
|
|
}
|
|
|
|
const swap_comments = (array, from, to) => {
|
|
if (from === to) {
|
|
return
|
|
}
|
|
|
|
SYMBOL_PREFIXES.forEach(prefix => {
|
|
const target_prop = symbol(prefix, to)
|
|
if (!hasOwnProperty(array, target_prop)) {
|
|
assign_comments(array, array, to, from, prefix)
|
|
return
|
|
}
|
|
|
|
const comments = array[target_prop]
|
|
assign_comments(array, array, to, from, prefix)
|
|
array[symbol(prefix, from)] = comments
|
|
})
|
|
}
|
|
|
|
const reverse_comments = array => {
|
|
const {length} = array
|
|
let i = 0
|
|
const max = length / 2
|
|
|
|
for (; i < max; i ++) {
|
|
swap_comments(array, i, length - i - 1)
|
|
}
|
|
}
|
|
|
|
const move_comment = (target, source, i, offset, remove) => {
|
|
SYMBOL_PREFIXES.forEach(prefix => {
|
|
assign_comments(target, source, i + offset, i, prefix, remove)
|
|
})
|
|
}
|
|
|
|
const move_comments = (
|
|
// `Array` target array
|
|
target,
|
|
// `Array` source array
|
|
source,
|
|
// `number` start index
|
|
start,
|
|
// `number` number of indexes to move
|
|
count,
|
|
// `number` offset to move
|
|
offset,
|
|
// `boolean` whether should remove the comments from source
|
|
remove
|
|
) => {
|
|
if (offset > 0) {
|
|
let i = count
|
|
// | count | offset |
|
|
// source: -------------
|
|
// target: -------------
|
|
// | remove |
|
|
// => remove === offset
|
|
|
|
// From [count - 1, 0]
|
|
while (i -- > 0) {
|
|
move_comment(target, source, start + i, offset, remove && i < offset)
|
|
}
|
|
return
|
|
}
|
|
|
|
let i = 0
|
|
const min_remove = count + offset
|
|
// | remove | count |
|
|
// -------------
|
|
// -------------
|
|
// | offset |
|
|
|
|
// From [0, count - 1]
|
|
while (i < count) {
|
|
const ii = i ++
|
|
move_comment(target, source, start + ii, offset, remove && i >= min_remove)
|
|
}
|
|
}
|
|
|
|
class CommentArray extends Array {
|
|
// - deleteCount + items.length
|
|
|
|
// We should avoid `splice(begin, deleteCount, ...items)`,
|
|
// because `splice(0, undefined)` is not equivalent to `splice(0)`,
|
|
// as well as:
|
|
// - slice
|
|
splice (...args) {
|
|
const {length} = this
|
|
const ret = super.splice(...args)
|
|
|
|
// #16
|
|
// If no element removed, we might still need to move comments,
|
|
// because splice could add new items
|
|
|
|
// if (!ret.length) {
|
|
// return ret
|
|
// }
|
|
|
|
// JavaScript syntax is silly
|
|
// eslint-disable-next-line prefer-const
|
|
let [begin, deleteCount, ...items] = args
|
|
|
|
if (begin < 0) {
|
|
begin += length
|
|
}
|
|
|
|
if (arguments.length === 1) {
|
|
deleteCount = length - begin
|
|
} else {
|
|
deleteCount = Math.min(length - begin, deleteCount)
|
|
}
|
|
|
|
const {
|
|
length: item_length
|
|
} = items
|
|
|
|
// itemsToDelete: -
|
|
// itemsToAdd: +
|
|
// | dc | count |
|
|
// =======-------------============
|
|
// =======++++++============
|
|
// | il |
|
|
const offset = item_length - deleteCount
|
|
const start = begin + deleteCount
|
|
const count = length - start
|
|
|
|
move_comments(this, this, start, count, offset, true)
|
|
|
|
return ret
|
|
}
|
|
|
|
slice (...args) {
|
|
const {length} = this
|
|
const array = super.slice(...args)
|
|
if (!array.length) {
|
|
return new CommentArray()
|
|
}
|
|
|
|
let [begin, before] = args
|
|
|
|
// Ref:
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
|
|
if (before === UNDEFINED) {
|
|
before = length
|
|
} else if (before < 0) {
|
|
before += length
|
|
}
|
|
|
|
if (begin < 0) {
|
|
begin += length
|
|
} else if (begin === UNDEFINED) {
|
|
begin = 0
|
|
}
|
|
|
|
move_comments(array, this, begin, before - begin, - begin)
|
|
|
|
return array
|
|
}
|
|
|
|
unshift (...items) {
|
|
const {length} = this
|
|
const ret = super.unshift(...items)
|
|
const {
|
|
length: items_length
|
|
} = items
|
|
|
|
if (items_length > 0) {
|
|
move_comments(this, this, 0, length, items_length, true)
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
shift () {
|
|
const ret = super.shift()
|
|
const {length} = this
|
|
|
|
move_comments(this, this, 1, length, - 1, true)
|
|
|
|
return ret
|
|
}
|
|
|
|
reverse () {
|
|
super.reverse()
|
|
|
|
reverse_comments(this)
|
|
|
|
return this
|
|
}
|
|
|
|
pop () {
|
|
const ret = super.pop()
|
|
|
|
// Removes comments
|
|
const {length} = this
|
|
SYMBOL_PREFIXES.forEach(prefix => {
|
|
const prop = symbol(prefix, length)
|
|
delete this[prop]
|
|
})
|
|
|
|
return ret
|
|
}
|
|
|
|
concat (...items) {
|
|
let {length} = this
|
|
const ret = super.concat(...items)
|
|
|
|
if (!items.length) {
|
|
return ret
|
|
}
|
|
|
|
items.forEach(item => {
|
|
const prev = length
|
|
length += isArray(item)
|
|
? item.length
|
|
: 1
|
|
|
|
if (!(item instanceof CommentArray)) {
|
|
return
|
|
}
|
|
|
|
move_comments(ret, item, 0, item.length, prev)
|
|
})
|
|
|
|
return ret
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
CommentArray,
|
|
assign (target, source, keys) {
|
|
if (!isObject(target)) {
|
|
throw new TypeError('Cannot convert undefined or null to object')
|
|
}
|
|
|
|
if (!isObject(source)) {
|
|
return target
|
|
}
|
|
|
|
if (keys === UNDEFINED) {
|
|
keys = Object.keys(source)
|
|
} else if (!isArray(keys)) {
|
|
throw new TypeError('keys must be array or undefined')
|
|
}
|
|
|
|
return assign(target, source, keys)
|
|
},
|
|
|
|
PREFIX_BEFORE,
|
|
PREFIX_AFTER_PROP,
|
|
PREFIX_AFTER_COLON,
|
|
PREFIX_AFTER_VALUE,
|
|
|
|
COLON,
|
|
UNDEFINED
|
|
}
|