mokuji.js 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -174,6 +174,7 @@ Returns `undefined` if no headings are found.
|
|
|
174
174
|
anchorContainerTagName: 'ol',
|
|
175
175
|
minLevel: 1,
|
|
176
176
|
maxLevel: 6,
|
|
177
|
+
includeBlockquoteHeadings: false,
|
|
177
178
|
}
|
|
178
179
|
```
|
|
179
180
|
|
|
@@ -240,6 +241,24 @@ set the minimum heading level to include in the table of contents (1 means h1).
|
|
|
240
241
|
|
|
241
242
|
set the maximum heading level to include in the table of contents (6 means h6).
|
|
242
243
|
|
|
244
|
+
### `includeBlockquoteHeadings`
|
|
245
|
+
|
|
246
|
+
(default: `false`)
|
|
247
|
+
|
|
248
|
+
Whether to include headings inside `<blockquote>` elements in the table of contents.
|
|
249
|
+
|
|
250
|
+
By default, headings within blockquotes are excluded from the TOC since they typically represent quoted content rather than the document's own structure.
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
// Default: blockquote headings are excluded
|
|
254
|
+
const result = Mokuji(element);
|
|
255
|
+
|
|
256
|
+
// Include blockquote headings
|
|
257
|
+
const result = Mokuji(element, {
|
|
258
|
+
includeBlockquoteHeadings: true,
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
243
262
|
## License
|
|
244
263
|
|
|
245
264
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,11 @@ type MokujiOption = {
|
|
|
53
53
|
* Default: 6
|
|
54
54
|
*/
|
|
55
55
|
maxLevel?: HeadingLevel;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to include headings inside blockquote elements in TOC
|
|
58
|
+
* Default: false (blockquote headings are excluded)
|
|
59
|
+
*/
|
|
60
|
+
includeBlockquoteHeadings?: boolean;
|
|
56
61
|
};
|
|
57
62
|
//#endregion
|
|
58
63
|
//#region src/index.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=e=>[
|
|
1
|
+
const e=(e,t=1,n=6)=>{if(t>n)return[];let r=Array.from({length:n-t+1},(e,n)=>`h${t+n}`).join(`, `);return[...e.querySelectorAll(r)]},t=e=>document.createElement(e),n=e=>{for(let t of e)t.remove()},r=/\s+/g,i=/%+/g,a=/%[0-9A-F]{2}/i,o=/%[^0-9A-F]|%[0-9A-F][^0-9A-F]|%$/i,s=/_\d+$/,c=e=>e.replaceAll(r,`_`).replace(`:`,``),l=e=>encodeURIComponent(e).replaceAll(i,`.`),u=(e,t)=>{if(t){let t=c(e);return l(t)}return encodeURIComponent(e.trim())},d=e=>{if(!a.test(e)||o.test(e))return e;try{return decodeURIComponent(e)}catch{return e}},f=(e,t)=>{let n=e.getAttribute(`id`)?.trim();if(n)return e.id=n,n;let r=(e.textContent||``).trim(),i=u(r,t);return e.id=i,i},p=(e,t)=>{let n=new Set,r=new Map,i=new Set;for(let[t,n]of e.entries()){let e=n.id||`mokuji-heading-${t}`;i.add(d(e))}for(let[a,o]of e.entries()){let e=t[a],c=o.id||`mokuji-heading-${a}`,l=d(c);if(!n.has(l)){o.id=c,n.add(l),e&&(e.href=`#${c}`);continue}let u=l.replace(s,``)||l,f=(r.get(u)||0)+1;for(;n.has(`${u}_${f}`)||i.has(`${u}_${f}`);)f++;let p=`${u}_${f}`;r.set(u,f),o.id=p,n.add(p),e&&(e.href=`#${p}`)}},m=e=>{let t=Number.parseInt(e.tagName.slice(1),10);return t>=1&&t<=6?t:6},h=(t,n,r,i)=>{let a=i?.includeBlockquoteHeadings??!1,o=e(t,n,r);return a?o:o.filter(e=>!e.closest(`blockquote`))},g=`data-mokuji-anchor`,_={anchorType:!0,anchorLink:!1,anchorLinkSymbol:`#`,anchorLinkPosition:`before`,anchorLinkClassName:``,anchorContainerTagName:`ol`,minLevel:1,maxLevel:6,includeBlockquoteHeadings:!1},v=e=>{let t=new Map;for(let n of e)n.hash&&n.hash.length>1&&t.set(n.hash.slice(1),n);return t},y=e=>{let t=new Map;for(let n of e){let e=n.textContent?.trim();e&&t.set(e,n)}return t},b=(e,t)=>e.get(t),x=(e,t)=>{let n=t.replace(/_\d+$/,``);if(n!==t)return e.get(n)},S=(e,t)=>{let n=t.trim();if(n){for(let t of e.values())if(t.textContent?.trim()===n)return t}},C=(e,t)=>{let n=t.trim();if(n)return e.get(n)},w=(e,t,n,r)=>b(e,t)||x(e,t)||(r?C(r,n):S(e,n)),T=(e,t)=>{let n=t.trim();n&&e.classList.add(...n.split(/\s+/).filter(Boolean))},E=e=>{let n=t(`a`);return n.setAttribute(g,``),T(n,e.anchorLinkClassName),n},D=(e,t,n,r,i)=>{let a=e.id,o=w(t,a,e.textContent||``,i);if(!o)return;let s=n.cloneNode(!1);return s.href=o.hash,s.textContent=r.anchorLinkSymbol,s},O=e=>{let t=e.querySelectorAll(`[${g}]`);n(t)},k=(e,t,n=`before`)=>{n===`before`?e.insertBefore(t,e.firstChild):e.append(t)},A=(e,t,n,r)=>{let i=E(n),a=[];for(let o of e){O(o);let e=D(o,t,i,n,r);if(!e)continue;k(o,e,n.anchorLinkPosition),a.push(e)}return a},j=(e,t,n,r)=>A(e,t,r,n),M=(e,t)=>{let n=[],r=[{level:0,items:n}];for(let n of e){let e=m(n),i=f(n,t),a={text:n.textContent,href:`#${i}`,level:e,children:[]},o=r.at(-1);for(;r.length>1&&e<=o.level;)r.pop(),o=r.at(-1);o.items.push(a),r.push({level:e,items:a.children})}return n},N=(e,n)=>{let r=t(`li`),i=t(`a`),a=n.tagName.toLowerCase(),o=t(a),s=(e,t)=>{for(let n of t){let t=r.cloneNode(!1),a=i.cloneNode(!1);if(a.href=n.href,a.textContent=n.text,t.append(a),n.children.length>0){let e=o.cloneNode(!1);s(e,n.children),t.append(e)}e.append(t)}};s(n,e)},P=(e,t,n)=>{let r=M(e,n);N(r,t)},F=e=>{let t={..._,...e},n=Math.max(1,Math.min(t.minLevel,6)),r=Math.max(n,Math.min(t.maxLevel,6));return{...t,minLevel:n,maxLevel:r}},I=(e,n)=>{if(!e){console.warn(`Mokuji: Target element not found.`);return}let r=F(n),{minLevel:i,maxLevel:a,includeBlockquoteHeadings:o}=r,s=h(e,i,a,{includeBlockquoteHeadings:o});if(s.length===0)return;let c=t(r.anchorContainerTagName);c.setAttribute(`data-mokuji-list`,``),P(s,c,r.anchorType);let l=[...c.querySelectorAll(`a`)];if(l.length===0)return;p(s,l);let u=r.anchorLink?j(s,v(l),y(l),r):[];return{element:e,list:c,destroy:()=>{c.remove();for(let e of u)e.remove()}}};export{I as Mokuji};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["MIN_HEADING_LEVEL: HeadingLevel","MAX_HEADING_LEVEL: HeadingLevel","candidateId: string","filteredHeadings: HTMLHeadingElement[]","defaultOptions: Required<MokujiOption>","insertedAnchors: HTMLAnchorElement[]","rootLevelItems: TocItem[]","levelStack: { level: number; items: TocItem[] }[]","newItem: TocItem","insertedAnchors: HTMLAnchorElement[]"],"sources":["../src/utils/dom.ts","../src/heading.ts","../src/utils/constants.ts","../src/anchor.ts","../src/mokuji-core.ts","../src/index.ts"],"sourcesContent":["export const getAllHeadingElements = (containerElement: Element): HTMLHeadingElement[] => {\n const headings = containerElement.querySelectorAll('h1, h2, h3, h4, h5, h6');\n return [...headings] as HTMLHeadingElement[];\n};\n\nexport const createElement = <T extends keyof HTMLElementTagNameMap>(tagName: T): HTMLElementTagNameMap[T] => {\n return document.createElement(tagName);\n};\n\nexport const removeAllElements = (elements: NodeListOf<Element> | Element[]): void => {\n for (const element of elements) {\n element.remove();\n }\n};\n","import { getAllHeadingElements } from './utils/dom';\nimport type { HeadingLevel } from './types';\n\n/**\n * Regular expressions and symbols used for text processing and anchor text generation\n */\nconst WHITESPACE_PATTERN = /\\s+/g;\nconst COLON_CHARACTER = ':';\nconst PERCENT_ENCODING_PATTERN = /%+/g;\nconst DOT_REPLACEMENT = '.';\n\n/**\n * Regular expressions for checking the validity of URL-encoded strings\n */\nconst VALID_PERCENT_ENCODING = /%[0-9A-F]{2}/i;\nconst INVALID_PERCENT_PATTERN = /%[^0-9A-F]|%[0-9A-F][^0-9A-F]|%$/i;\n\nconst HEADING_DUPLICATE_SUFFIX_PATTERN = /_\\d+$/;\n\nconst MIN_HEADING_LEVEL: HeadingLevel = 1;\nconst MAX_HEADING_LEVEL: HeadingLevel = 6;\nconst FALLBACK_HEADING_LEVEL = MAX_HEADING_LEVEL;\n\n/**\n * Replace spaces with underscores and remove colons in text\n */\nconst replaceSpacesWithUnderscores = (text: string): string => {\n return text.replaceAll(WHITESPACE_PATTERN, '_').replace(COLON_CHARACTER, '');\n};\n\n/**\n * Convert text to Wikipedia-style anchor format\n */\nconst convertToWikipediaStyleAnchor = (anchor: string): string => {\n return encodeURIComponent(anchor).replaceAll(PERCENT_ENCODING_PATTERN, DOT_REPLACEMENT);\n};\n\n/**\n * Generate anchor text\n */\nexport const generateAnchorText = (baseId: string, isConvertToWikipediaStyleAnchor: boolean): string => {\n if (isConvertToWikipediaStyleAnchor) {\n // Wikipedia style: Replace spaces with underscores, encode, then replace % with dots\n const anchorText = replaceSpacesWithUnderscores(baseId);\n return convertToWikipediaStyleAnchor(anchorText);\n } else {\n // RFC 3986 compliant: Use encodeURIComponent for proper fragment identifier encoding\n return encodeURIComponent(baseId.trim());\n }\n};\n\n/**\n * Safely decode URI component\n */\nconst safeDecodeURIComponent = (encoded: string): string => {\n if (!VALID_PERCENT_ENCODING.test(encoded)) {\n return encoded;\n }\n\n if (INVALID_PERCENT_PATTERN.test(encoded)) {\n return encoded;\n }\n\n try {\n return decodeURIComponent(encoded);\n } catch {\n return encoded;\n }\n};\n\n/**\n * Assign ID to heading element\n */\nexport const assignInitialIdToHeading = (\n heading: HTMLHeadingElement,\n isConvertToWikipediaStyleAnchor: boolean,\n): string => {\n const existingId = heading.getAttribute('id')?.trim();\n if (existingId) {\n heading.id = existingId;\n return existingId;\n }\n\n const baseHeadingId = (heading.textContent || '').trim();\n const anchorText = generateAnchorText(baseHeadingId, isConvertToWikipediaStyleAnchor);\n heading.id = anchorText;\n return anchorText;\n};\n\n/**\n * Resolve duplicate heading IDs and update anchors\n */\nexport const ensureUniqueHeadingIds = (headings: HTMLHeadingElement[], anchors: HTMLAnchorElement[]) => {\n const anchorList = [...anchors];\n const usedIds = new Set<string>();\n const idCounts = new Map<string, number>();\n\n // Cache decoded IDs to avoid recomputation\n const decodedIdCache = new Map<number, { originalId: string; decodedId: string }>();\n const originalIds = new Set<string>();\n\n // First pass: collect and cache all IDs\n for (const [i, heading] of headings.entries()) {\n const originalId = heading.id || `mokuji-heading-${i}`;\n const decodedId = safeDecodeURIComponent(originalId);\n decodedIdCache.set(i, { originalId, decodedId });\n originalIds.add(decodedId);\n }\n\n // Second pass: resolve duplicates using cached values\n for (const [i, heading] of headings.entries()) {\n const anchor = anchorList[i];\n const cached = decodedIdCache.get(i)!;\n const { originalId, decodedId } = cached;\n\n // If this ID is not used yet, keep it as is\n if (!usedIds.has(decodedId)) {\n heading.id = originalId;\n usedIds.add(decodedId);\n\n if (anchor) {\n anchor.href = `#${originalId}`;\n }\n continue;\n }\n\n // ID is already used, need to find a unique variant\n const baseId = decodedId.replace(HEADING_DUPLICATE_SUFFIX_PATTERN, '') || decodedId;\n let counter = (idCounts.get(baseId) || 0) + 1;\n let candidateId: string;\n\n // Find the next available suffix, skipping those reserved for original IDs\n let startingCounter = counter;\n while (true) {\n candidateId = `${baseId}_${startingCounter}`;\n\n // Available if not used and not reserved for original IDs\n if (!usedIds.has(candidateId) && !originalIds.has(candidateId)) {\n counter = startingCounter;\n break;\n }\n\n // If reserved for original ID but not used yet, skip this counter\n if (originalIds.has(candidateId) && !usedIds.has(candidateId)) {\n startingCounter++;\n continue;\n }\n\n // If already used, try next counter\n startingCounter++;\n }\n\n idCounts.set(baseId, counter);\n heading.id = candidateId;\n usedIds.add(candidateId);\n\n if (anchor) {\n anchor.href = `#${candidateId}`;\n }\n }\n};\n\n/**\n * Get heading element level as a numeric value\n */\nexport const getHeadingLevel = (heading: HTMLHeadingElement): HeadingLevel => {\n const numericLevel = Number.parseInt(heading.tagName.slice(1), 10);\n if (numericLevel >= MIN_HEADING_LEVEL && numericLevel <= MAX_HEADING_LEVEL) {\n return numericLevel as HeadingLevel;\n }\n return FALLBACK_HEADING_LEVEL;\n};\n\n/**\n * Get heading elements within the specified level range\n */\nexport const getFilteredHeadings = (\n element: Element,\n minLevel: HeadingLevel,\n maxLevel: HeadingLevel,\n): HTMLHeadingElement[] => {\n const filteredHeadings: HTMLHeadingElement[] = [];\n const allHeadings = getAllHeadingElements(element);\n\n for (const heading of allHeadings) {\n const level = getHeadingLevel(heading);\n if (level >= minLevel && level <= maxLevel) {\n filteredHeadings.push(heading);\n }\n }\n\n return filteredHeadings;\n};\n","import type { MokujiOption } from '../types';\n\nexport const MOKUJI_LIST_DATASET_ATTRIBUTE = 'data-mokuji-list';\nexport const ANCHOR_DATASET_ATTRIBUTE = 'data-mokuji-anchor';\n\nexport const defaultOptions: Required<MokujiOption> = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkPosition: 'before',\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n minLevel: 1,\n maxLevel: 6,\n} as const;\n","import { createElement, removeAllElements } from './utils/dom';\nimport { ANCHOR_DATASET_ATTRIBUTE } from './utils/constants';\nimport type { MokujiOption, AnchorLinkPosition } from './types';\n\n/**\n * Creates a map from anchor elements within the table of contents, using their href hash values as keys\n */\nexport const createAnchorMap = (anchors: HTMLAnchorElement[]): Map<string, HTMLAnchorElement> => {\n const result = new Map<string, HTMLAnchorElement>();\n\n for (const anchor of anchors) {\n if (anchor.hash && anchor.hash.length > 1) {\n result.set(anchor.hash.slice(1), anchor);\n }\n }\n\n return result;\n};\n\n/**\n * Creates a map with anchor element text content as keys\n */\nexport const createTextToAnchorMap = (anchors: HTMLAnchorElement[]): Map<string, HTMLAnchorElement> => {\n const result = new Map<string, HTMLAnchorElement>();\n\n for (const anchor of anchors) {\n const text = anchor.textContent?.trim();\n if (text) {\n result.set(text, anchor);\n }\n }\n\n return result;\n};\n\n/**\n * Search directly by ID from the anchor map\n */\nexport const findAnchorById = (\n anchorMap: Map<string, HTMLAnchorElement>,\n id: string,\n): HTMLAnchorElement | undefined => {\n return anchorMap.get(id);\n};\n\n/**\n * Search by ID with numeric suffix removed\n */\nexport const findAnchorByIdWithoutSuffix = (\n anchorMap: Map<string, HTMLAnchorElement>,\n id: string,\n): HTMLAnchorElement | undefined => {\n // Check if ID is in \"ID_number\" format (for IDs modified due to duplication)\n const idWithoutSuffix = id.replace(/_\\d+$/, '');\n if (idWithoutSuffix !== id) {\n // Search for anchor with the original ID without suffix\n return anchorMap.get(idWithoutSuffix);\n }\n return undefined;\n};\n\n/**\n * Search for anchor by text content\n */\nexport const findAnchorByText = (\n anchorMap: Map<string, HTMLAnchorElement>,\n text: string,\n): HTMLAnchorElement | undefined => {\n const trimmedText = text.trim();\n if (!trimmedText) return undefined;\n\n // Search within anchor map by text content\n for (const [, anchor] of anchorMap.entries()) {\n if (anchor.textContent?.trim() === trimmedText) {\n return anchor;\n }\n }\n return undefined;\n};\n\n/**\n * Search anchor from text map\n */\nexport const findAnchorInTextMap = (\n textToAnchorMap: Map<string, HTMLAnchorElement>,\n text: string,\n): HTMLAnchorElement | undefined => {\n const trimmedText = text.trim();\n if (!trimmedText) return undefined;\n\n return textToAnchorMap.get(trimmedText);\n};\n\n/**\n * Find matching anchor with 3-level fallback (core implementation)\n */\nconst findMatchingAnchorCore = (\n anchorMap: Map<string, HTMLAnchorElement>,\n headingId: string,\n headingText: string,\n textToAnchorMap?: Map<string, HTMLAnchorElement>,\n): HTMLAnchorElement | undefined => {\n // 1. Direct ID search → 2. Search after suffix removal → 3. Search by text content\n const directMatch = findAnchorById(anchorMap, headingId);\n if (directMatch) return directMatch;\n\n const suffixMatch = findAnchorByIdWithoutSuffix(anchorMap, headingId);\n if (suffixMatch) return suffixMatch;\n\n // Use optimized text map if available, otherwise fallback to linear search\n if (textToAnchorMap) {\n return findAnchorInTextMap(textToAnchorMap, headingText);\n } else {\n // Fallback: linear search through anchor map\n const trimmedText = headingText.trim();\n if (!trimmedText) return undefined;\n\n for (const [, anchor] of anchorMap.entries()) {\n if (anchor.textContent?.trim() === trimmedText) {\n return anchor;\n }\n }\n return undefined;\n }\n};\n\n/**\n * Find matching anchor with 3-level fallback\n */\nexport const findMatchingAnchor = (\n anchorMap: Map<string, HTMLAnchorElement>,\n headingId: string,\n headingText: string,\n): HTMLAnchorElement | undefined => {\n return findMatchingAnchorCore(anchorMap, headingId, headingText);\n};\n\n/**\n * Find matching anchor with 3-level fallback using maps\n */\nexport const findMatchingAnchorWithMaps = (\n anchorMap: Map<string, HTMLAnchorElement>,\n textToAnchorMap: Map<string, HTMLAnchorElement>,\n headingId: string,\n headingText: string,\n): HTMLAnchorElement | undefined => {\n return findMatchingAnchorCore(anchorMap, headingId, headingText, textToAnchorMap);\n};\n\n/**\n * Apply multiple class names to an element\n */\nexport const applyClassNamesToElement = (element: HTMLElement, classNameString: string): void => {\n const trimmedClassNames = classNameString.trim();\n if (!trimmedClassNames) return;\n\n element.classList.add(...trimmedClassNames.split(/\\s+/).filter(Boolean));\n};\n\n/**\n * Create anchor template element\n */\nexport const createAnchorElement = (options: Required<MokujiOption>): HTMLAnchorElement => {\n const anchorTemplate = createElement('a');\n anchorTemplate.setAttribute(ANCHOR_DATASET_ATTRIBUTE, '');\n\n // Execute class name application even if anchorLinkClassName is empty string\n // Early return occurs within applyClassNamesToElement for empty strings\n applyClassNamesToElement(anchorTemplate, options.anchorLinkClassName);\n\n return anchorTemplate;\n};\n\n/**\n * Create anchor element corresponding to a heading element (core implementation)\n */\nconst createAnchorForHeadingCore = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n textToAnchorMap?: Map<string, HTMLAnchorElement>,\n): HTMLAnchorElement | undefined => {\n const headingId = heading.id;\n const matchedTocAnchor = findMatchingAnchorCore(anchorMap, headingId, heading.textContent || '', textToAnchorMap);\n\n // If no matching anchor is found ultimately\n if (!matchedTocAnchor) {\n return undefined;\n }\n\n const anchorElement = anchorTemplate.cloneNode(false) as HTMLAnchorElement;\n anchorElement.href = matchedTocAnchor.hash;\n anchorElement.textContent = options.anchorLinkSymbol;\n\n return anchorElement;\n};\n\n/**\n * Create anchor element corresponding to a heading element\n */\nexport const createAnchorForHeading = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n): HTMLAnchorElement | undefined => {\n return createAnchorForHeadingCore(heading, anchorMap, anchorTemplate, options);\n};\n\n/**\n * Create anchor element corresponding to a heading element using maps\n */\nexport const createAnchorForHeadingWithMaps = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n textToAnchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n): HTMLAnchorElement | undefined => {\n return createAnchorForHeadingCore(heading, anchorMap, anchorTemplate, options, textToAnchorMap);\n};\n\n/**\n * Remove existing table of contents anchors from headings to prevent duplicate insertion\n */\nconst removeExistingAnchors = (heading: HTMLHeadingElement): void => {\n const existingAnchors = heading.querySelectorAll(`[${ANCHOR_DATASET_ATTRIBUTE}]`);\n removeAllElements(existingAnchors);\n};\n\n/**\n * Insert anchor element at specified position within heading element\n */\nconst placeAnchorInHeading = (\n heading: HTMLHeadingElement,\n anchor: HTMLAnchorElement,\n position: AnchorLinkPosition = 'before',\n): void => {\n if (position === 'before') {\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n heading.append(anchor);\n }\n};\n\n/**\n * Add anchor links to heading elements (core implementation)\n */\nconst insertAnchorsIntoHeadingsCore = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n textToAnchorMap?: Map<string, HTMLAnchorElement>,\n): HTMLAnchorElement[] => {\n const anchorTemplate = createAnchorElement(options);\n const insertedAnchors: HTMLAnchorElement[] = [];\n\n for (const heading of headings) {\n removeExistingAnchors(heading);\n const anchor = createAnchorForHeadingCore(heading, anchorMap, anchorTemplate, options, textToAnchorMap);\n if (!anchor) continue;\n\n placeAnchorInHeading(heading, anchor, options.anchorLinkPosition);\n insertedAnchors.push(anchor);\n }\n\n return insertedAnchors;\n};\n\n/**\n * Add anchor links to heading elements\n * @returns Array of inserted anchor elements\n */\nexport const insertAnchorsIntoHeadings = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n): HTMLAnchorElement[] => {\n return insertAnchorsIntoHeadingsCore(headings, anchorMap, options);\n};\n\n/**\n * Add anchor links to heading elements using maps\n * @returns Array of inserted anchor elements\n */\nexport const insertAnchorsIntoHeadingsWithMaps = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n textToAnchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n): HTMLAnchorElement[] => {\n return insertAnchorsIntoHeadingsCore(headings, anchorMap, options, textToAnchorMap);\n};\n","import { createElement } from './utils/dom';\nimport { assignInitialIdToHeading, getHeadingLevel } from './heading';\n\ntype TocItem = {\n text: string | null;\n href: string;\n level: number;\n children: TocItem[];\n};\n\ntype TableOfContentsContainer = HTMLUListElement | HTMLOListElement;\n\n/**\n * Build hierarchical data structure from headings\n */\nconst buildTocHierarchy = (headings: HTMLHeadingElement[], isConvertToWikipediaStyleAnchor: boolean): TocItem[] => {\n const rootLevelItems: TocItem[] = [];\n const levelStack: { level: number; items: TocItem[] }[] = [{ level: 0, items: rootLevelItems }];\n\n for (const heading of headings) {\n const currentHeadingLevel = getHeadingLevel(heading);\n const anchorText = assignInitialIdToHeading(heading, isConvertToWikipediaStyleAnchor);\n\n const newItem: TocItem = {\n text: heading.textContent,\n href: `#${anchorText}`,\n level: currentHeadingLevel,\n children: [],\n };\n\n // Find appropriate parent level\n let topLevel = levelStack.at(-1)!;\n while (levelStack.length > 1 && currentHeadingLevel <= topLevel.level) {\n levelStack.pop();\n topLevel = levelStack.at(-1)!;\n }\n\n topLevel.items.push(newItem);\n levelStack.push({ level: currentHeadingLevel, items: newItem.children });\n }\n\n return rootLevelItems;\n};\n\n/**\n * Generate DOM elements from TOC hierarchy\n */\nconst buildTocDom = (items: TocItem[], listContainer: TableOfContentsContainer): void => {\n const listItemTemplate = createElement('li');\n const anchorTemplate = createElement('a');\n const childListTagName = listContainer.tagName.toLowerCase() as 'ul' | 'ol';\n const childListTemplate = createElement(childListTagName);\n\n const buildListRecursive = (parentListElement: HTMLElement, tocItems: TocItem[]): void => {\n for (const item of tocItems) {\n const listItem = listItemTemplate.cloneNode(false) as HTMLLIElement;\n const anchor = anchorTemplate.cloneNode(false) as HTMLAnchorElement;\n\n anchor.href = item.href;\n anchor.textContent = item.text;\n listItem.append(anchor);\n\n if (item.children.length > 0) {\n const childList = childListTemplate.cloneNode(false) as TableOfContentsContainer;\n buildListRecursive(childList, item.children);\n listItem.append(childList);\n }\n parentListElement.append(listItem);\n }\n };\n\n buildListRecursive(listContainer, items);\n};\n\n/**\n * Generate hierarchical table of contents data structure from heading elements and build DOM\n *\n * @param headings Array of heading elements to process\n * @param listContainer Container element to store the table of contents (ul or ol)\n * @param isConvertToWikipediaStyleAnchor Flag to generate Wikipedia-style anchors\n */\nexport const buildMokujiHierarchy = (\n headings: HTMLHeadingElement[],\n listContainer: TableOfContentsContainer,\n isConvertToWikipediaStyleAnchor: boolean,\n): void => {\n const tocItems = buildTocHierarchy(headings, isConvertToWikipediaStyleAnchor);\n buildTocDom(tocItems, listContainer);\n};\n","import { createElement } from './utils/dom';\nimport type { MokujiOption, HeadingLevel } from './types';\nimport { getFilteredHeadings, ensureUniqueHeadingIds } from './heading';\nimport { createAnchorMap, createTextToAnchorMap, insertAnchorsIntoHeadingsWithMaps } from './anchor';\nimport { buildMokujiHierarchy } from './mokuji-core';\nimport { MOKUJI_LIST_DATASET_ATTRIBUTE, defaultOptions } from './utils/constants';\n\nexport type MokujiResult<T extends HTMLElement = HTMLElement> = {\n element?: T;\n list: HTMLUListElement | HTMLOListElement;\n destroy: () => void;\n};\n\nexport { MokujiOption, HeadingLevel };\n\n/**\n * Process option settings, merge with default values, and restrict to valid range\n */\nconst processOptions = (externalOptions?: MokujiOption): Required<MokujiOption> => {\n const options = {\n ...defaultOptions,\n ...externalOptions,\n };\n\n options.minLevel = Math.max(1, Math.min(options.minLevel, 6)) as HeadingLevel;\n options.maxLevel = Math.max(options.minLevel, Math.min(options.maxLevel, 6)) as HeadingLevel;\n\n return options;\n};\n\n/**\n * Generate table of contents from headings within the given element (public API)\n */\nexport const Mokuji = <T extends HTMLElement>(\n element: T | undefined,\n externalOptions?: MokujiOption,\n): MokujiResult<T> | undefined => {\n if (!element) {\n console.warn('Mokuji: Target element not found.');\n return undefined;\n }\n\n const options = processOptions(externalOptions);\n\n const { minLevel, maxLevel } = options;\n const filteredHeadings = getFilteredHeadings(element, minLevel, maxLevel);\n\n if (filteredHeadings.length === 0) {\n return undefined;\n }\n\n // Generate table of contents\n const listContainer = createElement(options.anchorContainerTagName);\n listContainer.setAttribute(MOKUJI_LIST_DATASET_ATTRIBUTE, '');\n\n buildMokujiHierarchy(filteredHeadings, listContainer, options.anchorType);\n\n const anchors = [...listContainer.querySelectorAll('a')];\n\n if (anchors.length === 0) {\n return undefined;\n }\n\n ensureUniqueHeadingIds(filteredHeadings, anchors);\n\n const insertedAnchors: HTMLAnchorElement[] = [];\n\n if (options.anchorLink) {\n const anchorsMap = createAnchorMap(anchors);\n const textToAnchorMap = createTextToAnchorMap(anchors);\n const anchorElements = insertAnchorsIntoHeadingsWithMaps(filteredHeadings, anchorsMap, textToAnchorMap, options);\n insertedAnchors.push(...anchorElements);\n }\n\n const destroy = () => {\n listContainer.remove();\n\n for (const anchor of insertedAnchors) {\n anchor.remove();\n }\n };\n\n return { element, list: listContainer, destroy };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["MIN_HEADING_LEVEL: HeadingLevel","MAX_HEADING_LEVEL: HeadingLevel","defaultOptions: Required<MokujiOption>","insertedAnchors: HTMLAnchorElement[]","rootLevelItems: TocItem[]","levelStack: { level: number; items: TocItem[] }[]","newItem: TocItem"],"sources":["../src/utils/dom.ts","../src/heading.ts","../src/utils/constants.ts","../src/anchor.ts","../src/mokuji-core.ts","../src/index.ts"],"sourcesContent":["import type { HeadingLevel } from '../types';\n\nexport const getAllHeadingElements = (\n containerElement: Element,\n minLevel: HeadingLevel = 1,\n maxLevel: HeadingLevel = 6,\n): HTMLHeadingElement[] => {\n if (minLevel > maxLevel) {\n return [];\n }\n\n const selector = Array.from({ length: maxLevel - minLevel + 1 }, (_, i) => `h${minLevel + i}`).join(', ');\n const headings = containerElement.querySelectorAll(selector);\n return [...headings] as HTMLHeadingElement[];\n};\n\nexport const createElement = <T extends keyof HTMLElementTagNameMap>(tagName: T): HTMLElementTagNameMap[T] => {\n return document.createElement(tagName);\n};\n\nexport const removeAllElements = (elements: NodeListOf<Element> | Element[]): void => {\n for (const element of elements) {\n element.remove();\n }\n};\n","import { getAllHeadingElements } from './utils/dom';\nimport type { HeadingLevel } from './types';\n\n/**\n * Regular expressions and symbols used for text processing and anchor text generation\n */\nconst WHITESPACE_PATTERN = /\\s+/g;\nconst COLON_CHARACTER = ':';\nconst PERCENT_ENCODING_PATTERN = /%+/g;\nconst DOT_REPLACEMENT = '.';\n\n/**\n * Regular expressions for checking the validity of URL-encoded strings\n */\nconst VALID_PERCENT_ENCODING = /%[0-9A-F]{2}/i;\nconst INVALID_PERCENT_PATTERN = /%[^0-9A-F]|%[0-9A-F][^0-9A-F]|%$/i;\n\nconst HEADING_DUPLICATE_SUFFIX_PATTERN = /_\\d+$/;\n\nconst MIN_HEADING_LEVEL: HeadingLevel = 1;\nconst MAX_HEADING_LEVEL: HeadingLevel = 6;\nconst FALLBACK_HEADING_LEVEL = MAX_HEADING_LEVEL;\n\n/**\n * Replace spaces with underscores and remove colons in text\n */\nconst replaceSpacesWithUnderscores = (text: string): string => {\n return text.replaceAll(WHITESPACE_PATTERN, '_').replace(COLON_CHARACTER, '');\n};\n\n/**\n * Convert text to Wikipedia-style anchor format\n */\nconst convertToWikipediaStyleAnchor = (anchor: string): string => {\n return encodeURIComponent(anchor).replaceAll(PERCENT_ENCODING_PATTERN, DOT_REPLACEMENT);\n};\n\n/**\n * Generate anchor text\n */\nexport const generateAnchorText = (baseId: string, isConvertToWikipediaStyleAnchor: boolean): string => {\n if (isConvertToWikipediaStyleAnchor) {\n const anchorText = replaceSpacesWithUnderscores(baseId);\n return convertToWikipediaStyleAnchor(anchorText);\n }\n\n return encodeURIComponent(baseId.trim());\n};\n\n/**\n * Safely decode URI component\n */\nconst safeDecodeURIComponent = (encoded: string): string => {\n if (!VALID_PERCENT_ENCODING.test(encoded)) {\n return encoded;\n }\n\n if (INVALID_PERCENT_PATTERN.test(encoded)) {\n return encoded;\n }\n\n try {\n return decodeURIComponent(encoded);\n } catch {\n return encoded;\n }\n};\n\n/**\n * Assign ID to heading element\n */\nexport const assignInitialIdToHeading = (\n heading: HTMLHeadingElement,\n isConvertToWikipediaStyleAnchor: boolean,\n): string => {\n const existingId = heading.getAttribute('id')?.trim();\n if (existingId) {\n heading.id = existingId;\n return existingId;\n }\n\n const baseHeadingId = (heading.textContent || '').trim();\n const anchorText = generateAnchorText(baseHeadingId, isConvertToWikipediaStyleAnchor);\n heading.id = anchorText;\n return anchorText;\n};\n\n/**\n * Resolve duplicate heading IDs and update anchors\n */\nexport const ensureUniqueHeadingIds = (headings: HTMLHeadingElement[], anchors: HTMLAnchorElement[]) => {\n const usedIds = new Set<string>();\n const idCounts = new Map<string, number>();\n const originalIds = new Set<string>();\n\n for (const [i, heading] of headings.entries()) {\n const originalId = heading.id || `mokuji-heading-${i}`;\n originalIds.add(safeDecodeURIComponent(originalId));\n }\n\n for (const [i, heading] of headings.entries()) {\n const anchor = anchors[i];\n const originalId = heading.id || `mokuji-heading-${i}`;\n const decodedId = safeDecodeURIComponent(originalId);\n\n if (!usedIds.has(decodedId)) {\n heading.id = originalId;\n usedIds.add(decodedId);\n\n if (anchor) {\n anchor.href = `#${originalId}`;\n }\n continue;\n }\n\n const baseId = decodedId.replace(HEADING_DUPLICATE_SUFFIX_PATTERN, '') || decodedId;\n let counter = (idCounts.get(baseId) || 0) + 1;\n\n while (usedIds.has(`${baseId}_${counter}`) || originalIds.has(`${baseId}_${counter}`)) {\n counter++;\n }\n\n const candidateId = `${baseId}_${counter}`;\n idCounts.set(baseId, counter);\n heading.id = candidateId;\n usedIds.add(candidateId);\n\n if (anchor) {\n anchor.href = `#${candidateId}`;\n }\n }\n};\n\n/**\n * Get heading element level as a numeric value\n */\nexport const getHeadingLevel = (heading: HTMLHeadingElement): HeadingLevel => {\n const numericLevel = Number.parseInt(heading.tagName.slice(1), 10);\n if (numericLevel >= MIN_HEADING_LEVEL && numericLevel <= MAX_HEADING_LEVEL) {\n return numericLevel as HeadingLevel;\n }\n return FALLBACK_HEADING_LEVEL;\n};\n\n/**\n * Get heading elements within the specified level range\n */\nexport const getFilteredHeadings = (\n element: Element,\n minLevel: HeadingLevel,\n maxLevel: HeadingLevel,\n options?: { includeBlockquoteHeadings?: boolean },\n): HTMLHeadingElement[] => {\n const includeBlockquoteHeadings = options?.includeBlockquoteHeadings ?? false;\n const allHeadings = getAllHeadingElements(element, minLevel, maxLevel);\n\n if (includeBlockquoteHeadings) {\n return allHeadings;\n }\n\n return allHeadings.filter((heading) => !heading.closest('blockquote'));\n};\n","import type { MokujiOption } from '../types';\n\nexport const MOKUJI_LIST_DATASET_ATTRIBUTE = 'data-mokuji-list';\nexport const ANCHOR_DATASET_ATTRIBUTE = 'data-mokuji-anchor';\n\nexport const defaultOptions: Required<MokujiOption> = {\n anchorType: true,\n anchorLink: false,\n anchorLinkSymbol: '#',\n anchorLinkPosition: 'before',\n anchorLinkClassName: '',\n anchorContainerTagName: 'ol',\n minLevel: 1,\n maxLevel: 6,\n includeBlockquoteHeadings: false,\n} as const;\n","import { createElement, removeAllElements } from './utils/dom';\nimport { ANCHOR_DATASET_ATTRIBUTE } from './utils/constants';\nimport type { MokujiOption, AnchorLinkPosition } from './types';\n\n/**\n * Creates a map from anchor elements within the table of contents, using their href hash values as keys\n */\nexport const createAnchorMap = (anchors: HTMLAnchorElement[]): Map<string, HTMLAnchorElement> => {\n const result = new Map<string, HTMLAnchorElement>();\n\n for (const anchor of anchors) {\n if (anchor.hash && anchor.hash.length > 1) {\n result.set(anchor.hash.slice(1), anchor);\n }\n }\n\n return result;\n};\n\n/**\n * Creates a map with anchor element text content as keys\n */\nexport const createTextToAnchorMap = (anchors: HTMLAnchorElement[]): Map<string, HTMLAnchorElement> => {\n const result = new Map<string, HTMLAnchorElement>();\n\n for (const anchor of anchors) {\n const text = anchor.textContent?.trim();\n if (text) {\n result.set(text, anchor);\n }\n }\n\n return result;\n};\n\n/**\n * Search directly by ID from the anchor map\n */\nexport const findAnchorById = (\n anchorMap: Map<string, HTMLAnchorElement>,\n id: string,\n): HTMLAnchorElement | undefined => {\n return anchorMap.get(id);\n};\n\n/**\n * Search by ID with numeric suffix removed\n */\nexport const findAnchorByIdWithoutSuffix = (\n anchorMap: Map<string, HTMLAnchorElement>,\n id: string,\n): HTMLAnchorElement | undefined => {\n const idWithoutSuffix = id.replace(/_\\d+$/, '');\n if (idWithoutSuffix !== id) {\n return anchorMap.get(idWithoutSuffix);\n }\n return undefined;\n};\n\n/**\n * Search for anchor by text content\n */\nexport const findAnchorByText = (\n anchorMap: Map<string, HTMLAnchorElement>,\n text: string,\n): HTMLAnchorElement | undefined => {\n const trimmedText = text.trim();\n if (!trimmedText) return undefined;\n\n for (const anchor of anchorMap.values()) {\n if (anchor.textContent?.trim() === trimmedText) {\n return anchor;\n }\n }\n return undefined;\n};\n\nconst findAnchorInTextMap = (\n textToAnchorMap: Map<string, HTMLAnchorElement>,\n text: string,\n): HTMLAnchorElement | undefined => {\n const trimmedText = text.trim();\n if (!trimmedText) return undefined;\n\n return textToAnchorMap.get(trimmedText);\n};\n\n/**\n * Find matching anchor with 3-level fallback (core implementation)\n */\nconst findMatchingAnchorCore = (\n anchorMap: Map<string, HTMLAnchorElement>,\n headingId: string,\n headingText: string,\n textToAnchorMap?: Map<string, HTMLAnchorElement>,\n): HTMLAnchorElement | undefined => {\n // 1. Direct ID search → 2. Search after suffix removal → 3. Search by text content\n const directMatch = findAnchorById(anchorMap, headingId);\n if (directMatch) return directMatch;\n\n const suffixMatch = findAnchorByIdWithoutSuffix(anchorMap, headingId);\n if (suffixMatch) return suffixMatch;\n\n if (textToAnchorMap) {\n return findAnchorInTextMap(textToAnchorMap, headingText);\n }\n\n return findAnchorByText(anchorMap, headingText);\n};\n\n/**\n * Find matching anchor with 3-level fallback\n */\nexport const findMatchingAnchor = (\n anchorMap: Map<string, HTMLAnchorElement>,\n headingId: string,\n headingText: string,\n): HTMLAnchorElement | undefined => {\n return findMatchingAnchorCore(anchorMap, headingId, headingText);\n};\n\n/**\n * Apply multiple class names to an element\n */\nexport const applyClassNamesToElement = (element: HTMLElement, classNameString: string): void => {\n const trimmedClassNames = classNameString.trim();\n if (!trimmedClassNames) return;\n\n element.classList.add(...trimmedClassNames.split(/\\s+/).filter(Boolean));\n};\n\n/**\n * Create anchor template element\n */\nexport const createAnchorElement = (options: Required<MokujiOption>): HTMLAnchorElement => {\n const anchorTemplate = createElement('a');\n anchorTemplate.setAttribute(ANCHOR_DATASET_ATTRIBUTE, '');\n\n applyClassNamesToElement(anchorTemplate, options.anchorLinkClassName);\n\n return anchorTemplate;\n};\n\n/**\n * Create anchor element corresponding to a heading element (core implementation)\n */\nconst createAnchorForHeadingCore = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n textToAnchorMap?: Map<string, HTMLAnchorElement>,\n): HTMLAnchorElement | undefined => {\n const headingId = heading.id;\n const matchedTocAnchor = findMatchingAnchorCore(anchorMap, headingId, heading.textContent || '', textToAnchorMap);\n\n if (!matchedTocAnchor) {\n return undefined;\n }\n\n const anchorElement = anchorTemplate.cloneNode(false) as HTMLAnchorElement;\n anchorElement.href = matchedTocAnchor.hash;\n anchorElement.textContent = options.anchorLinkSymbol;\n\n return anchorElement;\n};\n\n/**\n * Create anchor element corresponding to a heading element\n */\nexport const createAnchorForHeading = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n): HTMLAnchorElement | undefined => {\n return createAnchorForHeadingCore(heading, anchorMap, anchorTemplate, options);\n};\n\n/**\n * Remove existing table of contents anchors from headings to prevent duplicate insertion\n */\nconst removeExistingAnchors = (heading: HTMLHeadingElement): void => {\n const existingAnchors = heading.querySelectorAll(`[${ANCHOR_DATASET_ATTRIBUTE}]`);\n removeAllElements(existingAnchors);\n};\n\n/**\n * Insert anchor element at specified position within heading element\n */\nconst placeAnchorInHeading = (\n heading: HTMLHeadingElement,\n anchor: HTMLAnchorElement,\n position: AnchorLinkPosition = 'before',\n): void => {\n if (position === 'before') {\n heading.insertBefore(anchor, heading.firstChild);\n } else {\n heading.append(anchor);\n }\n};\n\n/**\n * Add anchor links to heading elements (core implementation)\n */\nconst insertAnchorsIntoHeadingsCore = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n textToAnchorMap?: Map<string, HTMLAnchorElement>,\n): HTMLAnchorElement[] => {\n const anchorTemplate = createAnchorElement(options);\n const insertedAnchors: HTMLAnchorElement[] = [];\n\n for (const heading of headings) {\n removeExistingAnchors(heading);\n const anchor = createAnchorForHeadingCore(heading, anchorMap, anchorTemplate, options, textToAnchorMap);\n if (!anchor) continue;\n\n placeAnchorInHeading(heading, anchor, options.anchorLinkPosition);\n insertedAnchors.push(anchor);\n }\n\n return insertedAnchors;\n};\n\n/**\n * Add anchor links to heading elements\n * @returns Array of inserted anchor elements\n */\nexport const insertAnchorsIntoHeadings = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n): HTMLAnchorElement[] => {\n return insertAnchorsIntoHeadingsCore(headings, anchorMap, options);\n};\n\n/**\n * Add anchor links to heading elements using maps\n * @returns Array of inserted anchor elements\n */\nexport const insertAnchorsIntoHeadingsWithMaps = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n textToAnchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n): HTMLAnchorElement[] => {\n return insertAnchorsIntoHeadingsCore(headings, anchorMap, options, textToAnchorMap);\n};\n","import { createElement } from './utils/dom';\nimport { assignInitialIdToHeading, getHeadingLevel } from './heading';\n\ntype TocItem = {\n text: string | null;\n href: string;\n level: number;\n children: TocItem[];\n};\n\ntype TableOfContentsContainer = HTMLUListElement | HTMLOListElement;\n\n/**\n * Build hierarchical data structure from headings\n */\nconst buildTocHierarchy = (headings: HTMLHeadingElement[], isConvertToWikipediaStyleAnchor: boolean): TocItem[] => {\n const rootLevelItems: TocItem[] = [];\n const levelStack: { level: number; items: TocItem[] }[] = [{ level: 0, items: rootLevelItems }];\n\n for (const heading of headings) {\n const currentHeadingLevel = getHeadingLevel(heading);\n const anchorText = assignInitialIdToHeading(heading, isConvertToWikipediaStyleAnchor);\n\n const newItem: TocItem = {\n text: heading.textContent,\n href: `#${anchorText}`,\n level: currentHeadingLevel,\n children: [],\n };\n\n // Find appropriate parent level\n let topLevel = levelStack.at(-1)!;\n while (levelStack.length > 1 && currentHeadingLevel <= topLevel.level) {\n levelStack.pop();\n topLevel = levelStack.at(-1)!;\n }\n\n topLevel.items.push(newItem);\n levelStack.push({ level: currentHeadingLevel, items: newItem.children });\n }\n\n return rootLevelItems;\n};\n\n/**\n * Generate DOM elements from TOC hierarchy\n */\nconst buildTocDom = (items: TocItem[], listContainer: TableOfContentsContainer): void => {\n const listItemTemplate = createElement('li');\n const anchorTemplate = createElement('a');\n const childListTagName = listContainer.tagName.toLowerCase() as 'ul' | 'ol';\n const childListTemplate = createElement(childListTagName);\n\n const buildListRecursive = (parentListElement: HTMLElement, tocItems: TocItem[]): void => {\n for (const item of tocItems) {\n const listItem = listItemTemplate.cloneNode(false) as HTMLLIElement;\n const anchor = anchorTemplate.cloneNode(false) as HTMLAnchorElement;\n\n anchor.href = item.href;\n anchor.textContent = item.text;\n listItem.append(anchor);\n\n if (item.children.length > 0) {\n const childList = childListTemplate.cloneNode(false) as TableOfContentsContainer;\n buildListRecursive(childList, item.children);\n listItem.append(childList);\n }\n parentListElement.append(listItem);\n }\n };\n\n buildListRecursive(listContainer, items);\n};\n\n/**\n * Generate hierarchical table of contents data structure from heading elements and build DOM\n */\nexport const buildMokujiHierarchy = (\n headings: HTMLHeadingElement[],\n listContainer: TableOfContentsContainer,\n isConvertToWikipediaStyleAnchor: boolean,\n): void => {\n const tocItems = buildTocHierarchy(headings, isConvertToWikipediaStyleAnchor);\n buildTocDom(tocItems, listContainer);\n};\n","import { createElement } from './utils/dom';\nimport type { MokujiOption, HeadingLevel } from './types';\nimport { getFilteredHeadings, ensureUniqueHeadingIds } from './heading';\nimport { createAnchorMap, createTextToAnchorMap, insertAnchorsIntoHeadingsWithMaps } from './anchor';\nimport { buildMokujiHierarchy } from './mokuji-core';\nimport { MOKUJI_LIST_DATASET_ATTRIBUTE, defaultOptions } from './utils/constants';\n\nexport type MokujiResult<T extends HTMLElement = HTMLElement> = {\n element?: T;\n list: HTMLUListElement | HTMLOListElement;\n destroy: () => void;\n};\n\nexport { MokujiOption, HeadingLevel };\n\n/**\n * Process option settings, merge with default values, and restrict to valid range\n */\nconst processOptions = (externalOptions?: MokujiOption): Required<MokujiOption> => {\n const merged = {\n ...defaultOptions,\n ...externalOptions,\n };\n\n const minLevel = Math.max(1, Math.min(merged.minLevel, 6)) as HeadingLevel;\n const maxLevel = Math.max(minLevel, Math.min(merged.maxLevel, 6)) as HeadingLevel;\n\n return { ...merged, minLevel, maxLevel };\n};\n\n/**\n * Generate table of contents from headings within the given element (public API)\n */\nexport const Mokuji = <T extends HTMLElement>(\n element: T | undefined,\n externalOptions?: MokujiOption,\n): MokujiResult<T> | undefined => {\n if (!element) {\n console.warn('Mokuji: Target element not found.');\n return undefined;\n }\n\n const options = processOptions(externalOptions);\n\n const { minLevel, maxLevel, includeBlockquoteHeadings } = options;\n const filteredHeadings = getFilteredHeadings(element, minLevel, maxLevel, { includeBlockquoteHeadings });\n\n if (filteredHeadings.length === 0) {\n return undefined;\n }\n\n const listContainer = createElement(options.anchorContainerTagName);\n listContainer.setAttribute(MOKUJI_LIST_DATASET_ATTRIBUTE, '');\n\n buildMokujiHierarchy(filteredHeadings, listContainer, options.anchorType);\n\n const anchors = [...listContainer.querySelectorAll('a')];\n\n if (anchors.length === 0) {\n return undefined;\n }\n\n ensureUniqueHeadingIds(filteredHeadings, anchors);\n\n const insertedAnchors = options.anchorLink\n ? insertAnchorsIntoHeadingsWithMaps(\n filteredHeadings,\n createAnchorMap(anchors),\n createTextToAnchorMap(anchors),\n options,\n )\n : [];\n\n const destroy = () => {\n listContainer.remove();\n\n for (const anchor of insertedAnchors) {\n anchor.remove();\n }\n };\n\n return { element, list: listContainer, destroy };\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mokuji.js",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "A table of content JavaScript Library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"table of content",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
|
-
"url": "https://github.com/hiro0218/mokuji.js.git"
|
|
17
|
+
"url": "git+https://github.com/hiro0218/mokuji.js.git"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"author": "hiro",
|