starlight-cannoli-plugins 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +105 -0
- package/dist/chunk-6XXMT37V.js +162 -0
- package/dist/chunk-WOOF7XZX.js +109 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +10 -0
- package/dist/plugins/rehype-validate-links.d.ts +9 -0
- package/dist/plugins/rehype-validate-links.js +8 -0
- package/dist/plugins/starlight-index-only-sidebar.d.ts +18 -0
- package/dist/plugins/starlight-index-only-sidebar.js +6 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Cannoli Starlight Plugins
|
|
2
|
+
|
|
3
|
+
A collection of powerful plugins for [Astro Starlight](https://starlight.astro.build/) documentation sites.
|
|
4
|
+
|
|
5
|
+
## Plugins
|
|
6
|
+
|
|
7
|
+
### Starlight Index-Only Sidebar
|
|
8
|
+
|
|
9
|
+
Automatically generates your Starlight sidebar by scanning for `index.md` files in specified directories. Only directories containing an `index.md` file will appear in the sidebar.
|
|
10
|
+
|
|
11
|
+
**Features:**
|
|
12
|
+
- Scans directories recursively for `index.md` files
|
|
13
|
+
- Respects frontmatter: `draft: true` and `sidebar.hidden: true` hide entries
|
|
14
|
+
- Option to use directory names as sidebar labels with automatic formatting (e.g., `csci-316` → `CSCI 316`)
|
|
15
|
+
- No manual sidebar configuration needed
|
|
16
|
+
|
|
17
|
+
**Usage:**
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// astro.config.mjs
|
|
21
|
+
import { defineConfig } from "astro/config";
|
|
22
|
+
import starlight from "@astrojs/starlight";
|
|
23
|
+
import { starlightIndexOnlySidebar } from "cannoli-starlight-plugins";
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
integrations: [
|
|
27
|
+
starlight({
|
|
28
|
+
title: "My Docs",
|
|
29
|
+
plugins: [
|
|
30
|
+
starlightIndexOnlySidebar({
|
|
31
|
+
directories: [
|
|
32
|
+
{ label: "Guides", directory: "guides" },
|
|
33
|
+
{ label: "API Docs", directory: "api" },
|
|
34
|
+
],
|
|
35
|
+
dirnameDeterminesLabel: false, // optional: use directory names as labels
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Rehype Validate Links
|
|
44
|
+
|
|
45
|
+
A rehype plugin that validates all internal links in your Markdown/MDX files at build time. Links without matching files will cause the build to fail.
|
|
46
|
+
|
|
47
|
+
**Features:**
|
|
48
|
+
- Validates `<a href>` and `<img src>` attributes
|
|
49
|
+
- Supports relative paths (`../other`) and absolute paths (`/some/page`)
|
|
50
|
+
- Auto-expands extensionless links to match `.md` or `.mdx` files
|
|
51
|
+
- Converts internal links to site-absolute paths
|
|
52
|
+
- Throws build errors for broken links
|
|
53
|
+
|
|
54
|
+
**Usage:**
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// astro.config.mjs
|
|
58
|
+
import { defineConfig } from "astro/config";
|
|
59
|
+
import { rehypeValidateLinks } from "cannoli-starlight-plugins";
|
|
60
|
+
|
|
61
|
+
export default defineConfig({
|
|
62
|
+
markdown: {
|
|
63
|
+
rehypePlugins: [
|
|
64
|
+
rehypeValidateLinks,
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or import directly:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { rehypeValidateLinks } from "cannoli-starlight-plugins/rehype-validate-links";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install cannoli-starlight-plugins
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
With pnpm:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pnpm add cannoli-starlight-plugins
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
With yarn:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
yarn add cannoli-starlight-plugins
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Peer Dependencies
|
|
95
|
+
|
|
96
|
+
- `astro` ≥ 5.0.0
|
|
97
|
+
- `@astrojs/starlight` ≥ 0.30.0 (optional, only needed if using `starlightIndexOnlySidebar`)
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
|
102
|
+
|
|
103
|
+
## Contributing
|
|
104
|
+
|
|
105
|
+
Contributions welcome! Feel free to open issues or submit pull requests.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// src/plugins/starlight-index-only-sidebar.ts
|
|
2
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { parse as parseYaml } from "yaml";
|
|
5
|
+
var SITE_DOCS_ROOT = "./src/content/docs";
|
|
6
|
+
function getFrontmatterMetadata(mdFilePath) {
|
|
7
|
+
const defaultMetadata = {
|
|
8
|
+
title: null,
|
|
9
|
+
draft: false,
|
|
10
|
+
sidebarHidden: false
|
|
11
|
+
};
|
|
12
|
+
try {
|
|
13
|
+
const content = readFileSync(mdFilePath, "utf-8");
|
|
14
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
15
|
+
if (!match) return defaultMetadata;
|
|
16
|
+
const frontmatterText = match[1];
|
|
17
|
+
const frontmatter = parseYaml(frontmatterText);
|
|
18
|
+
if (!frontmatter || typeof frontmatter !== "object") {
|
|
19
|
+
return defaultMetadata;
|
|
20
|
+
}
|
|
21
|
+
const title = typeof frontmatter.title === "string" ? frontmatter.title : null;
|
|
22
|
+
const draft = frontmatter.draft === true;
|
|
23
|
+
let sidebarHidden = false;
|
|
24
|
+
if (frontmatter.sidebar) {
|
|
25
|
+
if (typeof frontmatter.sidebar === "object" && frontmatter.sidebar !== null) {
|
|
26
|
+
sidebarHidden = frontmatter.sidebar.hidden === true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
title,
|
|
31
|
+
draft,
|
|
32
|
+
sidebarHidden
|
|
33
|
+
};
|
|
34
|
+
} catch {
|
|
35
|
+
return defaultMetadata;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function pathSegmentToLabel(pathSegment) {
|
|
39
|
+
let label = pathSegment.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
40
|
+
const match = label.match(/^([a-z]+) [0-9]{2,}/i);
|
|
41
|
+
if (match) {
|
|
42
|
+
const firstGroup = match[1];
|
|
43
|
+
const uppercasedFirstGroup = firstGroup.toUpperCase();
|
|
44
|
+
label = uppercasedFirstGroup + label.substring(firstGroup.length);
|
|
45
|
+
}
|
|
46
|
+
return label;
|
|
47
|
+
}
|
|
48
|
+
function processRootIndex(dir, basePath, dirDeterminesLabel, items) {
|
|
49
|
+
if (!basePath || basePath.includes("/")) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const indexPath = join(dir, "index.md");
|
|
53
|
+
try {
|
|
54
|
+
statSync(indexPath);
|
|
55
|
+
} catch {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const metadata = getFrontmatterMetadata(indexPath);
|
|
59
|
+
if (metadata.draft || metadata.sidebarHidden) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (dirDeterminesLabel) {
|
|
63
|
+
const lastSegment = basePath.split("/").pop() || basePath;
|
|
64
|
+
items.push({
|
|
65
|
+
label: pathSegmentToLabel(lastSegment),
|
|
66
|
+
slug: basePath
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
items.push(basePath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function buildIndexSidebar(dir, basePath = "", docsRoot, dirDeterminesLabel = false) {
|
|
73
|
+
const items = [];
|
|
74
|
+
try {
|
|
75
|
+
processRootIndex(dir, basePath, dirDeterminesLabel, items);
|
|
76
|
+
const entries = readdirSync(dir).sort();
|
|
77
|
+
for (const entry of entries) {
|
|
78
|
+
if (entry.startsWith(".")) continue;
|
|
79
|
+
const fullPath = join(dir, entry);
|
|
80
|
+
const stat = statSync(fullPath);
|
|
81
|
+
if (stat.isDirectory()) {
|
|
82
|
+
const indexPath = join(fullPath, "index.md");
|
|
83
|
+
const slug = basePath ? `${basePath}/${entry}` : entry;
|
|
84
|
+
try {
|
|
85
|
+
statSync(indexPath);
|
|
86
|
+
const metadata = getFrontmatterMetadata(indexPath);
|
|
87
|
+
if (metadata.draft || metadata.sidebarHidden) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const subItems = buildIndexSidebar(fullPath, slug, docsRoot, dirDeterminesLabel);
|
|
91
|
+
if (subItems.length > 0) {
|
|
92
|
+
let groupLabel;
|
|
93
|
+
if (dirDeterminesLabel) {
|
|
94
|
+
groupLabel = pathSegmentToLabel(entry);
|
|
95
|
+
} else {
|
|
96
|
+
const title = metadata.title || entry;
|
|
97
|
+
groupLabel = title;
|
|
98
|
+
}
|
|
99
|
+
items.push({
|
|
100
|
+
label: groupLabel,
|
|
101
|
+
items: [dirDeterminesLabel ? { label: groupLabel, slug } : slug, ...subItems]
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
if (dirDeterminesLabel) {
|
|
105
|
+
items.push({
|
|
106
|
+
label: pathSegmentToLabel(entry),
|
|
107
|
+
slug
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
items.push(slug);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
const subItems = buildIndexSidebar(fullPath, slug, docsRoot, dirDeterminesLabel);
|
|
115
|
+
if (subItems.length > 0) {
|
|
116
|
+
items.push(...subItems);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error(`Error reading directory ${dir}:`, error);
|
|
123
|
+
}
|
|
124
|
+
return items.sort((a, b) => {
|
|
125
|
+
const aIsGroup = typeof a === "object" && "items" in a;
|
|
126
|
+
const bIsGroup = typeof b === "object" && "items" in b;
|
|
127
|
+
if (!aIsGroup && bIsGroup) return -1;
|
|
128
|
+
if (aIsGroup && !bIsGroup) return 1;
|
|
129
|
+
return 0;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function starlightIndexOnlySidebar(options) {
|
|
133
|
+
return {
|
|
134
|
+
name: "index-only-sidebar",
|
|
135
|
+
hooks: {
|
|
136
|
+
"config:setup": (hookOptions) => {
|
|
137
|
+
const { updateConfig } = hookOptions;
|
|
138
|
+
const dirnameDeterminesLabel = options.dirnameDeterminesLabel ?? false;
|
|
139
|
+
const sidebarItems = options.directories.map((dirConfig) => {
|
|
140
|
+
const dirItems = buildIndexSidebar(
|
|
141
|
+
join(SITE_DOCS_ROOT, dirConfig.directory),
|
|
142
|
+
dirConfig.directory,
|
|
143
|
+
SITE_DOCS_ROOT,
|
|
144
|
+
dirnameDeterminesLabel
|
|
145
|
+
);
|
|
146
|
+
const label = dirnameDeterminesLabel ? pathSegmentToLabel(dirConfig.directory) : dirConfig.label;
|
|
147
|
+
return {
|
|
148
|
+
label,
|
|
149
|
+
items: dirItems
|
|
150
|
+
};
|
|
151
|
+
}).filter((group) => group.items.length > 0);
|
|
152
|
+
updateConfig({
|
|
153
|
+
sidebar: sidebarItems
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export {
|
|
161
|
+
starlightIndexOnlySidebar
|
|
162
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/plugins/rehype-validate-links.ts
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { sync as globSync } from "glob";
|
|
4
|
+
import { dirname, join, relative, resolve } from "path";
|
|
5
|
+
import { visit } from "unist-util-visit";
|
|
6
|
+
var PROJECT_DOCS_DIR = "src/content/docs";
|
|
7
|
+
function getResolvedLink(href, currentFilePath) {
|
|
8
|
+
try {
|
|
9
|
+
new URL(href);
|
|
10
|
+
return null;
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
if (!href) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const fragmentMatch = href.split("#");
|
|
17
|
+
const withoutFragment = fragmentMatch[0];
|
|
18
|
+
const fragment = fragmentMatch[1] || "";
|
|
19
|
+
if (!withoutFragment) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
let projectAbsolute;
|
|
23
|
+
let relativePath;
|
|
24
|
+
if (withoutFragment.startsWith("/")) {
|
|
25
|
+
relativePath = withoutFragment.slice(1);
|
|
26
|
+
projectAbsolute = join(PROJECT_DOCS_DIR, relativePath);
|
|
27
|
+
} else {
|
|
28
|
+
const currentFileDir = dirname(currentFilePath);
|
|
29
|
+
const resolvedAbsPath = resolve(currentFileDir, withoutFragment);
|
|
30
|
+
projectAbsolute = resolvedAbsPath;
|
|
31
|
+
const docsRootAbsolute = resolve(PROJECT_DOCS_DIR);
|
|
32
|
+
relativePath = relative(docsRootAbsolute, resolvedAbsPath);
|
|
33
|
+
}
|
|
34
|
+
const hasExtension = /\.[a-z0-9]+$/i.test(projectAbsolute);
|
|
35
|
+
let finalProjectAbsoluteHref;
|
|
36
|
+
if (!hasExtension) {
|
|
37
|
+
finalProjectAbsoluteHref = `${projectAbsolute}.{md,mdx}`;
|
|
38
|
+
} else {
|
|
39
|
+
finalProjectAbsoluteHref = projectAbsolute;
|
|
40
|
+
}
|
|
41
|
+
let siteAbsoluteHref = "/" + relativePath;
|
|
42
|
+
if (fragment) {
|
|
43
|
+
siteAbsoluteHref += "#" + fragment;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
original_href: href,
|
|
47
|
+
project_absolute_href: finalProjectAbsoluteHref,
|
|
48
|
+
site_absolute_href: siteAbsoluteHref,
|
|
49
|
+
fragment
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function validateLink(link) {
|
|
53
|
+
const { project_absolute_href } = link;
|
|
54
|
+
if (project_absolute_href.includes(".{md,mdx}")) {
|
|
55
|
+
const matches = globSync(project_absolute_href);
|
|
56
|
+
if (matches.length === 0) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Link validation error: No matching file found for: ${link.original_href} (pattern: ${project_absolute_href})`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (matches.length > 1) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Link validation error: Multiple matching files found: ${matches.join(
|
|
64
|
+
", "
|
|
65
|
+
)} (from link: ${link.original_href})`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
if (!existsSync(project_absolute_href)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Link validation error: File not found: ${project_absolute_href} (from link: ${link.original_href})`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function rehypeValidateLinks() {
|
|
77
|
+
return (tree, file) => {
|
|
78
|
+
const filePath = file.path;
|
|
79
|
+
if (!filePath) {
|
|
80
|
+
console.warn(
|
|
81
|
+
"rehype-validate-links: Unable to determine file path for link validation. Skipping link validation for this file."
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
visit(tree, "element", (node) => {
|
|
86
|
+
let resourcePath;
|
|
87
|
+
let attributeName = null;
|
|
88
|
+
if (node.tagName === "a") {
|
|
89
|
+
resourcePath = node.properties?.href;
|
|
90
|
+
attributeName = "href";
|
|
91
|
+
} else if (node.tagName === "img") {
|
|
92
|
+
resourcePath = node.properties?.src;
|
|
93
|
+
attributeName = "src";
|
|
94
|
+
}
|
|
95
|
+
if (!resourcePath || !attributeName) return;
|
|
96
|
+
const link = getResolvedLink(resourcePath, filePath);
|
|
97
|
+
if (!link) return;
|
|
98
|
+
validateLink(link);
|
|
99
|
+
node.properties = node.properties || {};
|
|
100
|
+
node.properties[attributeName] = link.site_absolute_href;
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
var rehype_validate_links_default = rehypeValidateLinks;
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
rehypeValidateLinks,
|
|
108
|
+
rehype_validate_links_default
|
|
109
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Root } from 'hast';
|
|
2
|
+
import { VFile } from 'vfile';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rehype plugin to validate all internal links and convert them to absolute paths
|
|
6
|
+
*/
|
|
7
|
+
declare function rehypeValidateLinks(): (tree: Root, file: VFile) => void;
|
|
8
|
+
|
|
9
|
+
export { rehypeValidateLinks as default, rehypeValidateLinks };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { HookParameters } from '@astrojs/starlight/types';
|
|
2
|
+
|
|
3
|
+
type TDirectoryConfig = {
|
|
4
|
+
label: string;
|
|
5
|
+
directory: string;
|
|
6
|
+
};
|
|
7
|
+
type TIndexOnlySidebarPluginOptions = {
|
|
8
|
+
directories: Array<TDirectoryConfig>;
|
|
9
|
+
dirnameDeterminesLabel?: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare function starlightIndexOnlySidebar(options: TIndexOnlySidebarPluginOptions): {
|
|
12
|
+
name: string;
|
|
13
|
+
hooks: {
|
|
14
|
+
"config:setup": (hookOptions: HookParameters<"config:setup">) => void;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { starlightIndexOnlySidebar };
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "starlight-cannoli-plugins",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Starlight plugins for automatic sidebar generation and link validation",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./starlight-index-only-sidebar": {
|
|
15
|
+
"import": "./dist/plugins/starlight-index-only-sidebar.js",
|
|
16
|
+
"types": "./dist/plugins/starlight-index-only-sidebar.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./rehype-validate-links": {
|
|
19
|
+
"import": "./dist/plugins/rehype-validate-links.js",
|
|
20
|
+
"types": "./dist/plugins/rehype-validate-links.d.ts"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"astro",
|
|
28
|
+
"starlight",
|
|
29
|
+
"plugin",
|
|
30
|
+
"sidebar",
|
|
31
|
+
"rehype",
|
|
32
|
+
"link-validation"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/OccasionalCoderByTrade/astro-starlight-plugins"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build:lib": "tsup",
|
|
40
|
+
"dev": "node scripts/sync-docs-to-public.js && astro dev --port 5600",
|
|
41
|
+
"build": "npm run build:lib && node scripts/sync-docs-to-public.js && astro build",
|
|
42
|
+
"preview": "astro build && astro preview --port 5600",
|
|
43
|
+
"help": "astro --help",
|
|
44
|
+
"check": "astro check",
|
|
45
|
+
"prepublishOnly": "npm run build:lib"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"glob": "^13.0.6",
|
|
49
|
+
"unist-util-visit": "^5.0.0",
|
|
50
|
+
"yaml": "^2.4.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@astrojs/starlight": ">=0.30.0",
|
|
54
|
+
"astro": ">=5.0.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"astro": {
|
|
58
|
+
"optional": false
|
|
59
|
+
},
|
|
60
|
+
"@astrojs/starlight": {
|
|
61
|
+
"optional": true
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@astrojs/check": "^0.9.6",
|
|
66
|
+
"@astrojs/starlight": "^0.37.6",
|
|
67
|
+
"@expressive-code/plugin-line-numbers": "^0.41.7",
|
|
68
|
+
"@hpcc-js/wasm": "^2.33.1",
|
|
69
|
+
"@types/hast": "^2.3.10",
|
|
70
|
+
"astro": "^5.6.1",
|
|
71
|
+
"hast": "^1.0.0",
|
|
72
|
+
"rehype-graphviz": "^0.3.0",
|
|
73
|
+
"rehype-mathjax": "^7.1.0",
|
|
74
|
+
"rehype-raw": "^7.0.0",
|
|
75
|
+
"remark-math": "^6.0.0",
|
|
76
|
+
"sharp": "^0.34.2",
|
|
77
|
+
"tsup": "^8.3.0",
|
|
78
|
+
"typescript": "^5.9.3",
|
|
79
|
+
"vfile": "^6.0.0",
|
|
80
|
+
"@eslint/js": "^10.0.1",
|
|
81
|
+
"@eslint/markdown": "^7.5.1",
|
|
82
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
84
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
85
|
+
"eslint": "^10.0.2",
|
|
86
|
+
"eslint-md-cannoli-plugins": "^1.0.2",
|
|
87
|
+
"globals": "^17.4.0",
|
|
88
|
+
"jiti": "^2.6.1",
|
|
89
|
+
"sass-embedded": "^1.97.3",
|
|
90
|
+
"typescript-eslint": "^8.56.1"
|
|
91
|
+
}
|
|
92
|
+
}
|