mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 23:49:51 +00:00
Zeta: Type MDX Plugins
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'next-docs-zeta': patch
|
||||
---
|
||||
|
||||
Type MDX Plugins
|
||||
@@ -22,9 +22,9 @@
|
||||
"import": "./dist/toc/index.mjs",
|
||||
"types": "./dist/toc/index.d.ts"
|
||||
},
|
||||
"./search": {
|
||||
"import": "./dist/search/index.mjs",
|
||||
"types": "./dist/search/index.d.ts"
|
||||
"./search/*": {
|
||||
"import": "./dist/search/*.mjs",
|
||||
"types": "./dist/search/*.d.ts"
|
||||
},
|
||||
"./server": {
|
||||
"import": "./dist/server/index.mjs",
|
||||
@@ -50,13 +50,9 @@
|
||||
"import": "./dist/mdx-plugins/index.mjs",
|
||||
"types": "./dist/mdx-plugins/index.d.ts"
|
||||
},
|
||||
"./algolia": {
|
||||
"import": "./dist/algolia/index.mjs",
|
||||
"types": "./dist/algolia/index.d.ts"
|
||||
},
|
||||
"./search-algolia": {
|
||||
"import": "./dist/search-algolia/index.mjs",
|
||||
"types": "./dist/search-algolia/index.d.ts"
|
||||
"./search-algolia/*": {
|
||||
"import": "./dist/search-algolia/*.mjs",
|
||||
"types": "./dist/search-algolia/*.d.ts"
|
||||
}
|
||||
},
|
||||
"typesVersions": {
|
||||
@@ -70,8 +66,8 @@
|
||||
"toc": [
|
||||
"./dist/toc/index.d.ts"
|
||||
],
|
||||
"search": [
|
||||
"./dist/search/index.d.ts"
|
||||
"search/*": [
|
||||
"./dist/search/*.d.ts"
|
||||
],
|
||||
"server": [
|
||||
"./dist/server/index.d.ts"
|
||||
@@ -91,11 +87,8 @@
|
||||
"middleware": [
|
||||
"./dist/middleware/index.d.ts"
|
||||
],
|
||||
"algolia": [
|
||||
"./dist/algolia/index.d.ts"
|
||||
],
|
||||
"search-algolia": [
|
||||
"./dist/search-algolia/index.d.ts"
|
||||
"search-algolia/*": [
|
||||
"./dist/search-algolia/*.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -130,6 +123,8 @@
|
||||
"devDependencies": {
|
||||
"@algolia/client-search": "^4.20.0",
|
||||
"@types/flexsearch": "0.7.4",
|
||||
"@types/hast": "^2.3.5",
|
||||
"@types/mdast": "^3.0.12",
|
||||
"@types/negotiator": "^0.6.1",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-dom": "18.2.1",
|
||||
|
||||
+8
-6
@@ -1,15 +1,17 @@
|
||||
// @ts-nocheck
|
||||
import Slugger from 'github-slugger'
|
||||
import rehypePrettycode from 'rehype-pretty-code'
|
||||
import type { Root } from 'hast'
|
||||
import rehypePrettycode, {
|
||||
type Options as RehypePrettyCodeOptions
|
||||
} from 'rehype-pretty-code'
|
||||
import type { Transformer } from 'unified'
|
||||
import { flattenNode, visit } from './utils'
|
||||
|
||||
const slugger = new Slugger()
|
||||
const headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
|
||||
const customMetaRegex = /custom="([^"]+)"/
|
||||
|
||||
/**
|
||||
* @type {import('rehype-pretty-code').Options}
|
||||
*/
|
||||
const rehypePrettyCodeOptions = {
|
||||
const rehypePrettyCodeOptions: RehypePrettyCodeOptions = {
|
||||
theme: 'css-variables',
|
||||
defaultLang: {
|
||||
block: 'text'
|
||||
@@ -24,7 +26,7 @@ const rehypePrettyCodeOptions = {
|
||||
/**
|
||||
* Handle codeblocks and heading slugs
|
||||
*/
|
||||
export const rehypeNextDocs = () => async tree => {
|
||||
export const rehypeNextDocs = (): Transformer<Root, Root> => async tree => {
|
||||
slugger.reset()
|
||||
|
||||
visit(tree, ['pre', ...headings], node => {
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import type { Plugin } from 'unified'
|
||||
import type { Root } from 'mdast'
|
||||
import type { Transformer } from 'unified'
|
||||
import { visit } from 'unist-util-visit'
|
||||
|
||||
const regex = /^\|reference:(.+)\|/
|
||||
@@ -10,6 +11,12 @@ type Options = {
|
||||
cwd?: string
|
||||
/** @default true */
|
||||
trim?: boolean
|
||||
|
||||
/**
|
||||
* Filter specific element types
|
||||
* @default ['text','code']
|
||||
* */
|
||||
visit?: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18,18 +25,26 @@ type Options = {
|
||||
* @example
|
||||
* |reference:../path/to/file.ts|
|
||||
*/
|
||||
export function remarkDynamicContent(options: Options = {}): Plugin {
|
||||
const { cwd = process.cwd(), trim = true } = options
|
||||
export function remarkDynamicContent(
|
||||
options: Options = {}
|
||||
): Transformer<Root, Root> {
|
||||
const {
|
||||
cwd = process.cwd(),
|
||||
trim = true,
|
||||
visit: filter = ['text', 'code']
|
||||
} = options
|
||||
|
||||
return tree => {
|
||||
visit(tree, ['text', 'code'], node => {
|
||||
visit(tree, filter, node => {
|
||||
if (!('value' in node) || typeof node.value !== 'string') return
|
||||
const result = regex.exec(node.value)
|
||||
|
||||
if (result && result[1]) {
|
||||
const dest = path.resolve(cwd, result[1])
|
||||
let value = fs.readFileSync(dest).toString()
|
||||
if (trim) value = value.trim()
|
||||
|
||||
node.value = fs.readFileSync(dest).toString()
|
||||
if (trim) node.value = node.value.trim()
|
||||
node.value = value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// @ts-nocheck
|
||||
import Slugger from 'github-slugger'
|
||||
import type { Node, Root } from 'mdast'
|
||||
import { remark } from 'remark'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkMdx from 'remark-mdx'
|
||||
import type { PluggableList } from 'unified'
|
||||
import type { PluggableList, Transformer } from 'unified'
|
||||
import { visit } from 'unist-util-visit'
|
||||
|
||||
type Heading = {
|
||||
@@ -36,8 +37,8 @@ type Options = {
|
||||
const slugger = new Slugger()
|
||||
const textTypes = ['text', 'inlineCode']
|
||||
|
||||
function flattenNode(node: any) {
|
||||
const p: any[] = []
|
||||
function flattenNode(node: Node) {
|
||||
const p: string[] = []
|
||||
visit(node, textTypes, node => {
|
||||
if (typeof node.value !== 'string') return
|
||||
p.push(node.value)
|
||||
@@ -45,9 +46,10 @@ function flattenNode(node: any) {
|
||||
return p.join(``)
|
||||
}
|
||||
|
||||
const structurize =
|
||||
({ types = ['paragraph', 'blockquote', 'heading'] }: Options = {}) =>
|
||||
(node: any, file: any) => {
|
||||
function structurize({
|
||||
types = ['paragraph', 'blockquote', 'heading']
|
||||
}: Options = {}): Transformer<Root, Root> {
|
||||
return (node, file) => {
|
||||
slugger.reset()
|
||||
const data: StructuredData = { contents: [], headings: [] }
|
||||
let lastHeading: string | undefined = ''
|
||||
@@ -76,6 +78,7 @@ const structurize =
|
||||
|
||||
file.data = data
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract data from markdown/mdx content
|
||||
@@ -92,5 +95,5 @@ export function structure(
|
||||
.use([structurize, options])
|
||||
.processSync(content)
|
||||
|
||||
return result.data as StructuredData
|
||||
return result.data
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* @typedef {import('hast').Nodes} Nodes
|
||||
* @typedef {import('hast').Parents} Parents
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visit a node with filtered tag names
|
||||
*
|
||||
* @param {Nodes} node
|
||||
* Node to visit.
|
||||
* @param {Array<string>} tagNames
|
||||
* @param {(node: Nodes) => void} handler
|
||||
*/
|
||||
export function visit(node, tagNames, handler) {
|
||||
if (tagNames.includes(node.tagName)) {
|
||||
handler(node)
|
||||
return
|
||||
}
|
||||
|
||||
node.children?.forEach(n => visit(n, tagNames, handler))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plain-text value of a hast node.
|
||||
*
|
||||
* @param {Nodes} node
|
||||
* Node to serialize.
|
||||
* @returns {string}
|
||||
* Serialized node.
|
||||
*/
|
||||
export function flattenNode(node) {
|
||||
// “The concatenation of data of all the Text node descendants of the context
|
||||
// object, in tree order.”
|
||||
if ('children' in node) {
|
||||
return all(node)
|
||||
}
|
||||
|
||||
// “Context object’s data.”
|
||||
return 'value' in node ? node.value : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Nodes} node
|
||||
* Node.
|
||||
* @returns {string}
|
||||
* Serialized node.
|
||||
*/
|
||||
function one(node) {
|
||||
if (node.type === 'text') {
|
||||
return node.value
|
||||
}
|
||||
|
||||
return 'children' in node ? all(node) : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Parents} node
|
||||
* Node.
|
||||
* @returns {string}
|
||||
* Serialized node.
|
||||
*/
|
||||
function all(node) {
|
||||
/** @type {Array<string>} */
|
||||
const result = []
|
||||
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
result[i] = one(node.children[i])
|
||||
}
|
||||
|
||||
return result.join('')
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// @ts-nocheck
|
||||
import type { Node } from 'hast'
|
||||
|
||||
/**
|
||||
* Visit a node with filtered tag names
|
||||
*/
|
||||
export function visit(
|
||||
node: Node,
|
||||
tagNames: string[],
|
||||
handler: (node: Node) => void
|
||||
) {
|
||||
if (tagNames.includes(node.tagName)) {
|
||||
handler(node)
|
||||
return
|
||||
}
|
||||
|
||||
node.children?.forEach(n => visit(n, tagNames, handler))
|
||||
}
|
||||
|
||||
export function flattenNode(node: Node): string {
|
||||
if ('children' in node) {
|
||||
return all(node)
|
||||
}
|
||||
|
||||
return 'value' in node ? node.value : ''
|
||||
}
|
||||
|
||||
function one(node: Node): string {
|
||||
if (node.type === 'text') {
|
||||
return node.value
|
||||
}
|
||||
|
||||
return 'children' in node ? all(node) : ''
|
||||
}
|
||||
|
||||
function all(node: Node) {
|
||||
const result: string[] = []
|
||||
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
result[i] = one(node.children[i])
|
||||
}
|
||||
|
||||
return result.join('')
|
||||
}
|
||||
Generated
+6
@@ -286,6 +286,12 @@ importers:
|
||||
'@types/flexsearch':
|
||||
specifier: 0.7.4
|
||||
version: 0.7.4
|
||||
'@types/hast':
|
||||
specifier: ^2.3.5
|
||||
version: 2.3.5
|
||||
'@types/mdast':
|
||||
specifier: ^3.0.12
|
||||
version: 3.0.12
|
||||
'@types/negotiator':
|
||||
specifier: ^0.6.1
|
||||
version: 0.6.1
|
||||
|
||||
Reference in New Issue
Block a user