astro-smart-links 0.0.0-stage → 1.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/LICENSE +21 -0
- package/README.md +239 -2
- package/README.zh-CN.md +239 -0
- package/dist/chunk-67PNI3F6.js +370 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +69 -0
- package/dist/index.d.ts +249 -0
- package/dist/index.js +368 -0
- package/package.json +96 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 EveSunMaple
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,240 @@
|
|
|
1
|
-
|
|
1
|
+
[English](README.md) | [中文](README.zh-CN.md)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# astro-smart-links
|
|
4
|
+
|
|
5
|
+
An Astro integration that gives every link in your Markdown a smarter style:
|
|
6
|
+
|
|
7
|
+
- **Internal links** (pages that exist) get a customizable class.
|
|
8
|
+
- **Broken internal links** (pages that do not exist) get a red, Wikipedia-style class and are reported at the end of the build.
|
|
9
|
+
- **External links** get an icon `↗`, `target="_blank"` and `rel="noopener noreferrer"` by default.
|
|
10
|
+
|
|
11
|
+
No routes file, no second build. The integration validates links against the real build output.
|
|
12
|
+
|
|
13
|
+
> Migrating from `rehype-smart-links@0.x`? See [Migration](#migration-from-rehype-smart-links).
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# npm
|
|
19
|
+
npm install astro-smart-links
|
|
20
|
+
|
|
21
|
+
# pnpm
|
|
22
|
+
pnpm add astro-smart-links
|
|
23
|
+
|
|
24
|
+
# yarn
|
|
25
|
+
yarn add astro-smart-links
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// astro.config.mjs
|
|
32
|
+
import { defineConfig } from "astro/config";
|
|
33
|
+
import { smartLinks } from "astro-smart-links";
|
|
34
|
+
|
|
35
|
+
export default defineConfig({
|
|
36
|
+
integrations: [
|
|
37
|
+
smartLinks({
|
|
38
|
+
internalLinkClass: "internal-link",
|
|
39
|
+
externalLinkClass: "external-link",
|
|
40
|
+
brokenLinkClass: "broken-link",
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Add the classes to your global CSS:
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
.internal-link {
|
|
50
|
+
color: #2563eb;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Wikipedia-style broken link */
|
|
54
|
+
.broken-link {
|
|
55
|
+
color: #dc2626;
|
|
56
|
+
text-decoration: underline wavy;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.external-link {
|
|
60
|
+
color: #7c3aed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.external-link .external-icon {
|
|
64
|
+
margin-left: 0.25em;
|
|
65
|
+
font-size: 0.75em;
|
|
66
|
+
opacity: 0.8;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Broken link detection
|
|
71
|
+
|
|
72
|
+
When the build finishes, the integration scans the generated pages, builds the real route table and:
|
|
73
|
+
|
|
74
|
+
1. Switches broken internal links from `internal-link` to `broken-link`.
|
|
75
|
+
2. Prints a report to the console.
|
|
76
|
+
3. Optionally writes a `.json`/`.html` report and/or fails the build.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
smartLinks({
|
|
80
|
+
failOnBroken: true, // exit non-zero on broken links (great for CI)
|
|
81
|
+
reportFile: ".smart-links-report.json", // or .html
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Console output:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
[astro-smart-links] Smart links report (2026-01-01T00:00:00.000Z)
|
|
89
|
+
Routes scanned: 42
|
|
90
|
+
Links: 180 internal, 12 external, 2 broken
|
|
91
|
+
|
|
92
|
+
Broken internal links:
|
|
93
|
+
/blog/old-post (found in src/content/blog/new-post.md)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Link matching ignores query strings and hashes (`/about?x=1#team` counts as `/about`), resolves relative links against the current page, and handles the Astro `base` sub-path and trailing-slash differences.
|
|
97
|
+
|
|
98
|
+
## CLI
|
|
99
|
+
|
|
100
|
+
Check any build directory, even outside Astro:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx astro-smart-links check --dir dist --fail-on-broken
|
|
104
|
+
npx astro-smart-links check --json
|
|
105
|
+
npx astro-smart-links check --all --extensions html pdf zip
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| Option | Description |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `-d, --dir <path>` | Build directory (default `./dist`) |
|
|
111
|
+
| `-o, --output <path>` | Write the report to a file |
|
|
112
|
+
| `--format <json\|html>` | Report format (default `json`) |
|
|
113
|
+
| `--json` | Print the report to stdout |
|
|
114
|
+
| `-a, --all` | Treat every file type as a valid route |
|
|
115
|
+
| `-e, --extensions <ext...>` | File extensions to include (default `html`) |
|
|
116
|
+
| `--fail-on-broken` | Exit with code 1 when broken links are found |
|
|
117
|
+
| `-q, --quiet` | Only print the summary |
|
|
118
|
+
|
|
119
|
+
## Options
|
|
120
|
+
|
|
121
|
+
| Option | Type | Default | Description |
|
|
122
|
+
| --- | --- | --- | --- |
|
|
123
|
+
| `internalLinkClass` | `string` | `'internal-link'` | Class for internal links |
|
|
124
|
+
| `externalLinkClass` | `string` | `'external-link'` | Class for external links |
|
|
125
|
+
| `brokenLinkClass` | `string` | `'broken-link'` | Class for broken links |
|
|
126
|
+
| `content` | `{ type: 'text', value: string } \| null` | `{ type: 'text', value: '↗' }` | Content appended to external links |
|
|
127
|
+
| `contentClass` | `string` | `'external-icon'` | Class of the external icon |
|
|
128
|
+
| `target` | `string \| null` | `'_blank'` | `target` attribute for external links |
|
|
129
|
+
| `rel` | `string \| null` | `'noopener noreferrer'` | `rel` attribute for external links |
|
|
130
|
+
| `ignore` | `(string \| RegExp)[]` | `[]` | Hrefs that are never processed (prefix match or RegExp) |
|
|
131
|
+
| `routes` | `string[]` | — | Explicit route list for broken-link detection |
|
|
132
|
+
| `routesFile` | `string` | — | JSON file with a route list |
|
|
133
|
+
| `publicDir` | `string` | — | Directory to scan for routes |
|
|
134
|
+
| `includeFileExtensions` | `string[]` | `['html']` | Extensions treated as routes while scanning |
|
|
135
|
+
| `includeAllFiles` | `boolean` | `false` | Treat every scanned file as a route |
|
|
136
|
+
| `base` | `string` | Astro `base` | Site sub-path |
|
|
137
|
+
| `wrapperTemplate` | `(node, type, meta) => Element` | — | Fully customize the link HTML |
|
|
138
|
+
| `customInternalLinkTransform` | `(node, meta) => void` | — | Custom transform for internal links |
|
|
139
|
+
| `customExternalLinkTransform` | `(node, meta) => void` | — | Custom transform for external links |
|
|
140
|
+
| `customBrokenLinkTransform` | `(node, meta) => void` | — | Custom transform for broken links |
|
|
141
|
+
| `onLink` | `(record) => void` | — | Called for every processed link |
|
|
142
|
+
| `logger` / `logLevel` | `SmartLinksLogger \| false` / `'debug' \| 'info' \| 'warn' \| 'error' \| 'silent'` | `'warn'` | Diagnostics |
|
|
143
|
+
| `failOnBroken` | `boolean` | `false` | Integration option: fail the build on broken links |
|
|
144
|
+
| `reportFile` | `string` | — | Integration option: write a report file |
|
|
145
|
+
| `reportFormat` | `'json' \| 'html'` | `'json'` | Integration option: report format |
|
|
146
|
+
|
|
147
|
+
## Customization
|
|
148
|
+
|
|
149
|
+
### Custom HTML structure
|
|
150
|
+
|
|
151
|
+
`wrapperTemplate` receives the anchor `node`, the link `type` and a `meta` object (`{ href, pathname, className, sourceFile }`), and returns the replacement node:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
smartLinks({
|
|
155
|
+
wrapperTemplate: (node, type, meta) => {
|
|
156
|
+
if (type === "external") {
|
|
157
|
+
node.properties.className = [...(node.properties.className ?? []), "tooltip"];
|
|
158
|
+
node.properties["data-tip"] = `Opens ${meta.href}`;
|
|
159
|
+
}
|
|
160
|
+
return node;
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
When `wrapperTemplate` is provided it is responsible for applying classes; `meta.className` contains the configured class for the link type.
|
|
166
|
+
|
|
167
|
+
### Custom transforms
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
smartLinks({
|
|
171
|
+
customExternalLinkTransform: (node, meta) => {
|
|
172
|
+
node.properties.target = "_blank";
|
|
173
|
+
node.properties.rel = "noopener noreferrer";
|
|
174
|
+
node.properties["data-external"] = "true";
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Custom transforms fully take over the given link type, so set `target`/`rel` yourself when needed.
|
|
180
|
+
|
|
181
|
+
### Ignoring links
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
smartLinks({
|
|
185
|
+
ignore: ["/draft/", /^\/preview\//],
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Using the rehype plugin directly
|
|
190
|
+
|
|
191
|
+
The integration is built on an exported rehype plugin, so any rehype-based framework (Next.js, Gatsby, ...) can use it. In that case you provide the routes yourself:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
import { rehypeSmartLinks } from "astro-smart-links";
|
|
195
|
+
|
|
196
|
+
// unified / Astro markdown config
|
|
197
|
+
rehypePlugins: [
|
|
198
|
+
[rehypeSmartLinks, { routes: ["/", "/about"] }],
|
|
199
|
+
];
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Routes come from `routes`, `routesFile` or `publicDir`. When none is given, every internal link is treated as valid and only styled.
|
|
203
|
+
|
|
204
|
+
## API
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
import {
|
|
208
|
+
smartLinks, // Astro integration (default export)
|
|
209
|
+
rehypeSmartLinks, // rehype plugin
|
|
210
|
+
classifyHref,
|
|
211
|
+
normalizeRoute,
|
|
212
|
+
scanRoutes,
|
|
213
|
+
checkDirectory,
|
|
214
|
+
buildReport,
|
|
215
|
+
} from "astro-smart-links";
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Migration from rehype-smart-links
|
|
219
|
+
|
|
220
|
+
`rehype-smart-links@0.x` required a two-phase build (`astro build && rehype-smart-links build && astro build`) and a `.smart-links-routes.json` file. In `astro-smart-links@1.0`:
|
|
221
|
+
|
|
222
|
+
1. Install `astro-smart-links` and remove `rehype-smart-links`.
|
|
223
|
+
2. Replace the `markdown.rehypePlugins` entry with the `smartLinks()` integration.
|
|
224
|
+
3. Delete the routes file and the `build:with-routes` script.
|
|
225
|
+
4. `wrapperTemplate` now receives `(node, type, meta)` instead of `(node, type, className)`, and returns a replacement node instead of being merged into the original one.
|
|
226
|
+
|
|
227
|
+
## Development
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
pnpm install
|
|
231
|
+
pnpm lint
|
|
232
|
+
pnpm typecheck
|
|
233
|
+
pnpm test
|
|
234
|
+
pnpm build
|
|
235
|
+
cd example && pnpm dev
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
[English](README.md) | [中文](README.zh-CN.md)
|
|
2
|
+
|
|
3
|
+
# astro-smart-links
|
|
4
|
+
|
|
5
|
+
一个 Astro 集成,让你的 Markdown 链接更智能:
|
|
6
|
+
|
|
7
|
+
- **内部链接**(页面存在)自动添加可自定义的类名。
|
|
8
|
+
- **断开的内部链接**(页面不存在)添加维基百科风格的红色样式,并在构建结束时输出报告。
|
|
9
|
+
- **外部链接**默认添加 `↗` 图标、`target="_blank"` 和 `rel="noopener noreferrer"`。
|
|
10
|
+
|
|
11
|
+
无需路由文件,无需二次构建:集成会在构建完成后使用真实的路由表校验链接。
|
|
12
|
+
|
|
13
|
+
> 从 `rehype-smart-links@0.x` 迁移?见 [迁移指南](#从-rehype-smart-links-迁移)。
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# npm
|
|
19
|
+
npm install astro-smart-links
|
|
20
|
+
|
|
21
|
+
# pnpm
|
|
22
|
+
pnpm add astro-smart-links
|
|
23
|
+
|
|
24
|
+
# yarn
|
|
25
|
+
yarn add astro-smart-links
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 使用
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// astro.config.mjs
|
|
32
|
+
import { defineConfig } from "astro/config";
|
|
33
|
+
import { smartLinks } from "astro-smart-links";
|
|
34
|
+
|
|
35
|
+
export default defineConfig({
|
|
36
|
+
integrations: [
|
|
37
|
+
smartLinks({
|
|
38
|
+
internalLinkClass: "internal-link",
|
|
39
|
+
externalLinkClass: "external-link",
|
|
40
|
+
brokenLinkClass: "broken-link",
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
在全局 CSS 中添加样式:
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
.internal-link {
|
|
50
|
+
color: #2563eb;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* 维基百科风格的红链 */
|
|
54
|
+
.broken-link {
|
|
55
|
+
color: #dc2626;
|
|
56
|
+
text-decoration: underline wavy;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.external-link {
|
|
60
|
+
color: #7c3aed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.external-link .external-icon {
|
|
64
|
+
margin-left: 0.25em;
|
|
65
|
+
font-size: 0.75em;
|
|
66
|
+
opacity: 0.8;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 断链检测
|
|
71
|
+
|
|
72
|
+
构建完成后,集成会扫描生成的页面、得到真实路由表,然后:
|
|
73
|
+
|
|
74
|
+
1. 将断链从 `internal-link` 切换为 `broken-link`。
|
|
75
|
+
2. 在控制台输出报告。
|
|
76
|
+
3. 可选:写入 `.json`/`.html` 报告文件,和/或让构建失败。
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
smartLinks({
|
|
80
|
+
failOnBroken: true, // 发现断链时退出码非 0,适合 CI
|
|
81
|
+
reportFile: ".smart-links-report.json", // 也可以是 .html
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
控制台输出示例:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
[astro-smart-links] Smart links report (2026-01-01T00:00:00.000Z)
|
|
89
|
+
Routes scanned: 42
|
|
90
|
+
Links: 180 internal, 12 external, 2 broken
|
|
91
|
+
|
|
92
|
+
Broken internal links:
|
|
93
|
+
/blog/old-post (found in src/content/blog/new-post.md)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
链接匹配会自动忽略查询参数与哈希(`/about?x=1#team` 视为 `/about`),按当前页面解析相对链接,并处理 Astro `base` 子路径与结尾斜杠差异。
|
|
97
|
+
|
|
98
|
+
## CLI
|
|
99
|
+
|
|
100
|
+
可以检查任何构建目录,不限于 Astro 项目:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx astro-smart-links check --dir dist --fail-on-broken
|
|
104
|
+
npx astro-smart-links check --json
|
|
105
|
+
npx astro-smart-links check --all --extensions html pdf zip
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| 选项 | 描述 |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `-d, --dir <path>` | 构建目录(默认 `./dist`) |
|
|
111
|
+
| `-o, --output <path>` | 将报告写入文件 |
|
|
112
|
+
| `--format <json\|html>` | 报告格式(默认 `json`) |
|
|
113
|
+
| `--json` | 以 JSON 输出到 stdout |
|
|
114
|
+
| `-a, --all` | 将所有文件类型视为有效路由 |
|
|
115
|
+
| `-e, --extensions <ext...>` | 要包含的文件扩展名(默认 `html`) |
|
|
116
|
+
| `--fail-on-broken` | 发现断链时以退出码 1 结束 |
|
|
117
|
+
| `-q, --quiet` | 只输出摘要 |
|
|
118
|
+
|
|
119
|
+
## 配置选项
|
|
120
|
+
|
|
121
|
+
| 选项 | 类型 | 默认值 | 描述 |
|
|
122
|
+
| --- | --- | --- | --- |
|
|
123
|
+
| `internalLinkClass` | `string` | `'internal-link'` | 内部链接的类名 |
|
|
124
|
+
| `externalLinkClass` | `string` | `'external-link'` | 外部链接的类名 |
|
|
125
|
+
| `brokenLinkClass` | `string` | `'broken-link'` | 断链的类名 |
|
|
126
|
+
| `content` | `{ type: 'text', value: string } \| null` | `{ type: 'text', value: '↗' }` | 外部链接追加的内容 |
|
|
127
|
+
| `contentClass` | `string` | `'external-icon'` | 外部链接图标的类名 |
|
|
128
|
+
| `target` | `string \| null` | `'_blank'` | 外部链接的 `target` |
|
|
129
|
+
| `rel` | `string \| null` | `'noopener noreferrer'` | 外部链接的 `rel` |
|
|
130
|
+
| `ignore` | `(string \| RegExp)[]` | `[]` | 不处理的链接(前缀匹配或正则) |
|
|
131
|
+
| `routes` | `string[]` | — | 显式路由列表 |
|
|
132
|
+
| `routesFile` | `string` | — | 包含路由列表的 JSON 文件 |
|
|
133
|
+
| `publicDir` | `string` | — | 扫描路由的目录 |
|
|
134
|
+
| `includeFileExtensions` | `string[]` | `['html']` | 扫描时视为路由的扩展名 |
|
|
135
|
+
| `includeAllFiles` | `boolean` | `false` | 将所有扫描到的文件视为路由 |
|
|
136
|
+
| `base` | `string` | Astro `base` | 站点子路径 |
|
|
137
|
+
| `wrapperTemplate` | `(node, type, meta) => Element` | — | 完全自定义链接的 HTML |
|
|
138
|
+
| `customInternalLinkTransform` | `(node, meta) => void` | — | 内部链接自定义转换 |
|
|
139
|
+
| `customExternalLinkTransform` | `(node, meta) => void` | — | 外部链接自定义转换 |
|
|
140
|
+
| `customBrokenLinkTransform` | `(node, meta) => void` | — | 断链自定义转换 |
|
|
141
|
+
| `onLink` | `(record) => void` | — | 每个已处理链接的回调 |
|
|
142
|
+
| `logger` / `logLevel` | `SmartLinksLogger \| false` / `'debug' \| 'info' \| 'warn' \| 'error' \| 'silent'` | `'warn'` | 日志 |
|
|
143
|
+
| `failOnBroken` | `boolean` | `false` | 集成选项:发现断链时让构建失败 |
|
|
144
|
+
| `reportFile` | `string` | — | 集成选项:写入报告文件 |
|
|
145
|
+
| `reportFormat` | `'json' \| 'html'` | `'json'` | 集成选项:报告格式 |
|
|
146
|
+
|
|
147
|
+
## 自定义
|
|
148
|
+
|
|
149
|
+
### 自定义 HTML 结构
|
|
150
|
+
|
|
151
|
+
`wrapperTemplate` 接收锚点 `node`、链接 `type` 和 `meta`(`{ href, pathname, className, sourceFile }`),返回替换后的节点:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
smartLinks({
|
|
155
|
+
wrapperTemplate: (node, type, meta) => {
|
|
156
|
+
if (type === "external") {
|
|
157
|
+
node.properties.className = [...(node.properties.className ?? []), "tooltip"];
|
|
158
|
+
node.properties["data-tip"] = `打开 ${meta.href}`;
|
|
159
|
+
}
|
|
160
|
+
return node;
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
使用 `wrapperTemplate` 时由它负责添加类名;`meta.className` 中包含当前类型配置的类名。
|
|
166
|
+
|
|
167
|
+
### 自定义转换
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
smartLinks({
|
|
171
|
+
customExternalLinkTransform: (node, meta) => {
|
|
172
|
+
node.properties.target = "_blank";
|
|
173
|
+
node.properties.rel = "noopener noreferrer";
|
|
174
|
+
node.properties["data-external"] = "true";
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
自定义转换会完全接管该类型的链接,需要自行设置 `target`/`rel`。
|
|
180
|
+
|
|
181
|
+
### 忽略链接
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
smartLinks({
|
|
185
|
+
ignore: ["/draft/", /^\/preview\//],
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 直接使用 rehype 插件
|
|
190
|
+
|
|
191
|
+
集成基于一个导出的 rehype 插件实现,因此任何使用 rehype 的框架(Next.js、Gatsby 等)都可以使用。此时需要自行提供路由:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
import { rehypeSmartLinks } from "astro-smart-links";
|
|
195
|
+
|
|
196
|
+
rehypePlugins: [
|
|
197
|
+
[rehypeSmartLinks, { routes: ["/", "/about"] }],
|
|
198
|
+
];
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
路由来源三选一:`routes`、`routesFile` 或 `publicDir`。都不提供时,所有内部链接都会被视为有效链接,只做样式标记。
|
|
202
|
+
|
|
203
|
+
## API
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
import {
|
|
207
|
+
smartLinks, // Astro 集成(默认导出)
|
|
208
|
+
rehypeSmartLinks, // rehype 插件
|
|
209
|
+
classifyHref,
|
|
210
|
+
normalizeRoute,
|
|
211
|
+
scanRoutes,
|
|
212
|
+
checkDirectory,
|
|
213
|
+
buildReport,
|
|
214
|
+
} from "astro-smart-links";
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## 从 rehype-smart-links 迁移
|
|
218
|
+
|
|
219
|
+
`rehype-smart-links@0.x` 需要二次构建(`astro build && rehype-smart-links build && astro build`)和 `.smart-links-routes.json` 文件。升级到 `astro-smart-links@1.0`:
|
|
220
|
+
|
|
221
|
+
1. 安装 `astro-smart-links`,移除 `rehype-smart-links`。
|
|
222
|
+
2. 把 `markdown.rehypePlugins` 配置替换为 `smartLinks()` 集成。
|
|
223
|
+
3. 删除路由文件与 `build:with-routes` 脚本。
|
|
224
|
+
4. `wrapperTemplate` 签名变为 `(node, type, meta)`,并改为返回替换节点(不再合并到原节点)。
|
|
225
|
+
|
|
226
|
+
## 开发
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
pnpm install
|
|
230
|
+
pnpm lint
|
|
231
|
+
pnpm typecheck
|
|
232
|
+
pnpm test
|
|
233
|
+
pnpm build
|
|
234
|
+
cd example && pnpm dev
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 许可证
|
|
238
|
+
|
|
239
|
+
[MIT](LICENSE)
|