@valaxyjs/utils 0.19.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.cjs +1 -0
- package/dist/index.d.cts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.mjs +2 -0
- package/package.json +31 -0
- package/src/client/headers.ts +148 -0
- package/src/client/index.ts +1 -0
- package/src/index.ts +1 -0
- package/tsup.config.ts +38 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var i=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var h=(r,e)=>{for(var t in e)i(r,t,{get:e[t],enumerable:!0})},g=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of p(e))!b.call(r,o)&&o!==t&&i(r,o,{get:()=>e[o],enumerable:!(n=f(e,o))||n.enumerable});return r};var y=r=>g(i({},"__esModule",{value:!0}),r);var H={};h(H,{addToParent:()=>s,getHeaders:()=>x,groupHeaders:()=>m,resolveHeaders:()=>a,serializeHeader:()=>c});module.exports=y(H);function m(r,e){let t=[];return r=r.map(n=>({...n})),r.forEach((n,o)=>{n.level>=e[0]&&n.level<=e[1]&&s(o,r,e)&&t.push(n)}),t}function s(r,e,t){if(r===0)return!0;let n=e[r];for(let o=r-1;o>=0;o--){let l=e[o];if(l.level<n.level&&l.level>=t[0]&&l.level<=t[1])return l.children==null&&(l.children=[]),l.children.push(n),!1}return!0}function a(r,e=[2,4]){return m(r,typeof e=="number"?[e,e]:e==="deep"?[2,6]:e)}function c(r){let e="";for(let t of Array.from(r.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(r={range:[2,4],selector:".markdown-body"}){let e=r.selector||".markdown-body",t=document.querySelectorAll(e),n=t[t.length-1],o=Array.from(n.querySelectorAll(`${e} :where(h1,h2,h3,h4,h5,h6)`)).filter(l=>r.filter?r.filter(l):!0).map(l=>{let d=Number(l.tagName[1]);return{title:c(l),link:`#${l.id}`,level:d,lang:l.lang}});return a(o,r.range)}0&&(module.exports={addToParent,getHeaders,groupHeaders,resolveHeaders,serializeHeader});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
interface GetHeadersOptions {
|
|
30
|
+
range?: number | [number, number] | 'deep';
|
|
31
|
+
selector?: string;
|
|
32
|
+
filter?: (el: Element) => boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @en
|
|
36
|
+
* Menu item, the title menu parsed from the article.
|
|
37
|
+
*
|
|
38
|
+
* @zh
|
|
39
|
+
* 菜单项,从文章中解析出的标题菜单。
|
|
40
|
+
*/
|
|
41
|
+
type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
|
42
|
+
children?: MenuItem[];
|
|
43
|
+
};
|
|
44
|
+
declare function groupHeaders(headers: MenuItem[], levelsRange: [number, number]): MenuItem[];
|
|
45
|
+
declare function addToParent(currIndex: number, headers: MenuItem[], levelsRange: [number, number]): boolean;
|
|
46
|
+
declare function resolveHeaders(headers: MenuItem[], levelsRange?: GetHeadersOptions['range']): MenuItem[];
|
|
47
|
+
declare function serializeHeader(h: Element): string;
|
|
48
|
+
/**
|
|
49
|
+
* get headers from document directly
|
|
50
|
+
*/
|
|
51
|
+
declare function getHeaders(options?: GetHeadersOptions): MenuItem[];
|
|
52
|
+
|
|
53
|
+
export { type GetHeadersOptions, type Header, type MenuItem, addToParent, getHeaders, groupHeaders, resolveHeaders, serializeHeader };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
interface GetHeadersOptions {
|
|
30
|
+
range?: number | [number, number] | 'deep';
|
|
31
|
+
selector?: string;
|
|
32
|
+
filter?: (el: Element) => boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @en
|
|
36
|
+
* Menu item, the title menu parsed from the article.
|
|
37
|
+
*
|
|
38
|
+
* @zh
|
|
39
|
+
* 菜单项,从文章中解析出的标题菜单。
|
|
40
|
+
*/
|
|
41
|
+
type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
|
42
|
+
children?: MenuItem[];
|
|
43
|
+
};
|
|
44
|
+
declare function groupHeaders(headers: MenuItem[], levelsRange: [number, number]): MenuItem[];
|
|
45
|
+
declare function addToParent(currIndex: number, headers: MenuItem[], levelsRange: [number, number]): boolean;
|
|
46
|
+
declare function resolveHeaders(headers: MenuItem[], levelsRange?: GetHeadersOptions['range']): MenuItem[];
|
|
47
|
+
declare function serializeHeader(h: Element): string;
|
|
48
|
+
/**
|
|
49
|
+
* get headers from document directly
|
|
50
|
+
*/
|
|
51
|
+
declare function getHeaders(options?: GetHeadersOptions): MenuItem[];
|
|
52
|
+
|
|
53
|
+
export { type GetHeadersOptions, type Header, type MenuItem, addToParent, getHeaders, groupHeaders, resolveHeaders, serializeHeader };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {createRequire as __createRequire} from 'module';var require=__createRequire(import.meta.url);
|
|
2
|
+
function s(r,e){let t=[];return r=r.map(o=>({...o})),r.forEach((o,l)=>{o.level>=e[0]&&o.level<=e[1]&&a(l,r,e)&&t.push(o)}),t}function a(r,e,t){if(r===0)return!0;let o=e[r];for(let l=r-1;l>=0;l--){let n=e[l];if(n.level<o.level&&n.level>=t[0]&&n.level<=t[1])return n.children==null&&(n.children=[]),n.children.push(o),!1}return!0}function c(r,e=[2,4]){return s(r,typeof e=="number"?[e,e]:e==="deep"?[2,6]:e)}function d(r){let e="";for(let t of Array.from(r.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 f(r={range:[2,4],selector:".markdown-body"}){let e=r.selector||".markdown-body",t=document.querySelectorAll(e),o=t[t.length-1],l=Array.from(o.querySelectorAll(`${e} :where(h1,h2,h3,h4,h5,h6)`)).filter(n=>r.filter?r.filter(n):!0).map(n=>{let m=Number(n.tagName[1]);return{title:d(n),link:`#${n.id}`,level:m,lang:n.lang}});return c(l,r.range)}export{a as addToParent,f as getHeaders,s as groupHeaders,c as resolveHeaders,d as serializeHeader};
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@valaxyjs/utils",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.19.2",
|
|
5
|
+
"description": "A utility library for Valaxy",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Valaxy",
|
|
8
|
+
"url": "https://valaxy.site"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"homepage": "https://valaxy.site",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/YunYouJun/valaxy"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.mjs",
|
|
20
|
+
"require": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"main": "./dist/index.mjs",
|
|
24
|
+
"module": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "tsup --watch",
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
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
|
+
export interface GetHeadersOptions {
|
|
31
|
+
range?: number | [number, number] | 'deep'
|
|
32
|
+
selector?: string
|
|
33
|
+
filter?: (el: Element) => boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @en
|
|
38
|
+
* Menu item, the title menu parsed from the article.
|
|
39
|
+
*
|
|
40
|
+
* @zh
|
|
41
|
+
* 菜单项,从文章中解析出的标题菜单。
|
|
42
|
+
*/
|
|
43
|
+
export type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
|
44
|
+
children?: MenuItem[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function groupHeaders(headers: MenuItem[], levelsRange: [number, number]) {
|
|
48
|
+
const result: MenuItem[] = []
|
|
49
|
+
|
|
50
|
+
headers = headers.map(h => ({ ...h }))
|
|
51
|
+
headers.forEach((h, index) => {
|
|
52
|
+
if (h.level >= levelsRange[0] && h.level <= levelsRange[1]) {
|
|
53
|
+
if (addToParent(index, headers, levelsRange))
|
|
54
|
+
result.push(h)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
return result
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function addToParent(
|
|
62
|
+
currIndex: number,
|
|
63
|
+
headers: MenuItem[],
|
|
64
|
+
levelsRange: [number, number],
|
|
65
|
+
) {
|
|
66
|
+
if (currIndex === 0)
|
|
67
|
+
return true
|
|
68
|
+
|
|
69
|
+
const currentHeader = headers[currIndex]
|
|
70
|
+
for (let index = currIndex - 1; index >= 0; index--) {
|
|
71
|
+
const header = headers[index]
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
header.level < currentHeader.level
|
|
75
|
+
&& header.level >= levelsRange[0]
|
|
76
|
+
&& header.level <= levelsRange[1]
|
|
77
|
+
) {
|
|
78
|
+
if (header.children == null)
|
|
79
|
+
header.children = []
|
|
80
|
+
header.children.push(currentHeader)
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function resolveHeaders(
|
|
89
|
+
headers: MenuItem[],
|
|
90
|
+
levelsRange: GetHeadersOptions['range'] = [2, 4],
|
|
91
|
+
) {
|
|
92
|
+
const levels: [number, number]
|
|
93
|
+
= typeof levelsRange === 'number'
|
|
94
|
+
? [levelsRange, levelsRange]
|
|
95
|
+
: levelsRange === 'deep'
|
|
96
|
+
? [2, 6]
|
|
97
|
+
: levelsRange
|
|
98
|
+
|
|
99
|
+
return groupHeaders(headers, levels)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function serializeHeader(h: Element): string {
|
|
103
|
+
let ret = ''
|
|
104
|
+
for (const node of Array.from(h.childNodes)) {
|
|
105
|
+
if (node.nodeType === 1) {
|
|
106
|
+
if (
|
|
107
|
+
(node as Element).classList.contains('VABadge')
|
|
108
|
+
|| (node as Element).classList.contains('header-anchor')
|
|
109
|
+
)
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
ret += node.textContent
|
|
113
|
+
}
|
|
114
|
+
else if (node.nodeType === 3) {
|
|
115
|
+
ret += node.textContent
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return ret.trim()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// el => el.id && el.hasChildNodes()
|
|
122
|
+
/**
|
|
123
|
+
* get headers from document directly
|
|
124
|
+
*/
|
|
125
|
+
export function getHeaders(options: GetHeadersOptions = {
|
|
126
|
+
range: [2, 4],
|
|
127
|
+
selector: '.markdown-body',
|
|
128
|
+
}) {
|
|
129
|
+
const mdBodySelector = options.selector || '.markdown-body'
|
|
130
|
+
// when transition, the markdown-body will be two
|
|
131
|
+
// the first is the old one, the last is the new one
|
|
132
|
+
const markdownBodyElements = document.querySelectorAll(mdBodySelector) as NodeListOf<HTMLElement>
|
|
133
|
+
const markdownBody = markdownBodyElements[markdownBodyElements.length - 1]
|
|
134
|
+
const headers = Array.from(markdownBody.querySelectorAll(`${mdBodySelector} :where(h1,h2,h3,h4,h5,h6)`))
|
|
135
|
+
.filter(el => options.filter ? options.filter(el) : true)
|
|
136
|
+
.map((el) => {
|
|
137
|
+
const level = Number(el.tagName[1])
|
|
138
|
+
return {
|
|
139
|
+
title: serializeHeader(el),
|
|
140
|
+
link: `#${el.id}`,
|
|
141
|
+
level,
|
|
142
|
+
// @ts-expect-error lang
|
|
143
|
+
lang: el.lang,
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
return resolveHeaders(headers, options.range)
|
|
148
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './headers'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './client'
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
* @see https://github.com/egoist/tsup/discussions/505
|
|
29
|
+
*/
|
|
30
|
+
banner: ({ format }) => {
|
|
31
|
+
if (format === 'esm') {
|
|
32
|
+
return {
|
|
33
|
+
js: `import {createRequire as __createRequire} from 'module';var require=__createRequire(import\.meta.url);`,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
})
|