@valaxyjs/utils 0.26.0 → 0.26.2
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/dist/{index.d.cts → index.d.mts} +2 -1
- package/dist/index.mjs +82 -1
- package/package.json +12 -9
- package/dist/index.cjs +0 -1
- package/dist/index.d.ts +0 -64
- package/src/client/headers.ts +0 -146
- package/src/client/index.ts +0 -1
- package/src/index.ts +0 -2
- package/src/types/index.ts +0 -40
- package/tsup.config.ts +0 -28
|
@@ -61,4 +61,5 @@ declare function serializeHeader(h: Element): string;
|
|
|
61
61
|
*/
|
|
62
62
|
declare function getHeaders(options?: GetHeadersOptions): MenuItem[];
|
|
63
63
|
|
|
64
|
-
export {
|
|
64
|
+
export { addToParent, buildTree, getHeaders, resolveHeaders, resolvedHeaders, serializeHeader };
|
|
65
|
+
export type { GetHeadersOptions, Header, MenuItem };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1,82 @@
|
|
|
1
|
-
|
|
1
|
+
const resolvedHeaders = [];
|
|
2
|
+
function buildTree(data, min, max) {
|
|
3
|
+
resolvedHeaders.length = 0;
|
|
4
|
+
const result = [];
|
|
5
|
+
const stack = [];
|
|
6
|
+
data.forEach((item) => {
|
|
7
|
+
const node = { ...item, children: [] };
|
|
8
|
+
let parent = stack[stack.length - 1];
|
|
9
|
+
while (parent && parent.level >= node.level) {
|
|
10
|
+
stack.pop();
|
|
11
|
+
parent = stack[stack.length - 1];
|
|
12
|
+
}
|
|
13
|
+
if (node.element.classList.contains("ignore-header") || parent && "shouldIgnore" in parent) {
|
|
14
|
+
stack.push({ level: node.level, shouldIgnore: true });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (node.level > max || node.level < min)
|
|
18
|
+
return;
|
|
19
|
+
resolvedHeaders.push({ element: node.element, link: node.link });
|
|
20
|
+
if (parent)
|
|
21
|
+
parent.children.push(node);
|
|
22
|
+
else result.push(node);
|
|
23
|
+
stack.push(node);
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
function addToParent(currIndex, headers, levelsRange) {
|
|
28
|
+
if (currIndex === 0)
|
|
29
|
+
return true;
|
|
30
|
+
const currentHeader = headers[currIndex];
|
|
31
|
+
for (let index = currIndex - 1; index >= 0; index--) {
|
|
32
|
+
const header = headers[index];
|
|
33
|
+
if (header.level < currentHeader.level && header.level >= levelsRange[0] && header.level <= levelsRange[1]) {
|
|
34
|
+
if (header.children == null)
|
|
35
|
+
header.children = [];
|
|
36
|
+
header.children.push(currentHeader);
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
function resolveHeaders(headers, range = [2, 4]) {
|
|
43
|
+
const levelsRange = (typeof range === "object" && !Array.isArray(range) ? range.level : range) || 2;
|
|
44
|
+
const [high, low] = typeof levelsRange === "number" ? [levelsRange, levelsRange] : levelsRange === "deep" ? [2, 6] : levelsRange;
|
|
45
|
+
return buildTree(headers, high, low);
|
|
46
|
+
}
|
|
47
|
+
function serializeHeader(h) {
|
|
48
|
+
let ret = "";
|
|
49
|
+
for (const node of Array.from(h.childNodes)) {
|
|
50
|
+
if (node.nodeType === 1) {
|
|
51
|
+
if (node.classList.contains("VABadge") || node.classList.contains("header-anchor")) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
ret += node.textContent;
|
|
55
|
+
} else if (node.nodeType === 3) {
|
|
56
|
+
ret += node.textContent;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return ret.trim();
|
|
60
|
+
}
|
|
61
|
+
function getHeaders(options = {
|
|
62
|
+
range: [2, 4],
|
|
63
|
+
selector: ".markdown-body"
|
|
64
|
+
}) {
|
|
65
|
+
const mdBodySelector = options.selector || ".markdown-body";
|
|
66
|
+
const markdownBodyElements = document.querySelectorAll(mdBodySelector);
|
|
67
|
+
const markdownBody = markdownBodyElements[markdownBodyElements.length - 1];
|
|
68
|
+
const headers = Array.from(markdownBody?.querySelectorAll(`${mdBodySelector} :where(h1,h2,h3,h4,h5,h6)`) || []).filter((el) => options.filter ? options.filter(el) : true).map((el) => {
|
|
69
|
+
const level = Number(el.tagName[1]);
|
|
70
|
+
return {
|
|
71
|
+
element: el,
|
|
72
|
+
title: serializeHeader(el),
|
|
73
|
+
link: `#${el.id}`,
|
|
74
|
+
level,
|
|
75
|
+
// @ts-expect-error lang
|
|
76
|
+
lang: el.lang
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
return resolveHeaders(headers, options.range);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { addToParent, buildTree, getHeaders, resolveHeaders, resolvedHeaders, serializeHeader };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valaxyjs/utils",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.26.
|
|
4
|
+
"version": "0.26.2",
|
|
5
5
|
"description": "A utility library for Valaxy",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Valaxy",
|
|
@@ -18,17 +18,20 @@
|
|
|
18
18
|
"utils"
|
|
19
19
|
],
|
|
20
20
|
"exports": {
|
|
21
|
-
".":
|
|
22
|
-
|
|
23
|
-
"import": "./dist/index.mjs",
|
|
24
|
-
"require": "./dist/index.cjs"
|
|
25
|
-
}
|
|
21
|
+
".": "./dist/index.mjs",
|
|
22
|
+
"./package.json": "./package.json"
|
|
26
23
|
},
|
|
27
24
|
"main": "./dist/index.mjs",
|
|
28
25
|
"module": "./dist/index.mjs",
|
|
29
|
-
"types": "./dist/index.d.
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"unbuild": "^3.6.0"
|
|
32
|
+
},
|
|
30
33
|
"scripts": {
|
|
31
|
-
"dev": "
|
|
32
|
-
"build": "
|
|
34
|
+
"dev": "unbuild --stub",
|
|
35
|
+
"build": "unbuild"
|
|
33
36
|
}
|
|
34
37
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";var u=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var b=(n,e)=>{for(var t in e)u(n,t,{get:e[t],enumerable:!0})},y=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of p(e))!g.call(n,r)&&r!==t&&u(n,r,{get:()=>e[r],enumerable:!(o=f(e,r))||o.enumerable});return n};var v=n=>y(u({},"__esModule",{value:!0}),n);var M={};b(M,{addToParent:()=>H,buildTree:()=>d,getHeaders:()=>x,resolveHeaders:()=>c,resolvedHeaders:()=>m,serializeHeader:()=>h});module.exports=v(M);var m=[];function d(n,e,t){m.length=0;let o=[],r=[];return n.forEach(l=>{let s={...l,children:[]},i=r[r.length-1];for(;i&&i.level>=s.level;)r.pop(),i=r[r.length-1];if(s.element.classList.contains("ignore-header")||i&&"shouldIgnore"in i){r.push({level:s.level,shouldIgnore:!0});return}s.level>t||s.level<e||(m.push({element:s.element,link:s.link}),i?i.children.push(s):o.push(s),r.push(s))}),o}function H(n,e,t){if(n===0)return!0;let o=e[n];for(let r=n-1;r>=0;r--){let l=e[r];if(l.level<o.level&&l.level>=t[0]&&l.level<=t[1])return l.children==null&&(l.children=[]),l.children.push(o),!1}return!0}function c(n,e=[2,4]){let t=(typeof e=="object"&&!Array.isArray(e)?e.level:e)||2,[o,r]=typeof t=="number"?[t,t]:t==="deep"?[2,6]:t;return d(n,o,r)}function h(n){let e="";for(let t of Array.from(n.childNodes))if(t.nodeType===1){if(t.classList.contains("VABadge")||t.classList.contains("header-anchor"))continue;e+=t.textContent}else t.nodeType===3&&(e+=t.textContent);return e.trim()}function x(n={range:[2,4],selector:".markdown-body"}){let e=n.selector||".markdown-body",t=document.querySelectorAll(e),o=t[t.length-1],r=Array.from(o?.querySelectorAll(`${e} :where(h1,h2,h3,h4,h5,h6)`)||[]).filter(l=>n.filter?n.filter(l):!0).map(l=>{let s=Number(l.tagName[1]);return{element:l,title:h(l),link:`#${l.id}`,level:s,lang:l.lang}});return c(r,n.range)}0&&(module.exports={addToParent,buildTree,getHeaders,resolveHeaders,resolvedHeaders,serializeHeader});
|
package/dist/index.d.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
interface Header {
|
|
2
|
-
/**
|
|
3
|
-
* The level of the header
|
|
4
|
-
*
|
|
5
|
-
* `1` to `6` for `<h1>` to `<h6>`
|
|
6
|
-
*/
|
|
7
|
-
level: number;
|
|
8
|
-
/**
|
|
9
|
-
* The title of the header
|
|
10
|
-
*/
|
|
11
|
-
title: string;
|
|
12
|
-
/**
|
|
13
|
-
* The slug of the header
|
|
14
|
-
*
|
|
15
|
-
* Typically the `id` attr of the header anchor
|
|
16
|
-
*/
|
|
17
|
-
slug: string;
|
|
18
|
-
/**
|
|
19
|
-
* Link of the header
|
|
20
|
-
*
|
|
21
|
-
* Typically using `#${slug}` as the anchor hash
|
|
22
|
-
*/
|
|
23
|
-
link: string;
|
|
24
|
-
/**
|
|
25
|
-
* i18n
|
|
26
|
-
*/
|
|
27
|
-
lang?: string;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* @en
|
|
31
|
-
* Menu item, the title menu parsed from the article.
|
|
32
|
-
*
|
|
33
|
-
* @zh
|
|
34
|
-
* 菜单项,从文章中解析出的标题菜单。
|
|
35
|
-
*/
|
|
36
|
-
type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
|
37
|
-
element: HTMLHeadElement;
|
|
38
|
-
children?: MenuItem[];
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @ref vitepress src/client/theme-default/composables/outline.ts
|
|
43
|
-
*/
|
|
44
|
-
declare const resolvedHeaders: {
|
|
45
|
-
element: HTMLHeadElement;
|
|
46
|
-
link: string;
|
|
47
|
-
}[];
|
|
48
|
-
interface GetHeadersOptions {
|
|
49
|
-
range?: number | [number, number] | 'deep' | {
|
|
50
|
-
level: [number, number];
|
|
51
|
-
};
|
|
52
|
-
selector?: string;
|
|
53
|
-
filter?: (el: Element) => boolean;
|
|
54
|
-
}
|
|
55
|
-
declare function buildTree(data: MenuItem[], min: number, max: number): MenuItem[];
|
|
56
|
-
declare function addToParent(currIndex: number, headers: MenuItem[], levelsRange: [number, number]): boolean;
|
|
57
|
-
declare function resolveHeaders(headers: MenuItem[], range?: GetHeadersOptions['range']): MenuItem[];
|
|
58
|
-
declare function serializeHeader(h: Element): string;
|
|
59
|
-
/**
|
|
60
|
-
* get headers from document directly
|
|
61
|
-
*/
|
|
62
|
-
declare function getHeaders(options?: GetHeadersOptions): MenuItem[];
|
|
63
|
-
|
|
64
|
-
export { type GetHeadersOptions, type Header, type MenuItem, addToParent, buildTree, getHeaders, resolveHeaders, resolvedHeaders, serializeHeader };
|
package/src/client/headers.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import type { MenuItem } from '../types'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @ref vitepress src/client/theme-default/composables/outline.ts
|
|
5
|
-
*/
|
|
6
|
-
// cached list of anchor elements from resolveHeaders
|
|
7
|
-
export const resolvedHeaders: { element: HTMLHeadElement, link: string }[] = []
|
|
8
|
-
|
|
9
|
-
export interface GetHeadersOptions {
|
|
10
|
-
range?: number | [number, number] | 'deep' | { level: [number, number] }
|
|
11
|
-
selector?: string
|
|
12
|
-
filter?: (el: Element) => boolean
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function buildTree(data: MenuItem[], min: number, max: number): MenuItem[] {
|
|
16
|
-
resolvedHeaders.length = 0
|
|
17
|
-
|
|
18
|
-
const result: MenuItem[] = []
|
|
19
|
-
const stack: (MenuItem | { level: number, shouldIgnore: true })[] = []
|
|
20
|
-
|
|
21
|
-
data.forEach((item) => {
|
|
22
|
-
const node = { ...item, children: [] }
|
|
23
|
-
let parent = stack[stack.length - 1]
|
|
24
|
-
|
|
25
|
-
while (parent && parent.level >= node.level) {
|
|
26
|
-
stack.pop()
|
|
27
|
-
parent = stack[stack.length - 1]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
node.element.classList.contains('ignore-header')
|
|
32
|
-
|| (parent && 'shouldIgnore' in parent)
|
|
33
|
-
) {
|
|
34
|
-
stack.push({ level: node.level, shouldIgnore: true })
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (node.level > max || node.level < min)
|
|
39
|
-
return
|
|
40
|
-
resolvedHeaders.push({ element: node.element, link: node.link })
|
|
41
|
-
|
|
42
|
-
if (parent)
|
|
43
|
-
parent.children!.push(node)
|
|
44
|
-
else result.push(node)
|
|
45
|
-
|
|
46
|
-
stack.push(node)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
return result
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function addToParent(
|
|
53
|
-
currIndex: number,
|
|
54
|
-
headers: MenuItem[],
|
|
55
|
-
levelsRange: [number, number],
|
|
56
|
-
) {
|
|
57
|
-
if (currIndex === 0)
|
|
58
|
-
return true
|
|
59
|
-
|
|
60
|
-
const currentHeader = headers[currIndex]
|
|
61
|
-
for (let index = currIndex - 1; index >= 0; index--) {
|
|
62
|
-
const header = headers[index]
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
header.level < currentHeader.level
|
|
66
|
-
&& header.level >= levelsRange[0]
|
|
67
|
-
&& header.level <= levelsRange[1]
|
|
68
|
-
) {
|
|
69
|
-
if (header.children == null)
|
|
70
|
-
header.children = []
|
|
71
|
-
header.children.push(currentHeader)
|
|
72
|
-
return false
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return true
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function resolveHeaders(
|
|
80
|
-
headers: MenuItem[],
|
|
81
|
-
range: GetHeadersOptions['range'] = [2, 4],
|
|
82
|
-
) {
|
|
83
|
-
const levelsRange
|
|
84
|
-
= (typeof range === 'object' && !Array.isArray(range)
|
|
85
|
-
? range.level
|
|
86
|
-
: range) || 2
|
|
87
|
-
|
|
88
|
-
const [high, low]: [number, number]
|
|
89
|
-
= typeof levelsRange === 'number'
|
|
90
|
-
? [levelsRange, levelsRange]
|
|
91
|
-
: levelsRange === 'deep'
|
|
92
|
-
? [2, 6]
|
|
93
|
-
: levelsRange
|
|
94
|
-
|
|
95
|
-
return buildTree(headers, high, low)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function serializeHeader(h: Element): string {
|
|
99
|
-
let ret = ''
|
|
100
|
-
for (const node of Array.from(h.childNodes)) {
|
|
101
|
-
if (node.nodeType === 1) {
|
|
102
|
-
if (
|
|
103
|
-
(node as Element).classList.contains('VABadge')
|
|
104
|
-
|| (node as Element).classList.contains('header-anchor')
|
|
105
|
-
) {
|
|
106
|
-
continue
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
ret += node.textContent
|
|
110
|
-
}
|
|
111
|
-
else if (node.nodeType === 3) {
|
|
112
|
-
ret += node.textContent
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return ret.trim()
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// el => el.id && el.hasChildNodes()
|
|
119
|
-
/**
|
|
120
|
-
* get headers from document directly
|
|
121
|
-
*/
|
|
122
|
-
export function getHeaders(options: GetHeadersOptions = {
|
|
123
|
-
range: [2, 4],
|
|
124
|
-
selector: '.markdown-body',
|
|
125
|
-
}) {
|
|
126
|
-
const mdBodySelector = options.selector || '.markdown-body'
|
|
127
|
-
// when transition, the markdown-body will be two
|
|
128
|
-
// the first is the old one, the last is the new one
|
|
129
|
-
const markdownBodyElements = document.querySelectorAll(mdBodySelector) as NodeListOf<HTMLElement>
|
|
130
|
-
const markdownBody = markdownBodyElements[markdownBodyElements.length - 1]
|
|
131
|
-
const headers = Array.from(markdownBody?.querySelectorAll(`${mdBodySelector} :where(h1,h2,h3,h4,h5,h6)`) || [])
|
|
132
|
-
.filter(el => options.filter ? options.filter(el) : true)
|
|
133
|
-
.map((el) => {
|
|
134
|
-
const level = Number(el.tagName[1])
|
|
135
|
-
return {
|
|
136
|
-
element: el as HTMLHeadElement,
|
|
137
|
-
title: serializeHeader(el),
|
|
138
|
-
link: `#${el.id}`,
|
|
139
|
-
level,
|
|
140
|
-
// @ts-expect-error lang
|
|
141
|
-
lang: el.lang,
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
return resolveHeaders(headers, options.range)
|
|
146
|
-
}
|
package/src/client/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './headers'
|
package/src/index.ts
DELETED
package/src/types/index.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export interface Header {
|
|
2
|
-
/**
|
|
3
|
-
* The level of the header
|
|
4
|
-
*
|
|
5
|
-
* `1` to `6` for `<h1>` to `<h6>`
|
|
6
|
-
*/
|
|
7
|
-
level: number
|
|
8
|
-
/**
|
|
9
|
-
* The title of the header
|
|
10
|
-
*/
|
|
11
|
-
title: string
|
|
12
|
-
/**
|
|
13
|
-
* The slug of the header
|
|
14
|
-
*
|
|
15
|
-
* Typically the `id` attr of the header anchor
|
|
16
|
-
*/
|
|
17
|
-
slug: string
|
|
18
|
-
/**
|
|
19
|
-
* Link of the header
|
|
20
|
-
*
|
|
21
|
-
* Typically using `#${slug}` as the anchor hash
|
|
22
|
-
*/
|
|
23
|
-
link: string
|
|
24
|
-
/**
|
|
25
|
-
* i18n
|
|
26
|
-
*/
|
|
27
|
-
lang?: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @en
|
|
32
|
-
* Menu item, the title menu parsed from the article.
|
|
33
|
-
*
|
|
34
|
-
* @zh
|
|
35
|
-
* 菜单项,从文章中解析出的标题菜单。
|
|
36
|
-
*/
|
|
37
|
-
export type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
|
38
|
-
element: HTMLHeadElement
|
|
39
|
-
children?: MenuItem[]
|
|
40
|
-
}
|
package/tsup.config.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup'
|
|
2
|
-
|
|
3
|
-
export default defineConfig((options) => {
|
|
4
|
-
return {
|
|
5
|
-
entry: [
|
|
6
|
-
'src/index.ts',
|
|
7
|
-
],
|
|
8
|
-
// https://tsup.egoist.dev/#code-splitting
|
|
9
|
-
// Code splitting currently only works with the esm output format, and it's enabled by default. If you want code splitting for cjs output format as well, try using --splitting flag which is an experimental feature to get rid of the limitation in esbuild.
|
|
10
|
-
// splitting: true,
|
|
11
|
-
clean: true,
|
|
12
|
-
dts: true,
|
|
13
|
-
format: ['cjs', 'esm'],
|
|
14
|
-
minify: !options.watch,
|
|
15
|
-
|
|
16
|
-
outExtension({ format }) {
|
|
17
|
-
return {
|
|
18
|
-
js: `.${format === 'esm' ? 'mjs' : 'cjs'}`,
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @see https://tsup.egoist.dev/#inject-cjs-and-esm-shims
|
|
24
|
-
* shim for __filename
|
|
25
|
-
*/
|
|
26
|
-
shims: true,
|
|
27
|
-
}
|
|
28
|
-
})
|