insta-toc
Version:
Simultaneously generate, update, and maintain a table of contents for your notes in real time.
165 lines (164 loc) • 24.8 kB
JavaScript
var N=Object.defineProperty;var ue=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var pe=Object.prototype.hasOwnProperty;var he=(a,n)=>{for(var t in n)N(a,t,{get:n[t],enumerable:!0})},fe=(a,n,t,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of ge(n))!pe.call(a,i)&&i!==t&&N(a,i,{get:()=>n[i],enumerable:!(e=ue(n,i))||e.enumerable});return a};var me=a=>fe(N({},"__esModule",{value:!0}),a);var Ce={};he(Ce,{default:()=>C});module.exports=me(Ce);var w=require("obsidian");var H="insta-toc",X=/^(\s*)(-|\d+(?:\.\d+)*|\d\.)\s+(.*)/,O=/\[\[([^\]]+)\|([^\]]+)\]\]/g,B=/\[\[([^\]\|]+)\]\]/g,F=/\[([^\]]+)\]\([^)]+\)/g,Z=/(#)([/\-_\w][^\s]*)/g;var A=/-{3}\n([\s\S]*)\n-{3}/,U={dash:"dash",number:"number"},D=["*","_","`","==","~~","{","}","#","\\"],ee={onlyCommonKeys:!1,onlyUniversalKeys:!1,skipCommonKeys:!1,skipUniversalKeys:!1,dedupArrays:!0,sortArrays:!0};function te(){return{title:{name:C.getGlobalSetting("tocTitle")??"Table of Contents",level:1,center:!1},exclude:"",style:{listType:C.getGlobalSetting("bulletType")??U.dash},omit:[],levels:{min:1,max:6}}}function G(...a){let n={};return a.forEach((t=>{t.forEach((e=>{n[e]=e in n?++n[e]:1}))})),n}function ye(...a){return a.reduce(((n,t)=>n.filter(Set.prototype.has,new Set(t))))}function ve(...a){let n=G(...a);return Object.keys(n).filter((t=>n[t]>1))}function Te(...a){let n=G(...a);return Object.keys(n).filter((t=>n[t]<a.length))}function be(...a){let n=G(...a);return Object.keys(n).filter((t=>n[t]===1))}function xe(a,n=!1){let t=Object.getOwnPropertyNames(a);if(n)for(let e in a)!t.includes(e)&&t.push(e);return t}function j(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)}function ne(a){if(!j(a))return!1;let n=["writable","enumerable","configurable"].some((s=>s in a)),t=["get","set"].some((s=>typeof a[s]=="function")),e=["get","set"].every((s=>s in a)),i="value"in a&&n||t&&(e||n);if(i){let s=["configurable","get","set","enumerable","value","writable"];i=Object.keys(a).some((o=>!(o in s)))}return i}var k={onlyKeys:[],skipKeys:[],onlyCommonKeys:!1,onlyUniversalKeys:!1,skipCommonKeys:!1,skipUniversalKeys:!1,invokeGetters:!1,skipSetters:!1,appendArrays:!1,prependArrays:!1,dedupArrays:!1,sortArrays:!1,hoistEnumerable:!1,hoistProto:!1,skipProto:!1,filter:Function.prototype,beforeEach:Function.prototype,afterEach:Function.prototype,onCircular:Function.prototype};function z(a,...n){let t=arguments.length===1?arguments[0]:{},e={...k,...t},i=new Map,s=new Map,o=typeof e.sortArrays=="function"?e.sortArrays:void 0,c=new WeakMap,d=0;function y(f){return xe(f,e.hoistEnumerable)}function T(...f){let h;f.length>1&&(e.onlyCommonKeys?h=ve(...f.map((l=>y(l)))):e.onlyUniversalKeys?h=ye(...f.map((l=>y(l)))):e.skipCommonKeys?h=be(...f.map((l=>y(l)))):e.skipUniversalKeys&&(h=Te(...f.map((l=>y(l)))))),!h&&e.onlyKeys.length&&(h=e.onlyKeys),h&&h!==e.onlyKeys&&e.onlyKeys.length&&(h=h.filter((l=>e.onlyKeys.includes(l))));let E=f.reduce(((l,u)=>{c.set(u,l);let v=h||y(u);e.skipKeys.length&&(v=v.filter((b=>e.skipKeys.indexOf(b)===-1)));for(let b=0;b<v.length;b++){let g=v[b],S=l[g],m={configurable:!0,enumerable:!0};if(!(g in u))continue;let I=!1,r=u[g],L=Object.getOwnPropertyDescriptor(u,g);if(L&&typeof L.set=="function"&&typeof L.get!="function"){e.skipSetters||Object.defineProperty(l,g,L);continue}if(e.filter!==k.filter){let p=e.filter({depth:d,key:g,srcObj:u,srcVal:r,targetObj:l,targetVal:S});if(p!==void 0&&!p)continue}if(e.beforeEach!==k.beforeEach){let p=e.beforeEach({depth:d,key:g,srcObj:u,srcVal:r,targetObj:l,targetVal:S});p!==void 0&&(I=!0,r=p)}if(typeof r=="object"&&r!==null&&c.has(u[g])){let p=e.onCircular({depth:d,key:g,srcObj:u,srcVal:u[g],targetObj:l,targetVal:S});if(p===void 0){r=c.get(u[g]),l[g]=r;continue}I=!0,r=p}if(Array.isArray(r)){if(r=[...r],Array.isArray(S)&&(e.appendArrays?r=[...S,...r]:e.prependArrays&&(r=[...r,...S])),e.dedupArrays)if(e.afterEach!==k.afterEach)r=[...new Set(r)];else{let p=i.get(l);p&&!p.includes(g)?p.push(g):i.set(l,[g])}if(e.sortArrays)if(e.afterEach!==k.afterEach)r=r.sort(o);else{let p=s.get(l);p&&!p.includes(g)?p.push(g):s.set(l,[g])}}else r instanceof Date?r=new Date(r):j(r)&&(!I||!ne(r))&&(d++,j(S)?r=T(S,r):r=T(r),d--);if(e.afterEach!==k.afterEach){let p=e.afterEach({depth:d,key:g,mergeVal:r,srcObj:u,targetObj:l});p!==void 0&&(I=!0,r=p)}if(I){let p=ne(r)?r:{configurable:!0,enumerable:!0,value:r,writable:!0};Object.defineProperty(l,g,p);continue}if(L){let{configurable:p,enumerable:ce,get:J,set:Q,writable:de}=L;Object.assign(m,{configurable:p,enumerable:ce}),typeof J=="function"&&(e.invokeGetters?m.value=r:m.get=J),!e.skipSetters&&typeof Q=="function"&&!Object.hasOwnProperty.call(m,"value")&&(m.set=Q),!m.get&&!m.set&&(m.writable=!!de)}!m.get&&!m.set&&!("value"in m)&&(m.value=r,m.writable=L&&"writable"in L?L.writable:!0),Object.defineProperty(l,g,m)}return l}),{});for(let[l,u]of i.entries())for(let v of u){let b=Object.getOwnPropertyDescriptor(l,v),{configurable:g,enumerable:S,writable:m}=b;Object.defineProperty(l,v,{configurable:g,enumerable:S,value:[...new Set(l[v])],writable:m!==void 0?m:!0})}for(let[l,u]of s.entries())for(let v of u)l[v].sort(o);let P=E;if(!e.skipProto){let l=f.reduce(((u,v)=>{let b=Object.getPrototypeOf(v);return b&&b!==Object.prototype&&u.push(b),u}),[]);if(l.length){let u=T(...l);e.hoistProto?P=T(u,E):P=Object.create(u,Object.getOwnPropertyDescriptors(E))}}return P}return arguments.length===1?function(...f){return arguments.length===1?z({...e,...f[0]}):T(...f)}:T(...arguments)}var _={bulletType:"dash",indentSize:2,updateDelay:2e3,tocTitle:"Table of Contents",excludedHeadingLevels:[],excludedHeadingText:[],excludedChars:D};var x=require("obsidian");var R=class extends x.PluginSettingTab{constructor(n,t){super(n,t),this.plugin=t}display(){let{containerEl:n}=this;n.empty();let t=new x.Setting(n).setHeading().setName("Insta ToC Global Settings");t.nameEl.classList.add("setting-title"),t.controlEl.remove(),new x.Setting(n).setName("List bullet style").setDesc("Select the global list bullet type.").addDropdown((e=>e.addOptions(U).setValue(this.plugin.settings.bulletType).onChange((async i=>{this.plugin.settings.bulletType=i,await this.plugin.saveSettings()})))),new x.Setting(n).setName("Indentation width").setDesc("Select the global indentation size.").addSlider((e=>e.setLimits(2,8,2).setDynamicTooltip().setInstant(!0).setValue(this.plugin.settings.indentSize).onChange((async i=>{this.plugin.settings.indentSize=i,await this.plugin.saveSettings()})))),new x.Setting(n).setName("Update delay").setDesc("The delay for each ToC update.").addSlider((e=>{e.setLimits(500,1e4,500).setDynamicTooltip().setInstant(!0).setValue(this.plugin.settings.updateDelay).onChange((async i=>{this.plugin.settings.updateDelay=i,await this.plugin.saveSettings(),this.plugin.updateModifyEventListener()}))})),new x.Setting(n).setName("ToC Title").setDesc("The global title for the Table of Contents.").addText((e=>{e.setValue(this.plugin.settings.tocTitle).onChange((async i=>{this.plugin.settings.tocTitle=i,await this.plugin.saveSettings()})),e.inputEl.placeholder="Table of Contents"})).infoEl.classList.add("insta-toc-text-info"),new x.Setting(n).setName("Excluded heading text").setDesc("Comma-separated list of headings to exclude globally within the Table of Contents.").addTextArea((e=>{e.setValue(this.plugin.settings.excludedHeadingText.join(",")).onChange((async i=>{let s=e.getValue(),o=[...this.plugin.settings.excludedHeadingText].concat(s.replace(/^,/,"").replace(/,$/,"").split(",").map((c=>c.trim())));this.plugin.settings.excludedHeadingText=[...o],await this.plugin.saveSettings()})),e.inputEl.placeholder="Table of Contents,Introduction,Side Note",e.inputEl.classList.add("insta-toc-text-area")})).infoEl.classList.add("insta-toc-text-info"),new x.Setting(n).setName("Excluded heading levels").setDesc("Comma-separated list of heading levels to exclude globally within the Table of Contents.").setTooltip("Valid values are 1-6.").addTextArea((e=>{e.setValue(this.plugin.settings.excludedHeadingLevels.join(",")).onChange((async i=>{let o=e.getValue().replace(/^,/,"").replace(/,$/,"").split(",").map((c=>parseInt(c.trim()))).filter((c=>c>0&&c<7));this.plugin.settings.excludedHeadingLevels=[...o],await this.plugin.saveSettings()})),e.inputEl.classList.add("insta-toc-text-area"),e.inputEl.placeholder="1,2,3,4,5,6"})).infoEl.classList.add("insta-toc-text-info"),new x.Setting(n).setName("Excluded characters").setDesc("Globally excluded heading characters.").addTextArea((e=>{e.setValue([...new Set(this.plugin.settings.excludedChars)].join(",")).onChange((async i=>{let s=e.getValue(),o=new Set([...s.trim().replace(/^,/,"").replace(/,$/,"").split(",").map((c=>c.trim())).filter((c=>c.length>0))]);this.plugin.settings.excludedChars=[...o],await this.plugin.saveSettings()})),e.inputEl.classList.add("exclude-chars"),e.inputEl.placeholder=D.join(",")})).infoEl.classList.add("insta-toc-text-info")}};var W=require("obsidian");var M=class{constructor(n,t){this.plugin=n,this.validator=t,this.headingLevelStack=[],this.updateAutoToc()}getIndentationLevel(n){for(;this.headingLevelStack.length>0&&n<=this.headingLevelStack[this.headingLevelStack.length-1];)this.headingLevelStack.pop();return this.headingLevelStack.push(n),this.headingLevelStack.length-1}generateNumberedToc(){let n=[],t={},e=this.validator.fileHeadings;for(let s of e){let o=s.level,c=s.heading;if(c.length===0)continue;let d=this.getIndentationLevel(o);t[d]||(t[d]=0);for(let h=d+1;h<=6;h++)t[h]=0;t[d]++;let y=" ".repeat(d*4),T=t[d].toString(),f=`${y}${T}. ${c}`;n.push(f)}return`\`\`\`${`${H}\n---\n${(0,W.stringifyYaml)(this.validator.localTocSettings)}---\n\n${"#".repeat(this.validator.localTocSettings.title.level)} ${this.validator.localTocSettings.title.center?"<center>"+this.validator.localTocSettings.title.name+"</center>":this.validator.localTocSettings.title.name}\n\n${n.join(`\n`)}`}\n\`\`\``}generateNormalToc(){let n=[],t=this.validator.fileHeadings;for(let i of t){let s=i.level,o=i.heading;if(o.length===0)continue;let c=this.getIndentationLevel(s),y=`${" ".repeat(c*4)}- ${o}`;n.push(y)}return`\`\`\`${`${H}\n---\n${(0,W.stringifyYaml)(this.validator.localTocSettings)}---\n\n${"#".repeat(this.validator.localTocSettings.title.level)} ${this.validator.localTocSettings.title.center?"<center>"+this.validator.localTocSettings.title.name+"</center>":this.validator.localTocSettings.title.name}\n\n${n.join(`\n`)}`}\n\`\`\``}updateAutoToc(){let n=this.validator.tocInsertPos,t=this.plugin.settings.bulletType!==this.validator.localTocSettings.style.listType?this.validator.localTocSettings.style.listType:this.plugin.settings.bulletType,e;switch(t){case"dash":e=this.generateNormalToc();break;case"number":e=this.generateNumberedToc();break;default:e=this.generateNormalToc();break}this.plugin.isPluginEdit=!0,this.validator.editor.replaceRange(e,n.from,n.to)}};var ie=require("obsidian");function se(a,n,t,e,i){let[,s,o,c]=e,{contentText:d,alias:y}=Se(n,c),T=a.fileManager.generateMarkdownLink(t,i,`#${d}`,y);return{indent:s,bullet:o,navLink:T}}function Se(a,n){let[t,e]=[n,n];return t=t.replace(O,((i,s,o)=>`${s} ${o}`)),e=e.replace(O,((i,s,o)=>o)),t=t.replace(B,((i,s)=>s.split("/").pop()??s)),e=e.replace(B,((i,s)=>s.split("/").pop()??s)),t=t.replace(F,((i,s)=>i)),e=e.replace(F,((i,s)=>s)),t=t.replace(Z,((i,s,o)=>o)),e=Le(e,a),{contentText:t,alias:e}}function Le(a,n,t){let e=(n?n.settings.excludedChars:t)??[],i=(0,ie.htmlToMarkdown)(a);for(let s of e)i=i.replaceAll(s,"");return i}function ae(a,n,t){a.querySelectorAll("li").forEach(((i,s)=>{n[s]>1&&(i.style.marginInlineStart=`${t*10}px`);let c=i.querySelector("ul, ol");if(c){let d=document.createElement("button");d.textContent="▾",d.classList.add("fold-toggle"),d.addEventListener("click",(()=>{c.style.display==="none"?(c.style.display="",d.textContent="▾"):(c.style.display="none",d.textContent="▸")})),i.prepend(d)}}))}function oe(a){let n=a.workspace.activeEditor?.editor,t=n?.getCursor();return{editor:n,cursorPos:t}}function q(a){return a.replace(/[.*+\-?^${}()|[\]\\]/g,"\\$&")}function le(a){return/^\/.*\/$/.test(a)}function V(a){return[1,2,3,4,5,6].includes(a)}function Y(a){return a&&typeof a=="object"&&!Array.isArray(a)}function $(a,n,t=!0){if(Y(a)&&Y(n))for(let e of Object.keys(n)){let i=a[e],s=n[e];Y(s)?(i||(a[e]={}),$(a[e],s)):Array.isArray(i)&&Array.isArray(s)&&t?a[e]=[...new Set(i.concat(s))]:a[e]=s}return a}var re=require("obsidian");var K=class{constructor(n,t,e,i){this.previousHeadings=[];this.plugin=n,this.metadata=t,this.editor=e,this.cursorPos=i,this.localTocSettings=te()}update(n,t,e,i){this.plugin=n,this.metadata=t,this.editor=e,this.cursorPos=i}haveHeadingsChanged(){let n=this.metadata.headings||[],t=this.previousHeadings.length===0,e=n.length!==this.previousHeadings.length;return(t||e?!1:n.every(((s,o)=>s.heading===this.previousHeadings[o].heading&&s.level===this.previousHeadings[o].level)))?!1:(this.previousHeadings=n,!0)}hasHeadingsAndSections(){return!!this.metadata&&!!this.metadata.headings&&!!this.metadata.sections}hasInstaTocSection(){if(!this.hasHeadingsAndSections())return!1;let n=this.metadata.sections.find((t=>t.type==="code"&&this.editor.getLine(t.position.start.line)===`\`\`\`${H}`));return n?(this.instaTocSection=n,!0):!1}setTocInsertPos(){let n=this.instaTocSection.position.start.line,t=0,e=this.instaTocSection.position.end.line,i=this.instaTocSection.position.end.col,s={line:n,ch:t},o={line:e,ch:i};this.tocInsertPos={from:s,to:o}}configureLocalSettings(){let t=this.editor.getRange(this.tocInsertPos.from,this.tocInsertPos.to).match(A);if(!t)return;let[,e]=t;this.validateLocalSettings(e)}validateLocalSettings(n){let t;try{t=(0,re.parseYaml)(n)}catch(i){this.localTocSettings=this.updatedLocalSettings||this.localTocSettings;let s=`Invalid YAML in insta-toc settings:\n`+i;console.error(s),new Notice(s);return}let e=[];if(t.title!==void 0){let i=t.title;if(typeof i!="object"||i===null)e.push("'title' must be an object.");else{let{name:s,level:o,center:c}=i;s!==void 0&&typeof s!="string"&&e.push("'title.name' must be a string indicating the title to be displayed on the ToC."),o!==void 0&&!V(o)&&e.push("'title.level' must be an integer between 1 and 6 indicating the heading level of the ToC title."),c!==void 0&&typeof c!="boolean"&&e.push("'title.center' must be a boolean indicating whether the title position should be centered.")}}if(t.exclude!==void 0&&typeof t.exclude!="string"&&e.push(`'exclude' must be a string ("...") containing each character to exclude, or a regex pattern (/.../).`),t.style!==void 0){let i=t.style;if(typeof i!="object"||i===null)e.push("'style' must be an object.");else{let{listType:s}=i;s!==void 0&&!["dash","number"].includes(s)&&e.push("'style.listType' must be 'dash' or 'number'.")}}if(t.omit!==void 0){if(!Array.isArray(t.omit))e.push("'omit' must be an array of strings indicating the text of each heading you'd like to omit.");else for(let i of t.omit)if(typeof i!="string"){e.push("'omit' array must contain only strings indicating the text of headings you'd like to omit.");break}}if(t.levels!==void 0){let i=t.levels;if(typeof i!="object"||i===null)e.push("'levels' must be an object.");else{let{min:s,max:o}=i;s!==void 0&&!V(s)&&e.push("'levels.min' must be an integer between 1 and 6 indicating the minimum heading level to include."),o!==void 0&&!V(o)&&e.push("'levels.max' must be an integer between 1 and 6 indicating the maximum heading level to include."),s!==void 0&&o!==void 0&&s>o&&e.push("'levels.min' cannot be greater than 'levels.max'.")}}if(e.length>0){let i=`Invalid properties in insta-toc settings:\n`+e.join(`\n`);console.error(i),new Notice(i),this.updatedLocalSettings=this.localTocSettings}else this.updatedLocalSettings?this.updatedLocalSettings=$(this.updatedLocalSettings,t,!1):this.updatedLocalSettings=$(this.localTocSettings,t,!0);this.localTocSettings=this.updatedLocalSettings}cursorInToc(){return this.cursorPos.line>=this.instaTocSection.position.start.line&&this.cursorPos.line<=this.instaTocSection.position.end.line}setFileHeadings(){this.metadata.headings&&(this.fileHeadings=this.metadata.headings.filter((n=>{let t=n.heading.trim(),e=n.level;return!t.match(/<!--\s*omit\s*-->/)&&!this.localTocSettings.omit.includes(t)&&e>=this.localTocSettings.levels.min&&e<=this.localTocSettings.levels.max&&t.trim().length>0&&!this.plugin.settings.excludedHeadingText.includes(t)&&!this.plugin.settings.excludedHeadingLevels.includes(e)})).map((n=>{let t=n.heading,e=[];if(this.plugin.settings.excludedChars&&this.plugin.settings.excludedChars.length>0){let i=this.plugin.settings.excludedChars.map((s=>q(s))).join("");i.length>0&&e.push(`[${i}]`)}if(this.localTocSettings.exclude&&this.localTocSettings.exclude.length>0){let i=this.localTocSettings.exclude;if(le(i)){let s=i.slice(1,-1);e.push(`(${s})`)}else{let s=q(i);s.length>0&&e.push(`[${s}]`)}}if(e.length>0){let i=new RegExp(e.join("|"),"g");t=t.replace(i,"")}return{...n,heading:t}})))}isValid(){return this.hasInstaTocSection()?this.haveHeadingsChanged()?(this.setTocInsertPos(),this.configureLocalSettings(),this.setFileHeadings(),!this.cursorInToc()):!1:(this.plugin.hasTocBlock=!1,!1)}};var C=class extends w.Plugin{constructor(t,e){super(t,e);this.isPluginEdit=!1;this.hasTocBlock=!0;this.getDelay=()=>this.settings.updateDelay;this.app=t}async onload(){console.log("Loading Insta TOC Plugin"),await this.loadSettings(),this.addSettingTab(new R(this.app,this)),this.registerMarkdownCodeBlockProcessor("insta-toc",(async(t,e,i)=>{this.hasTocBlock||(this.hasTocBlock=!0);let s=i.sourcePath,o=s.substring(0,s.lastIndexOf(".")),c=this.app.vault.getAbstractFileByPath(s),d=t.replace(A,"").split(`\n`),y=[],T=d.map((f=>{let h=f.match(X);if(!h)return f;let{indent:E,bullet:P,navLink:l}=se(this.app,this,c,h,o),v=Math.floor(E.length/4)+1;return y.push(v),`${E}${P} ${l}`})).join(`\n`);await w.MarkdownRenderer.render(this.app,T,e,s,this),ae(e,y,this.settings.indentSize)})),this.registerEvent(this.app.workspace.on("file-open",(()=>this.hasTocBlock=!0))),this.updateModifyEventListener()}onunload(){console.log("Insta TOC Plugin Unloaded.")}async loadSettings(){let t=_,e=await this.loadData();e&&(t=z(ee)(_,e)),this.settings=t}async saveSettings(){await this.saveData(this.settings)}updateModifyEventListener(){this.modifyEventRef&&this.app.metadataCache.offref(this.modifyEventRef),this.setDebouncer(),this.modifyEventRef=this.app.metadataCache.on("changed",((t,e,i)=>{this.hasTocBlock&&this.debouncer(i)})),this.registerEvent(this.modifyEventRef)}setDebouncer(){this.debouncer=(0,w.debounce)((t=>{if(this.isPluginEdit){this.isPluginEdit=!1;return}let{editor:e,cursorPos:i}=oe(this.app);if(!e||!i)return;this.validator?this.validator.update(this,t,e,i):this.validator=new K(this,t,e,i),this.validator.isValid()&&new M(this,this.validator)}),this.settings.updateDelay,!1)}static getGlobalSetting(t){return(window.app.plugins.getPlugin("insta-toc")?.settings)[t]}};
/*! Bundled license information:
mergician/dist/mergician.esm.js:
(*!
* mergician
* v2.0.2
* https://jhildenbiddle.github.io/mergician/
* (c) 2022-2024 John Hildenbiddle
* MIT license
*)
(**
* @typedef {Object} MergicianOptions
* @property {string[]} [onlyKeys] - Exclusive array of keys to be merged
* (others are skipped)
* @property {string[]} [skipKeys] - Array of keys to skip (others are
* merged)
* @property {boolean} [onlyCommonKeys=false] - Merge only keys found
* in multiple objects (ignore single occurrence keys)
* @property {boolean} [onlyUniversalKeys=false] - Merge only keys
* found in all objects
* @property {boolean} [skipCommonKeys=false] - Skip keys found in
* multiple objects (merge only single occurrence keys)
* @property {boolean} [skipUniversalKeys=false] - Skip keys found in
* all objects (merge only common keys)
* @property {boolean} [invokeGetters=false] - Invoke "getter" methods
* and merge returned values
* @property {boolean} [skipSetters=false] - Skip "setter" methods
* during merge
* @property {boolean} [appendArrays=false] - Merge array values at
* the end of existing arrays
* @property {boolean} [prependArrays=false] - Merge array values at
* the beginning of existing arrays
* @property {boolean} [dedupArrays=false] - Remove duplicate array
* values in new merged object
* @property {boolean|function} [sortArrays=false] - Sort array values
* in new merged object
* @property {boolean} [hoistEnumerable=false] - Merge enumerable
* prototype properties as direct properties of merged object
* @property {boolean} [hoistProto=false] - Merge custom prototype
* properties as direct properties of merged object
* @property {boolean} [skipProto=false] - Skip merging of custom
* prototype properties
* @property {filterCallback} [filter] - Callback used to conditionally merge
* or skip a property. Return a "truthy" value to merge or a "falsy" value to
* skip. Return no value to proceed according to other option values.
* @property {beforeEachCallback} [beforeEach] - Callback used for
* inspecting/modifying properties before merge. Return value is used as value
* to merge.
* @property {afterEachCallback} [afterEach] - Callback used for
* inspecting/modifying properties after merge. Return value is used as merged
* value.
* @property {onCircularCallback} [onCircular] - Callback used for handling
* circular object references during merge
* @preserve
*)
(**
* @callback filterCallback
* @param {callbackData} callbackData
* @preserve
*)
(**
* @callback beforeEachCallback
* @param {callbackData} callbackData
* @preserve
*)
(**
* @callback afterEachCallback
* @param {afterEachCallbackData} callbackData
* @preserve
*)
(**
* @callback onCircularCallback
* @param {callbackData} callbackData
* @preserve
*)
(**
* @typedef {Object} callbackData
* @property {number} depth - Nesting level of the key being processed
* @property {string} key - Object key being processed
* @property {object} srcObj - Object containing the source value
* @property {any} srcVal - Source object’s property value
* @property {object} targetObj - New merged object
* @property {any} targetVal - New merged object’s current property value
* @preserve
*)
(**
* @typedef {Object} afterEachCallbackData
* @property {number} depth - Nesting level of the key being processed
* @property {string} key - Object key being processed
* @property {any} mergeVal - New merged value
* @property {object} srcObj - Object containing the source value
* @property {object} targetObj - New merged object
* @preserve
*)
(**
* @description Deep (recursive) object merging with support for descriptor
* values, accessor functions, custom prototypes, and advanced options for
* customizing the merge process.
*
* @example
* // Custom merge options
* const mergedObj = mergician({
* // Options
* })(obj1, obj2, obj3);
*
* // Custom merge function
* const customMerge = mergician({
* // Options
* });
* const customMergeObj = customMerge(obj1, obj2, obj3);
*
* @overload
* @param {MergicianOptions} options
* @returns {function} New merge function with options set as defaults
* @preserve
*)
(**
* @description Deep (recursive) object merging with support for descriptor
* values, accessor functions, custom prototypes, and advanced options for
* customizing the merge process.
*
* @example
* // Clone with default options
* const clonedObj = mergician({}, obj1);
*
* // Merge with default options
* const mergedObj = mergician(obj1, obj2, obj3);
*
* @overload
* @param {...object} objects
* @returns {object} New merged object
* @preserve
*)
(**
* @description Deep (recursive) object merging with support for descriptor
* values, accessor functions, custom prototypes, and advanced options for
* customizing the merge process.
*
* @example
* // Clone with default options
* const clonedObj = mergician({}, obj1);
*
* // Merge with default options
* const mergedObj = mergician(obj1, obj2, obj3);
*
* @example
* // Custom merge options
* const mergedObj = mergician({
* // Options
* })(obj1, obj2, obj3);
*
* // Custom merge function
* const customMerge = mergician({
* // Options
* });
* const customMergeObj = customMerge(obj1, obj2, obj3);
*
* @param {MergicianOptions} optionsOrObject
* @param {...object} [objects]
* @returns {function|object} New merge function with options set as defaults
* (single argument) or new merged object (multiple arguments)
* @preserve
*)
*/