Add global link references

This commit is contained in:
tequ
2025-07-15 16:28:16 +09:00
parent 669f98e45f
commit 5747a948a6
5 changed files with 151 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ import starlight from '@astrojs/starlight'
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'astro/config'
import starlightOpenAPI, { openAPISidebarGroups } from 'starlight-openapi'
import { remarkGlobalReferences } from './src/plugins/remarkGlobalReferences'
// https://astro.build/config
export default defineConfig({
@@ -311,6 +312,9 @@ export default defineConfig({
}),
mdx(),
],
markdown: {
remarkPlugins: [remarkGlobalReferences],
},
vite: {
plugins: [tailwindcss()],
},

15
package-lock.json generated
View File

@@ -18,6 +18,7 @@
"astro": "^5.10.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"remark-reference-links": "^7.0.0",
"starlight-openapi": "^0.19.1",
"tailwindcss": "^4.1.11",
"vanilla-cookieconsent": "^3.1.0"
@@ -6421,6 +6422,20 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/remark-reference-links": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/remark-reference-links/-/remark-reference-links-7.0.0.tgz",
"integrity": "sha512-OMACEps7CkpBio5nutUToCcXFJr9QkkoHdku41iIholMdFZ0jdRxgFmPm2B7R+DSvW83ZShdA3ubWTH+C3M6Eg==",
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
"unist-util-visit": "^5.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/remark-rehype": {
"version": "11.1.2",
"resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",

View File

@@ -20,6 +20,7 @@
"astro": "^5.10.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"remark-reference-links": "^7.0.0",
"starlight-openapi": "^0.19.1",
"tailwindcss": "^4.1.11",
"vanilla-cookieconsent": "^3.1.0"

View File

@@ -0,0 +1,2 @@
<!-- Currently, remarkPlugins does not support HMR, so you will need to restart the dev server if you change this file. -->
[Internal Type]: /docs/protocol-reference/binary-format

View File

@@ -0,0 +1,129 @@
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { visit } from 'unist-util-visit'
/**
* Remark plugin to resolve reference-style links from global.md
*/
export function remarkGlobalReferences() {
let globalRefs: Record<string, string> | null = null
function loadGlobalReferences() {
if (globalRefs !== null) return globalRefs
try {
const globalMdPath = join(
process.cwd(),
'src/content/references/global.md',
)
const content = readFileSync(globalMdPath, 'utf-8')
globalRefs = {}
// Parse reference-style link definitions: [label]: url
const lines = content.split('\n')
for (const line of lines) {
const match = line.match(/^\[([^\]]+)\]:\s*(.+)$/)
if (match) {
const [, label, url] = match
globalRefs[label] = url.trim()
}
}
console.log('Loaded global references:', globalRefs)
return globalRefs
} catch (error: any) {
console.warn('Could not load global.md references:', error.message)
globalRefs = {}
return globalRefs
}
}
return function transformer(tree: any) {
const refs = loadGlobalReferences()
// Find all reference-style links in the format [text][]
visit(tree, 'linkReference', (node) => {
if (
node.referenceType === 'shortcut' ||
node.referenceType === 'collapsed'
) {
const label = node.label || node.children?.[0]?.value
if (label && refs[label]) {
// Convert linkReference to a regular link
node.type = 'link'
node.url = refs[label]
delete node.referenceType
delete node.identifier
delete node.label
console.log(`Resolved reference [${label}][] to ${refs[label]}`)
}
}
})
// Also look for escaped reference-style links in text nodes: \[label]\[]
visit(tree, 'text', (node, index, parent) => {
if (!node.value) return
// Find escaped reference-style links: \[label]\[]
const pattern = /\\?\[([^\]]+)\\?\]\\?\[\]/g
const replacements = []
let match: RegExpExecArray | null = null
match = pattern.exec(node.value)
while (match !== null) {
const [fullMatch, label] = match
if (refs[label]) {
replacements.push({
start: match.index,
end: match.index + fullMatch.length,
label,
url: refs[label],
})
console.log(`Found escaped reference ${fullMatch} -> ${refs[label]}`)
}
match = pattern.exec(node.value)
}
// Apply replacements from right to left to maintain indices
if (replacements.length > 0) {
const newNodes = []
let lastIndex = 0
for (const replacement of replacements) {
// Add text before the replacement
if (replacement.start > lastIndex) {
newNodes.push({
type: 'text',
value: node.value.slice(lastIndex, replacement.start),
})
}
// Add the link
newNodes.push({
type: 'link',
url: replacement.url,
children: [{ type: 'text', value: replacement.label }],
})
lastIndex = replacement.end
}
// Add remaining text
if (lastIndex < node.value.length) {
newNodes.push({
type: 'text',
value: node.value.slice(lastIndex),
})
}
// Replace the current node with the new nodes
if (parent && typeof index === 'number') {
parent.children.splice(index, 1, ...newNodes)
}
}
})
}
}