mirror of
				https://github.com/Xahau/xahau-web.git
				synced 2025-11-04 12:15:49 +00:00 
			
		
		
		
	Merge pull request #51 from tequdev/global-ref
Enable external references in Markdown
This commit is contained in:
		@@ -6,6 +6,7 @@ import starlight from '@astrojs/starlight'
 | 
				
			|||||||
import tailwindcss from '@tailwindcss/vite'
 | 
					import tailwindcss from '@tailwindcss/vite'
 | 
				
			||||||
import { defineConfig } from 'astro/config'
 | 
					import { defineConfig } from 'astro/config'
 | 
				
			||||||
import starlightOpenAPI, { openAPISidebarGroups } from 'starlight-openapi'
 | 
					import starlightOpenAPI, { openAPISidebarGroups } from 'starlight-openapi'
 | 
				
			||||||
 | 
					import { remarkGlobalReferences } from './src/plugins/remarkGlobalReferences'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// https://astro.build/config
 | 
					// https://astro.build/config
 | 
				
			||||||
export default defineConfig({
 | 
					export default defineConfig({
 | 
				
			||||||
@@ -311,6 +312,9 @@ export default defineConfig({
 | 
				
			|||||||
    }),
 | 
					    }),
 | 
				
			||||||
    mdx(),
 | 
					    mdx(),
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 | 
					  markdown: {
 | 
				
			||||||
 | 
					    remarkPlugins: [remarkGlobalReferences],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  vite: {
 | 
					  vite: {
 | 
				
			||||||
    plugins: [tailwindcss()],
 | 
					    plugins: [tailwindcss()],
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -18,6 +18,7 @@
 | 
				
			|||||||
        "astro": "^5.10.1",
 | 
					        "astro": "^5.10.1",
 | 
				
			||||||
        "react": "^19.1.0",
 | 
					        "react": "^19.1.0",
 | 
				
			||||||
        "react-dom": "^19.1.0",
 | 
					        "react-dom": "^19.1.0",
 | 
				
			||||||
 | 
					        "remark-reference-links": "^7.0.0",
 | 
				
			||||||
        "starlight-openapi": "^0.19.1",
 | 
					        "starlight-openapi": "^0.19.1",
 | 
				
			||||||
        "tailwindcss": "^4.1.11",
 | 
					        "tailwindcss": "^4.1.11",
 | 
				
			||||||
        "vanilla-cookieconsent": "^3.1.0"
 | 
					        "vanilla-cookieconsent": "^3.1.0"
 | 
				
			||||||
@@ -6421,6 +6422,20 @@
 | 
				
			|||||||
        "url": "https://opencollective.com/unified"
 | 
					        "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": {
 | 
					    "node_modules/remark-rehype": {
 | 
				
			||||||
      "version": "11.1.2",
 | 
					      "version": "11.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@
 | 
				
			|||||||
    "astro": "^5.10.1",
 | 
					    "astro": "^5.10.1",
 | 
				
			||||||
    "react": "^19.1.0",
 | 
					    "react": "^19.1.0",
 | 
				
			||||||
    "react-dom": "^19.1.0",
 | 
					    "react-dom": "^19.1.0",
 | 
				
			||||||
 | 
					    "remark-reference-links": "^7.0.0",
 | 
				
			||||||
    "starlight-openapi": "^0.19.1",
 | 
					    "starlight-openapi": "^0.19.1",
 | 
				
			||||||
    "tailwindcss": "^4.1.11",
 | 
					    "tailwindcss": "^4.1.11",
 | 
				
			||||||
    "vanilla-cookieconsent": "^3.1.0"
 | 
					    "vanilla-cookieconsent": "^3.1.0"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								src/content/references/global.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/content/references/global.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<!-- 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
 | 
				
			||||||
 | 
					[Sequence Number]: /docs/protocol-reference/data-types/#account-sequence
 | 
				
			||||||
 | 
					[Index Number]: /docs/protocol-reference/data-types/#index-number
 | 
				
			||||||
 | 
					[SHA-512Half]: /docs/protocol-reference/data-types/#hashes
 | 
				
			||||||
 | 
					[Specifying Time]: /docs/protocol-reference/data-types/#specifying-time
 | 
				
			||||||
 | 
					[seconds since the Ripple Epoch]: /docs/protocol-reference/data-types/#specifying-time
 | 
				
			||||||
 | 
					[Ledger Index]: /docs/protocol-reference/data-types/#ledger-index
 | 
				
			||||||
 | 
					[ledger index]: /docs/protocol-reference/data-types/#ledger-index
 | 
				
			||||||
 | 
					[Hash]: /docs/protocol-reference/data-types/#hashes
 | 
				
			||||||
 | 
					[Address]: /docs/protocol-reference/data-types/#addresses
 | 
				
			||||||
 | 
					[Currency Amount]: /docs/protocol-reference/data-types/#specifying-currency-amounts
 | 
				
			||||||
 | 
					[drops of XAH]: /docs/protocol-reference/data-types/#specifying-currency-amounts
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/content/references/pseudo-transactions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/content/references/pseudo-transactions.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					EnableAmendment
 | 
				
			||||||
 | 
					EmitFailure
 | 
				
			||||||
 | 
					SetFee
 | 
				
			||||||
 | 
					UNLModify
 | 
				
			||||||
 | 
					UNLReport
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/content/references/transactions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/content/references/transactions.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					AccountDelete
 | 
				
			||||||
 | 
					AccountSet
 | 
				
			||||||
 | 
					CheckCancel
 | 
				
			||||||
 | 
					CheckCash
 | 
				
			||||||
 | 
					CheckCreate
 | 
				
			||||||
 | 
					ClaimReward
 | 
				
			||||||
 | 
					Clawback
 | 
				
			||||||
 | 
					DepositPreauth
 | 
				
			||||||
 | 
					EscrowCancel
 | 
				
			||||||
 | 
					EscrowCreate
 | 
				
			||||||
 | 
					EscrowFinish
 | 
				
			||||||
 | 
					GenesisMint
 | 
				
			||||||
 | 
					Import
 | 
				
			||||||
 | 
					Invoke
 | 
				
			||||||
 | 
					NFTokenAcceptOffer
 | 
				
			||||||
 | 
					NFTokenBurn
 | 
				
			||||||
 | 
					NFTokenCancelOffer
 | 
				
			||||||
 | 
					NFTokenCreateOffer
 | 
				
			||||||
 | 
					NFTokenMint
 | 
				
			||||||
 | 
					OfferCancel
 | 
				
			||||||
 | 
					OfferCreate
 | 
				
			||||||
 | 
					Payment
 | 
				
			||||||
 | 
					PaymentChannelClaim
 | 
				
			||||||
 | 
					PaymentChannelCreate
 | 
				
			||||||
 | 
					PaymentChannelFund
 | 
				
			||||||
 | 
					Remit
 | 
				
			||||||
 | 
					SetHook
 | 
				
			||||||
 | 
					SetRegularKey
 | 
				
			||||||
 | 
					SetRemarks
 | 
				
			||||||
 | 
					SignerListSet
 | 
				
			||||||
 | 
					SpinalTap
 | 
				
			||||||
 | 
					TicketCreate
 | 
				
			||||||
 | 
					TrustSet
 | 
				
			||||||
 | 
					URITokenBurn
 | 
				
			||||||
 | 
					URITokenBuy
 | 
				
			||||||
 | 
					URITokenCancelSellOffer
 | 
				
			||||||
 | 
					URITokenCreateSellOffer
 | 
				
			||||||
 | 
					URITokenMint
 | 
				
			||||||
							
								
								
									
										168
									
								
								src/plugins/remarkGlobalReferences.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/plugins/remarkGlobalReferences.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					import { readFileSync } from 'node:fs'
 | 
				
			||||||
 | 
					import { visit } from 'unist-util-visit'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const parseRules: {
 | 
				
			||||||
 | 
					  path: string
 | 
				
			||||||
 | 
					  parse: (content: string) => { label: string; url: string }[]
 | 
				
			||||||
 | 
					}[] = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'src/content/references/global.md',
 | 
				
			||||||
 | 
					    parse: (content: string) => {
 | 
				
			||||||
 | 
					      const lines = content.split('\n')
 | 
				
			||||||
 | 
					      const result: { label: string; url: string }[] = []
 | 
				
			||||||
 | 
					      for (const line of lines) {
 | 
				
			||||||
 | 
					        const match = line.match(/^\[([^\]]+)\]:\s*(.+)$/)
 | 
				
			||||||
 | 
					        if (match) {
 | 
				
			||||||
 | 
					          const [, label, url] = match
 | 
				
			||||||
 | 
					          result.push({ label, url: url.trim() })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return result
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'src/content/references/transactions.md',
 | 
				
			||||||
 | 
					    parse: (content: string) => {
 | 
				
			||||||
 | 
					      const lines = content.split('\n')
 | 
				
			||||||
 | 
					      const result: { label: string; url: string }[] = []
 | 
				
			||||||
 | 
					      for (const line of lines) {
 | 
				
			||||||
 | 
					        if (line.length > 0) {
 | 
				
			||||||
 | 
					          const url = `/docs/protocol-reference/transactions/transaction-types/${line.toLowerCase()}`
 | 
				
			||||||
 | 
					          result.push({ label: `${line}`, url })
 | 
				
			||||||
 | 
					          result.push({ label: `${line} transaction`, url })
 | 
				
			||||||
 | 
					          result.push({ label: `${line} transactions`, url })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return result
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'src/content/references/pseudo-transactions.md',
 | 
				
			||||||
 | 
					    parse: (content: string) => {
 | 
				
			||||||
 | 
					      const lines = content.split('\n')
 | 
				
			||||||
 | 
					      const result: { label: string; url: string }[] = []
 | 
				
			||||||
 | 
					      for (const line of lines) {
 | 
				
			||||||
 | 
					        if (line.length > 0) {
 | 
				
			||||||
 | 
					          const url = `/docs/protocol-reference/transactions/pseudo-transaction-types/${line.toLowerCase()}`
 | 
				
			||||||
 | 
					          result.push({ label: `${line}`, url })
 | 
				
			||||||
 | 
					          result.push({ label: `${line} transaction`, url })
 | 
				
			||||||
 | 
					          result.push({ label: `${line} transactions`, url })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return result
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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 {
 | 
				
			||||||
 | 
					      globalRefs = {}
 | 
				
			||||||
 | 
					      for (const rule of parseRules) {
 | 
				
			||||||
 | 
					        const content = readFileSync(rule.path, 'utf-8')
 | 
				
			||||||
 | 
					        const refs = rule.parse(content)
 | 
				
			||||||
 | 
					        for (const ref of refs) {
 | 
				
			||||||
 | 
					          globalRefs[ref.label] = ref.url
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      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
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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],
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user