mokuji.js 4.8.0 → 5.0.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 +161 -7
- package/dist/index.d.ts +54 -64
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +39 -37
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
mokuji.js
|
|
2
|
-
===
|
|
1
|
+
# mokuji.js
|
|
3
2
|
|
|
4
3
|
A table of content JavaScript Library.
|
|
5
4
|
|
|
5
|
+
> "mokuji" means "table of contents" in Japanese.
|
|
6
|
+
|
|
6
7
|
## Installation
|
|
7
8
|
|
|
8
9
|
```bash
|
|
@@ -14,15 +15,153 @@ npm install --save mokuji.js
|
|
|
14
15
|
```javascript
|
|
15
16
|
import { Mokuji } from 'mokuji.js';
|
|
16
17
|
|
|
18
|
+
// Get the element containing your content with headings
|
|
17
19
|
const textElement = document.querySelector('.text');
|
|
18
|
-
|
|
20
|
+
if (!textElement) {
|
|
21
|
+
console.warn('Target element not found');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
// Generate the table of contents
|
|
26
|
+
const result = Mokuji(textElement);
|
|
27
|
+
if (!result) {
|
|
28
|
+
console.warn('No headings found in the element');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
21
31
|
|
|
32
|
+
// Append the generated list to your container
|
|
22
33
|
const listElement = document.querySelector('.list');
|
|
23
|
-
listElement
|
|
34
|
+
if (listElement) {
|
|
35
|
+
listElement.appendChild(result.list);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Clean up when no longer needed (instance-scoped)
|
|
39
|
+
// For SPAs: Call on component unmount
|
|
40
|
+
// For regular pages: Call on page unload
|
|
41
|
+
result.destroy();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### TypeScript
|
|
45
|
+
|
|
46
|
+
Full TypeScript support with type definitions included:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { Mokuji, MokujiOption, MokujiResult } from 'mokuji.js';
|
|
50
|
+
|
|
51
|
+
const options: MokujiOption = {
|
|
52
|
+
anchorType: true, // true: Wikipedia-style, false: RFC 3986 compliant
|
|
53
|
+
anchorLink: true, // Enable anchor links in headings
|
|
54
|
+
anchorLinkSymbol: '🔗', // Symbol for anchor links
|
|
55
|
+
minLevel: 2, // Start from h2 (skip h1)
|
|
56
|
+
maxLevel: 4, // Include up to h4
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const element = document.querySelector<HTMLElement>('.content');
|
|
60
|
+
if (!element) {
|
|
61
|
+
console.warn('Content element not found');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const result: MokujiResult | undefined = Mokuji(element, options);
|
|
66
|
+
if (!result) {
|
|
67
|
+
console.warn('No headings found within specified levels');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const tocContainer = document.querySelector<HTMLElement>('.toc');
|
|
72
|
+
if (tocContainer) {
|
|
73
|
+
tocContainer.appendChild(result.list);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Cleanup when component unmounts or page unloads
|
|
77
|
+
result.destroy();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Cleanup Examples
|
|
81
|
+
|
|
82
|
+
The `destroy()` method removes generated IDs and anchor links. Call it when the TOC is no longer needed:
|
|
83
|
+
|
|
84
|
+
#### React
|
|
85
|
+
|
|
86
|
+
```jsx
|
|
87
|
+
import { useEffect, useRef } from 'react';
|
|
88
|
+
import { Mokuji } from 'mokuji.js';
|
|
89
|
+
|
|
90
|
+
function TableOfContents({ contentRef }) {
|
|
91
|
+
const tocRef = useRef(null);
|
|
92
|
+
const resultRef = useRef(null);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (contentRef.current && tocRef.current) {
|
|
96
|
+
const result = Mokuji(contentRef.current);
|
|
97
|
+
if (result) {
|
|
98
|
+
tocRef.current.appendChild(result.list);
|
|
99
|
+
resultRef.current = result;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Cleanup on unmount
|
|
104
|
+
return () => {
|
|
105
|
+
resultRef.current?.destroy();
|
|
106
|
+
};
|
|
107
|
+
}, [contentRef]);
|
|
108
|
+
|
|
109
|
+
return <div ref={tocRef} className="toc" />;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Anchor Type Examples
|
|
114
|
+
|
|
115
|
+
The `anchorType` option controls how heading IDs are encoded:
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
// Wikipedia-style encoding (anchorType: true, default)
|
|
119
|
+
const wikiStyle = Mokuji(element, {
|
|
120
|
+
anchorType: true,
|
|
121
|
+
anchorLink: true,
|
|
122
|
+
});
|
|
123
|
+
// Result: "Hello World" → "Hello_World"
|
|
124
|
+
// "日本語" → ".E6.97.A5.E6.9C.AC.E8.AA.9E"
|
|
125
|
+
|
|
126
|
+
// RFC 3986 compliant encoding (anchorType: false)
|
|
127
|
+
const standardStyle = Mokuji(element, {
|
|
128
|
+
anchorType: false,
|
|
129
|
+
anchorLink: true,
|
|
130
|
+
});
|
|
131
|
+
// Result: "Hello World" → "Hello%20World"
|
|
132
|
+
// "日本語" → "%E6%97%A5%E6%9C%AC%E8%AA%9E"
|
|
24
133
|
```
|
|
25
134
|
|
|
135
|
+
Choose `anchorType: true` for compatibility with Wikipedia-style URLs or when you prefer underscores over percent-encoding. Choose `anchorType: false` for standard URL encoding that works universally with all web frameworks and browsers.
|
|
136
|
+
|
|
137
|
+
## API
|
|
138
|
+
|
|
139
|
+
### `Mokuji(element, options)`
|
|
140
|
+
|
|
141
|
+
Generates a table of contents from heading elements within the specified element.
|
|
142
|
+
|
|
143
|
+
**Parameters:**
|
|
144
|
+
|
|
145
|
+
- `element`: HTMLElement - The container element to scan for headings
|
|
146
|
+
- `options`: MokujiOption (optional) - Configuration options
|
|
147
|
+
|
|
148
|
+
**Returns:**
|
|
149
|
+
|
|
150
|
+
- `MokujiResult` object with:
|
|
151
|
+
- `element`: The original element passed
|
|
152
|
+
- `list`: `HTMLOListElement | HTMLUListElement` - The generated table of contents
|
|
153
|
+
- `destroy()`: Function - Removes this instance's generated content
|
|
154
|
+
|
|
155
|
+
Returns `undefined` if no headings are found.
|
|
156
|
+
|
|
157
|
+
## Important Notes
|
|
158
|
+
|
|
159
|
+
- **Duplicate Headings**: When multiple headings have the same text, they are automatically assigned unique IDs with numeric suffixes (e.g., `section`, `section_1`, `section_2`).
|
|
160
|
+
|
|
161
|
+
- **RFC 3986 Compliance**: When `anchorType` is `false`, generated anchors are fully RFC 3986 compliant for use as URI fragment identifiers.
|
|
162
|
+
|
|
163
|
+
- **Instance-scoped Cleanup**: Each `Mokuji()` call returns its own `destroy()` function, allowing multiple TOC instances to coexist without conflicts.
|
|
164
|
+
|
|
26
165
|
## Options
|
|
27
166
|
|
|
28
167
|
```javascript
|
|
@@ -42,10 +181,22 @@ listElement?.appendChild(mokujiList);
|
|
|
42
181
|
|
|
43
182
|
(default: `true`)
|
|
44
183
|
|
|
45
|
-
|
|
184
|
+
Controls the anchor text encoding format.
|
|
46
185
|
|
|
47
|
-
|
|
186
|
+
- `true`: **Wikipedia-style format** - Spaces replaced with underscores, then URL-encoded with percent signs replaced by dots.
|
|
48
187
|
|
|
188
|
+
```
|
|
189
|
+
"Hello World" → "Hello_World"
|
|
190
|
+
"Section: Title" → "Section_Title"
|
|
191
|
+
"こんにちは" → ".E3.81.93.E3.82.93.E3.81.AB.E3.81.A1.E3.81.AF"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
- `false`: **RFC 3986 compliant format** - Standard URI fragment identifier encoding using `encodeURIComponent`.
|
|
195
|
+
```
|
|
196
|
+
"Hello World" → "Hello%20World"
|
|
197
|
+
"Section: Title" → "Section%3A%20Title"
|
|
198
|
+
"こんにちは" → "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF"
|
|
199
|
+
```
|
|
49
200
|
|
|
50
201
|
### `anchorLink`
|
|
51
202
|
|
|
@@ -89,3 +240,6 @@ set the minimum heading level to include in the table of contents (1 means h1).
|
|
|
89
240
|
|
|
90
241
|
set the maximum heading level to include in the table of contents (6 means h6).
|
|
91
242
|
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,80 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
* 目次生成のための型定義を提供するモジュール
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* 目次コンテナとして使用可能なHTML要素タグ名
|
|
6
|
-
*/
|
|
1
|
+
//#region src/types.d.ts
|
|
7
2
|
type AnchorContainerTagName = 'ul' | 'ol';
|
|
8
3
|
/**
|
|
9
|
-
*
|
|
4
|
+
* Type representing heading levels (values 1-6 corresponding to h1-h6)
|
|
10
5
|
*/
|
|
11
6
|
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
12
7
|
/**
|
|
13
|
-
*
|
|
8
|
+
* Anchor link placement position
|
|
14
9
|
*/
|
|
15
10
|
type AnchorLinkPosition = 'before' | 'after';
|
|
16
11
|
/**
|
|
17
|
-
*
|
|
12
|
+
* Option settings for TOC generation
|
|
18
13
|
*/
|
|
19
14
|
type MokujiOption = {
|
|
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
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Whether to generate Wikipedia-style anchors
|
|
17
|
+
* Default: true (e.g., "heading_text" -> "heading_text", "heading:text" -> "headingtext")
|
|
18
|
+
* If false, spaces are replaced with '_' but encoding and special character conversion is minimal
|
|
19
|
+
*/
|
|
20
|
+
anchorType?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to add anchor links (e.g., #) next to heading elements
|
|
23
|
+
* Default: false
|
|
24
|
+
*/
|
|
25
|
+
anchorLink?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Symbol or text to display when `anchorLink: true`
|
|
28
|
+
* Default: '#'
|
|
29
|
+
*/
|
|
30
|
+
anchorLinkSymbol?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Anchor link placement position (before or after heading text) when `anchorLink: true`
|
|
33
|
+
* Default: 'before'
|
|
34
|
+
*/
|
|
35
|
+
anchorLinkPosition?: AnchorLinkPosition;
|
|
36
|
+
/**
|
|
37
|
+
* CSS class names to apply to anchor link elements when `anchorLink: true` (multiple classes can be specified with space separation)
|
|
38
|
+
* Default: ''
|
|
39
|
+
*/
|
|
40
|
+
anchorLinkClassName?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Tag name of the generated TOC list container element
|
|
43
|
+
* Default: 'ol' (ordered list)
|
|
44
|
+
*/
|
|
45
|
+
anchorContainerTagName?: AnchorContainerTagName;
|
|
46
|
+
/**
|
|
47
|
+
* Minimum heading level to include in TOC (1 = h1, 6 = h6)
|
|
48
|
+
* Default: 1
|
|
49
|
+
*/
|
|
50
|
+
minLevel?: HeadingLevel;
|
|
51
|
+
/**
|
|
52
|
+
* Maximum heading level to include in TOC (1 = h1, 6 = h6)
|
|
53
|
+
* Default: 6
|
|
54
|
+
*/
|
|
55
|
+
maxLevel?: HeadingLevel;
|
|
61
56
|
};
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* 目次生成の結果型定義
|
|
65
|
-
*/
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/index.d.ts
|
|
66
59
|
type MokujiResult<T extends HTMLElement = HTMLElement> = {
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
element?: T;
|
|
61
|
+
list: HTMLUListElement | HTMLOListElement;
|
|
62
|
+
destroy: () => void;
|
|
69
63
|
};
|
|
70
|
-
|
|
71
64
|
/**
|
|
72
|
-
*
|
|
65
|
+
* Generate table of contents from headings within the given element (public API)
|
|
73
66
|
*/
|
|
74
67
|
declare const Mokuji: <T extends HTMLElement>(element: T | undefined, externalOptions?: MokujiOption) => MokujiResult<T> | undefined;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
declare const Destroy: () => void;
|
|
79
|
-
|
|
80
|
-
export { Destroy, type HeadingLevel, Mokuji, type MokujiOption, type MokujiResult };
|
|
68
|
+
//#endregion
|
|
69
|
+
export { HeadingLevel, Mokuji, MokujiOption, MokujiResult };
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
const e=e=>[...e.querySelectorAll(`h1, h2, h3, h4, h5, h6`)],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)}else 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=[...t],r=new Set,i=new Map,a=new Map,o=new Set;for(let[t,n]of e.entries()){let e=n.id||`mokuji-heading-${t}`,r=d(e);a.set(t,{originalId:e,decodedId:r}),o.add(r)}for(let[t,c]of e.entries()){let e=n[t],{originalId:l,decodedId:u}=a.get(t);if(!r.has(u)){c.id=l,r.add(u),e&&(e.href=`#${l}`);continue}let d=u.replace(s,``)||u,f=(i.get(d)||0)+1,p,m=f;for(;;){if(p=`${d}_${m}`,!r.has(p)&&!o.has(p)){f=m;break}if(o.has(p)&&!r.has(p)){m++;continue}m++}i.set(d,f),c.id=p,r.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)=>{let i=[],a=e(t);for(let e of a){let t=m(e);t>=n&&t<=r&&i.push(e)}return i},g=`data-mokuji-anchor`,_={anchorType:!0,anchorLink:!1,anchorLinkSymbol:`#`,anchorLinkPosition:`before`,anchorLinkClassName:``,anchorContainerTagName:`ol`,minLevel:1,maxLevel:6},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)return e.get(n)},C=(e,t,n,r)=>{let i=b(e,t);if(i)return i;let a=x(e,t);if(a)return a;if(r)return S(r,n);{let t=n.trim();if(!t)return;for(let[,n]of e.entries())if(n.textContent?.trim()===t)return n;return}},w=(e,t)=>{let n=t.trim();n&&e.classList.add(...n.split(/\s+/).filter(Boolean))},T=e=>{let n=t(`a`);return n.setAttribute(g,``),w(n,e.anchorLinkClassName),n},E=(e,t,n,r,i)=>{let a=e.id,o=C(t,a,e.textContent||``,i);if(!o)return;let s=n.cloneNode(!1);return s.href=o.hash,s.textContent=r.anchorLinkSymbol,s},D=e=>{let t=e.querySelectorAll(`[${g}]`);n(t)},O=(e,t,n=`before`)=>{n===`before`?e.insertBefore(t,e.firstChild):e.append(t)},k=(e,t,n,r)=>{let i=T(n),a=[];for(let o of e){D(o);let e=E(o,t,i,n,r);if(!e)continue;O(o,e,n.anchorLinkPosition),a.push(e)}return a},A=(e,t,n,r)=>k(e,t,r,n),j=(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},M=(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)},N=(e,t,n)=>{let r=j(e,n);M(r,t)},P=e=>{let t={..._,...e};return t.minLevel=Math.max(1,Math.min(t.minLevel,6)),t.maxLevel=Math.max(t.minLevel,Math.min(t.maxLevel,6)),t},F=(e,n)=>{if(!e){console.warn(`Mokuji: Target element not found.`);return}let r=P(n),{minLevel:i,maxLevel:a}=r,o=h(e,i,a);if(o.length===0)return;let s=t(r.anchorContainerTagName);s.setAttribute(`data-mokuji-list`,``),N(o,s,r.anchorType);let c=[...s.querySelectorAll(`a`)];if(c.length===0)return;p(o,c);let l=[];if(r.anchorLink){let e=v(c),t=y(c),n=A(o,e,t,r);l.push(...n)}return{element:e,list:s,destroy:()=>{s.remove();for(let e of l)e.remove()}}};export{F as Mokuji};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/common/dom.ts","../src/heading/text.ts","../src/heading/heading.ts","../src/common/constants.ts","../src/anchor/anchor.ts","../src/toc/core.ts","../src/index.ts"],"names":["getAllHeadingElements","containerElement","elementCache","createElement","tagName","WHITESPACE_PATTERN","COLON_CHARACTER","AMPERSAND_PATTERN","AMPERSAND_ENTITY_PATTERN","PERCENT_ENCODING_PATTERN","DOT_REPLACEMENT","replaceSpacesWithUnderscores","text","convertToWikipediaStyleAnchor","anchor","generateAnchorText","baseId","isConvertToWikipediaStyleAnchor","anchorText","VALID_PERCENT_ENCODING","INVALID_PERCENT_PATTERN","safeDecodeURIComponent","encoded","assignInitialIdToHeading","heading","baseHeadingId","getFilteredHeadings","element","minLevel","maxLevel","filteredHeadings","allHeadings","i","level","groupAnchorsByHeadingId","anchors","idToAnchorsMap","rawHeadingId","headingId","anchorsForId","ensureUniqueHeadingIds","headings","headingIdOccurrenceMap","currentHeadingId","occurrenceCount","uniqueHeadingId","originalIdDecoded","matchingAnchors","j","MOKUJI_LIST_DATASET_ATTRIBUTE","ANCHOR_DATASET_ATTRIBUTE","defaultOptions","generateAnchorsMap","result","applyClassNamesToElement","classNameString","trimmedClassNames","createAnchorTemplate","options","anchorTemplate","placeAnchorInHeading","position","createAnchorForHeading","anchorMap","matchedTocAnchor","idWithoutSuffix","headingText","anchorElement","createHeadingAnchorPair","insertAnchorToHeadings","headingsByParent","pair","parent","existingPairs","headingsWithAnchors","generateTableOfContents","listContainer","rootLevelItems","levelStack","headingsLength","currentHeadingLevel","newItem","stackIndex","currentStackTop","listItemTemplate","childListTagName","childListTemplate","buildListRecursive","parentListElement","items","item","elementList","elementAnchor","childListContainer","processOptions","externalOptions","generateTocAndAnchorsInternal","Mokuji","anchorsMap","Destroy","mokujiAnchors","tableOfContentsList"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * DOM操作のための共通ユーティリティ関数\n */\n\n/**\n * h1からh6までのすべての見出し要素を取得する\n */\nexport const getAllHeadingElements = (containerElement: Element): HTMLHeadingElement[] => {\n const headings = containerElement.querySelectorAll('h1, h2, h3, h4, h5, h6');\n return [...headings] as HTMLHeadingElement[];\n};\n\n/**\n * 指定したタグ名の新しいHTML要素を作成する\n */\nconst elementCache = new Map<string, HTMLElement>();\n\nexport const createElement = <T extends keyof HTMLElementTagNameMap>(tagName: T): HTMLElementTagNameMap[T] => {\n if (!elementCache.has(tagName)) {\n elementCache.set(tagName, document.createElement(tagName));\n }\n\n const cachedElement = elementCache.get(tagName)!;\n\n return cachedElement.cloneNode(false) as HTMLElementTagNameMap[T];\n};\n","/**\n * テキスト処理とアンカーテキスト生成のためのユーティリティ関数\n */\n\n// 正規表現定義\nconst WHITESPACE_PATTERN = /\\s+/g;\nconst COLON_CHARACTER = ':';\nconst AMPERSAND_PATTERN = /&+/g;\nconst AMPERSAND_ENTITY_PATTERN = /&+/g;\nconst PERCENT_ENCODING_PATTERN = /%+/g;\nconst DOT_REPLACEMENT = '.';\n\n/**\n * テキスト内のスペースをアンダースコアに置換し、コロンを除去する\n */\nconst replaceSpacesWithUnderscores = (text: string): string => {\n return text.replaceAll(WHITESPACE_PATTERN, '_').replace(COLON_CHARACTER, '');\n};\n\n/**\n * テキストをWikipediaスタイルのアンカー形式(パーセントエンコーディング後に%を.に置換)に変換する\n */\nconst convertToWikipediaStyleAnchor = (anchor: string): string => {\n return encodeURIComponent(anchor).replaceAll(PERCENT_ENCODING_PATTERN, DOT_REPLACEMENT);\n};\n\n/**\n * アンカーテキストを生成する\n * HTMLのid属性やhrefで使用される最終的な文字列を生成する。\n */\nexport const generateAnchorText = (baseId: string, isConvertToWikipediaStyleAnchor: boolean): string => {\n let anchorText = replaceSpacesWithUnderscores(baseId);\n\n if (isConvertToWikipediaStyleAnchor) {\n anchorText = convertToWikipediaStyleAnchor(anchorText);\n }\n\n if (!isConvertToWikipediaStyleAnchor && anchorText.includes('&')) {\n anchorText = anchorText.replaceAll(AMPERSAND_PATTERN, '').replaceAll(AMPERSAND_ENTITY_PATTERN, '');\n }\n\n return anchorText;\n};\n","/**\n * 見出し要素の処理(ID割り当て、フィルタリング、重複解決)に関するユーティリティを提供するモジュール\n */\nimport { generateAnchorText } from './text';\nimport { getAllHeadingElements } from '../common/dom';\nimport type { HeadingLevel } from '../common/types';\n\n/**\n * URLエンコード文字列の妥当性をチェックする正規表現\n * %の後に2桁の16進数が続くパターンが正しいものとみなす\n */\nconst VALID_PERCENT_ENCODING = /%[0-9A-F]{2}/gi;\nconst INVALID_PERCENT_PATTERN = /%[^0-9A-F]|%[0-9A-F][^0-9A-F]|%$/i;\n\n/**\n * URIコンポーネントを安全にデコードする(例外を発生させない)\n * 不正なエンコーディングの場合は元の文字列を返す\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 * 見出し要素に初期ID(アンカーテキスト)を割り当てる\n * この時点ではIDの重複可能性があるため、後続の ensureUniqueHeadingIds で解決される。\n */\nexport const assignInitialIdToHeading = (\n heading: HTMLHeadingElement,\n isConvertToWikipediaStyleAnchor: boolean,\n): string => {\n const baseHeadingId = (heading.textContent || '').trim();\n const anchorText = generateAnchorText(baseHeadingId, isConvertToWikipediaStyleAnchor);\n heading.id = anchorText;\n return anchorText;\n};\n\n/**\n * 指定したレベル範囲内の見出し要素を取得する\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 (let i = 0; i < allHeadings.length; i++) {\n const heading = allHeadings[i];\n const level = Number(heading.tagName.at(1)) as HeadingLevel;\n if (level >= minLevel && level <= maxLevel) {\n filteredHeadings.push(heading);\n }\n }\n\n return filteredHeadings;\n};\n\n/**\n * アンカー要素をhrefのハッシュ値(デコード済み)ごとにグループ化する\n */\nconst groupAnchorsByHeadingId = (anchors: HTMLAnchorElement[]): Map<string, HTMLAnchorElement[]> => {\n const idToAnchorsMap = new Map<string, HTMLAnchorElement[]>();\n\n for (let i = 0; i < anchors.length; i++) {\n const anchor = anchors[i];\n if (anchor.hash && anchor.hash.length > 1) {\n const rawHeadingId = anchor.hash.slice(1);\n const headingId = safeDecodeURIComponent(rawHeadingId);\n\n const anchorsForId = idToAnchorsMap.get(headingId) || [];\n anchorsForId.push(anchor);\n idToAnchorsMap.set(headingId, anchorsForId);\n }\n }\n\n return idToAnchorsMap;\n};\n\n/**\n * 見出し要素のIDが重複している場合に一意になるよう修正し、関連する目次アンカーのhrefも更新する\n */\nexport const ensureUniqueHeadingIds = (headings: HTMLHeadingElement[], anchors: HTMLAnchorElement[]) => {\n const headingIdOccurrenceMap = new Map<string, number>();\n const idToAnchorsMap = groupAnchorsByHeadingId(anchors);\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const currentHeadingId = heading.id;\n const occurrenceCount = headingIdOccurrenceMap.get(currentHeadingId) || 0;\n\n if (occurrenceCount > 0) {\n const uniqueHeadingId = `${currentHeadingId}_${occurrenceCount}`;\n heading.id = uniqueHeadingId;\n\n const originalIdDecoded = safeDecodeURIComponent(currentHeadingId);\n\n if (originalIdDecoded) {\n const matchingAnchors = idToAnchorsMap.get(originalIdDecoded) || [];\n for (let j = 0; j < matchingAnchors.length; j++) {\n const anchor = matchingAnchors[j];\n anchor.href = `#${uniqueHeadingId}`;\n }\n }\n }\n\n headingIdOccurrenceMap.set(heading.id, occurrenceCount + 1);\n }\n};\n","/**\n * 目次生成で使用する定数を提供するモジュール\n */\n\nimport type { MokujiOption } from './types';\n\n/**\n * 目次関連の要素を識別するためのデータ属性\n */\nexport const MOKUJI_LIST_DATASET_ATTRIBUTE = 'data-mokuji-list'; // 目次リスト本体\nexport const ANCHOR_DATASET_ATTRIBUTE = 'data-mokuji-anchor'; // 見出し横に挿入されるアンカー\n\n/**\n * デフォルトオプション設定\n */\nexport const defaultOptions: Required<MokujiOption> = {\n anchorType: true, // Wikipediaスタイルのアンカーを生成\n anchorLink: false, // 見出しへのアンカーリンクを追加\n anchorLinkSymbol: '#', // アンカーリンクのシンボル\n anchorLinkPosition: 'before', // アンカーリンクの位置\n anchorLinkClassName: '', // アンカーリンクのCSSクラス名\n anchorContainerTagName: 'ol', // 目次のコンテナ要素\n minLevel: 1, // 最小見出しレベル\n maxLevel: 6, // 最大見出しレベル\n} as const; // as const ensures the object is treated as readonly with literal types\n","/**\n * 見出し横へのアンカーリンク挿入に関する処理を提供するモジュール\n */\n\nimport { createElement } from '../common/dom';\nimport { ANCHOR_DATASET_ATTRIBUTE } from '../common/constants';\nimport type { MokujiOption, AnchorLinkPosition } from '../common/types';\n\n/**\n * 目次内のアンカー要素から、そのhrefのハッシュ値をキーとするマップを作成する\n */\nexport const generateAnchorsMap = (anchors: HTMLAnchorElement[]): Map<string, HTMLAnchorElement> => {\n const result = new Map<string, HTMLAnchorElement>();\n\n for (let i = 0; i < anchors.length; i++) {\n const anchor = anchors[i];\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 * 要素に複数のクラス名を適用する\n */\nconst 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 * アンカーテンプレート要素を作成する\n */\nconst createAnchorTemplate = (options: Required<MokujiOption>): HTMLAnchorElement => {\n const anchorTemplate = createElement('a');\n anchorTemplate.setAttribute(ANCHOR_DATASET_ATTRIBUTE, '');\n\n // anchorLinkClassNameが空文字列の場合でもクラス名適用処理を実行する\n // 空文字列の場合はapplyClassNamesToElement内で早期リターンされる\n applyClassNamesToElement(anchorTemplate, options.anchorLinkClassName);\n\n return anchorTemplate;\n};\n\n/**\n * 見出し要素内の指定した位置にアンカー要素を挿入する\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 * ある見出し要素に対応するアンカー要素を作成する\n */\nconst createAnchorForHeading = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n): HTMLAnchorElement | undefined => {\n const headingId = heading.id;\n let matchedTocAnchor = anchorMap.get(headingId);\n\n // headingIdから直接対応するアンカーが見つからない場合\n if (!matchedTocAnchor) {\n // IDが「ID_数字」の形式かチェックする(重複により変更されたIDの場合)\n const idWithoutSuffix = headingId.replace(/_\\d+$/, '');\n if (idWithoutSuffix !== headingId) {\n // サフィックスを取り除いた元のIDでアンカーを検索\n matchedTocAnchor = anchorMap.get(idWithoutSuffix);\n }\n\n // それでも見つからない場合はテキスト内容をベースに検索\n if (!matchedTocAnchor) {\n const headingText = heading.textContent?.trim() || '';\n // アンカーマップ内をテキスト内容で検索\n for (const [, anchor] of anchorMap.entries()) {\n if (anchor.textContent?.trim() === headingText) {\n matchedTocAnchor = anchor;\n break;\n }\n }\n }\n\n // 最終的にもマッチするアンカーが見つからなかった場合\n if (!matchedTocAnchor) {\n return undefined;\n }\n }\n\n const anchorElement = anchorTemplate.cloneNode(false) as HTMLAnchorElement;\n anchorElement.href = matchedTocAnchor.hash;\n\n anchorElement.textContent = options.anchorLinkSymbol;\n\n return anchorElement;\n};\n\n/**\n * 見出しと、それに対応する見出し横アンカーのペア\n */\ntype HeadingAnchorPair = {\n heading: HTMLHeadingElement;\n anchor: HTMLAnchorElement;\n};\n\n/**\n * 有効な見出しとアンカーのペアを作成する\n */\nconst createHeadingAnchorPair = (\n heading: HTMLHeadingElement,\n anchorMap: Map<string, HTMLAnchorElement>,\n anchorTemplate: HTMLAnchorElement,\n options: Required<MokujiOption>,\n): HeadingAnchorPair | undefined => {\n if (!heading.parentNode) return undefined;\n\n const anchor = createAnchorForHeading(heading, anchorMap, anchorTemplate, options);\n if (!anchor) return undefined;\n\n return { heading, anchor };\n};\n\n/**\n * 見出し要素にアンカーリンクを追加する\n */\nexport const insertAnchorToHeadings = (\n headings: HTMLHeadingElement[],\n anchorMap: Map<string, HTMLAnchorElement>,\n options: Required<MokujiOption>,\n): void => {\n const anchorTemplate = createAnchorTemplate(options);\n\n const headingsByParent = new Map<Node, HeadingAnchorPair[]>();\n\n for (let i = 0; i < headings.length; i++) {\n const heading = headings[i];\n const pair = createHeadingAnchorPair(heading, anchorMap, anchorTemplate, options);\n if (!pair || !pair.heading.parentNode) continue;\n\n const parent = pair.heading.parentNode;\n const existingPairs = headingsByParent.get(parent) || [];\n existingPairs.push(pair);\n headingsByParent.set(parent, existingPairs);\n }\n\n for (const [, headingsWithAnchors] of headingsByParent.entries()) {\n for (let j = 0; j < headingsWithAnchors.length; j++) {\n const { heading, anchor } = headingsWithAnchors[j];\n placeAnchorInHeading(heading, anchor, options.anchorLinkPosition);\n }\n }\n};\n","/**\n * 目次(もくじ)生成の中核ロジックを提供するモジュール (パフォーマンス改善版)\n */\nimport { createElement } from '../common/dom';\nimport { assignInitialIdToHeading } from '../heading/heading';\n\n/**\n * 目次アイテムの中間データ構造\n */\ntype TocItem = {\n text: string | null;\n href: string;\n level: number;\n children: TocItem[];\n};\n\n/**\n * 目次コンテナ要素の型 (ul または ol)\n */\ntype TableOfContentsContainer = HTMLUListElement | HTMLOListElement;\n\n/**\n * 見出し要素から階層構造を持つ目次データ構造を生成し、DOMを一括構築する\n *\n * @param headings 処理対象の見出し要素配列\n * @param listContainer 目次を格納するコンテナ要素 (ul or ol)\n * @param isConvertToWikipediaStyleAnchor Wikipediaスタイルのアンカー生成を行うかどうかのフラグ\n */\nexport const generateTableOfContents = (\n headings: HTMLHeadingElement[],\n listContainer: TableOfContentsContainer,\n isConvertToWikipediaStyleAnchor: boolean,\n): void => {\n const rootLevelItems: TocItem[] = [];\n const levelStack: { level: number; items: TocItem[] }[] = [];\n levelStack.push({ level: 0, items: rootLevelItems });\n\n const headingsLength = headings.length;\n for (let i = 0; i < headingsLength; i++) {\n const heading = headings[i];\n const currentHeadingLevel = Number(heading.tagName[1]);\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 let stackIndex = levelStack.length - 1;\n let currentStackTop = levelStack[stackIndex];\n\n while (currentHeadingLevel <= currentStackTop.level && stackIndex > 0) {\n levelStack.pop();\n stackIndex--;\n currentStackTop = levelStack[stackIndex];\n }\n\n currentStackTop.items.push(newItem);\n levelStack.push({ level: currentHeadingLevel, items: newItem.children });\n }\n\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, items: TocItem[]): void => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const elementList = listItemTemplate.cloneNode(false) as HTMLLIElement;\n const elementAnchor = anchorTemplate.cloneNode(false) as HTMLAnchorElement;\n\n elementAnchor.href = item.href;\n elementAnchor.textContent = item.text;\n elementList.append(elementAnchor);\n\n if (item.children.length > 0) {\n const childListContainer = childListTemplate.cloneNode(false) as TableOfContentsContainer;\n buildListRecursive(childListContainer, item.children);\n elementList.append(childListContainer);\n }\n parentListElement.append(elementList);\n }\n };\n\n buildListRecursive(listContainer, rootLevelItems);\n};\n","/**\n * 目次(もくじ)生成ライブラリのメインエントリーポイント\n */\nimport { createElement } from './common/dom';\nimport type { MokujiOption, HeadingLevel } from './common/types';\nimport { getFilteredHeadings, ensureUniqueHeadingIds } from './heading/heading';\nimport { generateAnchorsMap, insertAnchorToHeadings } from './anchor/anchor';\nimport { generateTableOfContents } from './toc/core';\nimport { MOKUJI_LIST_DATASET_ATTRIBUTE, ANCHOR_DATASET_ATTRIBUTE, defaultOptions } from './common/constants';\n\n/**\n * 目次生成の結果型定義\n */\nexport type MokujiResult<T extends HTMLElement = HTMLElement> = {\n element?: T;\n list: HTMLUListElement | HTMLOListElement;\n};\n\n// 型エクスポート\nexport { MokujiOption, HeadingLevel };\n\n/**\n * オプション設定を処理し、デフォルト値とマージして有効な範囲内に制限する\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 * 目次生成の主要ロジック(内部関数)\n */\nconst generateTocAndAnchorsInternal = (\n filteredHeadings: HTMLHeadingElement[],\n options: Required<MokujiOption>,\n): { listContainer: HTMLUListElement | HTMLOListElement; anchors: HTMLAnchorElement[] } => {\n const listContainer = createElement(options.anchorContainerTagName);\n listContainer.setAttribute(MOKUJI_LIST_DATASET_ATTRIBUTE, '');\n\n generateTableOfContents(filteredHeadings, listContainer, options.anchorType);\n\n const anchors = [...listContainer.querySelectorAll('a')];\n\n return { listContainer, anchors };\n};\n\n/**\n * 与えられた要素内の見出しから目次を生成する (公開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 const { listContainer, anchors } = generateTocAndAnchorsInternal(filteredHeadings, options);\n\n if (anchors.length === 0) {\n return undefined;\n }\n\n ensureUniqueHeadingIds(filteredHeadings, anchors);\n\n if (options.anchorLink) {\n const anchorsMap = generateAnchorsMap(anchors);\n insertAnchorToHeadings(filteredHeadings, anchorsMap, options);\n }\n\n return { element, list: listContainer };\n};\n\n/**\n * 生成された目次とアンカーリンクを破棄(削除)する\n */\nexport const Destroy = (): void => {\n const mokujiAnchors = document.querySelectorAll(`[${ANCHOR_DATASET_ATTRIBUTE}]`);\n for (let i = 0; i < mokujiAnchors.length; i++) {\n const anchor = mokujiAnchors[i];\n anchor.remove();\n }\n\n const tableOfContentsList = document.querySelector(`[${MOKUJI_LIST_DATASET_ATTRIBUTE}]`);\n if (tableOfContentsList) {\n tableOfContentsList.remove();\n }\n};\n"]}
|
|
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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"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mokuji.js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "A table of content JavaScript Library",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
"keywords": [
|
|
6
|
+
"table of content",
|
|
7
|
+
"toc",
|
|
8
|
+
"contents",
|
|
9
|
+
"index"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/hiro0218/mokuji.js",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/hiro0218/mokuji.js/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/hiro0218/mokuji.js.git"
|
|
12
18
|
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "hiro",
|
|
21
|
+
"sideEffects": false,
|
|
13
22
|
"type": "module",
|
|
14
|
-
"main": "./dist/index.js",
|
|
15
23
|
"exports": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
24
|
+
".": "./dist/index.js",
|
|
25
|
+
"./package.json": "./package.json"
|
|
18
26
|
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
19
29
|
"types": "./dist/index.d.ts",
|
|
20
30
|
"directories": {
|
|
21
31
|
"lib": "lib"
|
|
@@ -26,6 +36,14 @@
|
|
|
26
36
|
"package.json",
|
|
27
37
|
"README.md"
|
|
28
38
|
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsdown",
|
|
41
|
+
"dev": "tsdown --watch",
|
|
42
|
+
"lint": "eslint --cache ./src/**/*.ts",
|
|
43
|
+
"prepare": "npm run build && husky",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest"
|
|
46
|
+
},
|
|
29
47
|
"lint-staged": {
|
|
30
48
|
"*.{js,ts,tsx}": [
|
|
31
49
|
"eslint --fix --cache",
|
|
@@ -36,36 +54,20 @@
|
|
|
36
54
|
"bash -c 'tsc --noEmit --skipLibCheck'"
|
|
37
55
|
]
|
|
38
56
|
},
|
|
39
|
-
"repository": {
|
|
40
|
-
"type": "git",
|
|
41
|
-
"url": "https://github.com/hiro0218/mokuji.js.git"
|
|
42
|
-
},
|
|
43
|
-
"keywords": [
|
|
44
|
-
"table of content",
|
|
45
|
-
"toc",
|
|
46
|
-
"contents",
|
|
47
|
-
"index"
|
|
48
|
-
],
|
|
49
|
-
"author": "hiro",
|
|
50
|
-
"license": "MIT",
|
|
51
|
-
"bugs": {
|
|
52
|
-
"url": "https://github.com/hiro0218/mokuji.js/issues"
|
|
53
|
-
},
|
|
54
|
-
"homepage": "https://github.com/hiro0218/mokuji.js",
|
|
55
57
|
"devDependencies": {
|
|
56
|
-
"@testing-library/dom": "^10.4.
|
|
57
|
-
"@types/node": "~22.
|
|
58
|
+
"@testing-library/dom": "^10.4.1",
|
|
59
|
+
"@types/node": "~22.15.3",
|
|
58
60
|
"@typescript-eslint/eslint-plugin": "^8.31.1",
|
|
59
|
-
"@vitest/browser": "^3.
|
|
60
|
-
"eslint": "^9.
|
|
61
|
-
"eslint-config-prettier": "^10.1.
|
|
62
|
-
"eslint-plugin-unicorn": "^
|
|
61
|
+
"@vitest/browser": "^3.2.4",
|
|
62
|
+
"eslint": "^9.36.0",
|
|
63
|
+
"eslint-config-prettier": "^10.1.8",
|
|
64
|
+
"eslint-plugin-unicorn": "^61.0.2",
|
|
63
65
|
"husky": "^9.1.7",
|
|
64
66
|
"jsdom": "^26.1.0",
|
|
65
|
-
"lint-staged": "^
|
|
66
|
-
"prettier": "^3.
|
|
67
|
-
"
|
|
67
|
+
"lint-staged": "^16.1.6",
|
|
68
|
+
"prettier": "^3.6.2",
|
|
69
|
+
"tsdown": "^0.15.3",
|
|
68
70
|
"typescript": "~5.8.3",
|
|
69
|
-
"vitest": "^3.
|
|
71
|
+
"vitest": "^3.2.4"
|
|
70
72
|
}
|
|
71
73
|
}
|