@usecross/docs 0.10.2 → 0.12.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/dist/index.d.ts +164 -7
- package/dist/index.js +1304 -44
- package/dist/index.js.map +1 -1
- package/dist/ssr.d.ts +1 -1
- package/dist/types-_anC1UJu.d.ts +320 -0
- package/package.json +1 -1
- package/src/components/DocsLayout.tsx +75 -59
- package/src/components/Sidebar.tsx +171 -28
- package/src/components/TableOfContents.tsx +6 -6
- package/src/components/api/APILayout.tsx +231 -0
- package/src/components/api/APIPage.tsx +216 -0
- package/src/components/api/Breadcrumb.tsx +98 -0
- package/src/components/api/ClassDoc.tsx +257 -0
- package/src/components/api/CodeSpan.tsx +53 -0
- package/src/components/api/Docstring.tsx +269 -0
- package/src/components/api/FunctionDoc.tsx +130 -0
- package/src/components/api/ModuleDoc.tsx +298 -0
- package/src/components/api/ParameterTable.tsx +183 -0
- package/src/components/api/Signature.tsx +317 -0
- package/src/components/api/TableOfContents.tsx +50 -0
- package/src/components/api/index.ts +17 -0
- package/src/components/index.ts +13 -1
- package/src/index.ts +32 -0
- package/src/types.ts +222 -1
- package/dist/types-DlTTA3Dc.d.ts +0 -128
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { GriffeParameter, GriffeDocstringSection, GriffeDocstringElement, GriffeExpression } from '../../types'
|
|
2
|
+
import { CodeSpan } from './CodeSpan'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Render a type annotation expression to string
|
|
6
|
+
*/
|
|
7
|
+
function renderExpression(expr: GriffeExpression | string | undefined): string {
|
|
8
|
+
if (!expr) return ''
|
|
9
|
+
if (typeof expr === 'string') return expr
|
|
10
|
+
if (expr.str) return expr.str
|
|
11
|
+
if (expr.canonical) return expr.canonical
|
|
12
|
+
|
|
13
|
+
const exprAny = expr as any
|
|
14
|
+
|
|
15
|
+
// Handle ExprName with member reference
|
|
16
|
+
if (expr.name && typeof expr.name === 'string') return expr.name
|
|
17
|
+
|
|
18
|
+
// Handle ExprBoolOp (like `config or StrawberryConfig()`)
|
|
19
|
+
if (exprAny.cls === 'ExprBoolOp' && exprAny.operator && Array.isArray(exprAny.values)) {
|
|
20
|
+
return exprAny.values.map((v: any) => renderExpression(v)).join(` ${exprAny.operator} `)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Handle ExprBinOp (like `type | None`)
|
|
24
|
+
if (exprAny.cls === 'ExprBinOp' && exprAny.left && exprAny.right) {
|
|
25
|
+
const left = renderExpression(exprAny.left)
|
|
26
|
+
const right = renderExpression(exprAny.right)
|
|
27
|
+
const op = exprAny.operator || '|'
|
|
28
|
+
return `${left} ${op} ${right}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle ExprCall (like `StrawberryConfig()`)
|
|
32
|
+
if (exprAny.cls === 'ExprCall' && exprAny.function) {
|
|
33
|
+
const funcName = renderExpression(exprAny.function)
|
|
34
|
+
const args = Array.isArray(exprAny.arguments)
|
|
35
|
+
? exprAny.arguments.map((a: any) => renderExpression(a)).join(', ')
|
|
36
|
+
: ''
|
|
37
|
+
return `${funcName}(${args})`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Handle ExprAttribute (like contextlib.asynccontextmanager)
|
|
41
|
+
if (exprAny.cls === 'ExprAttribute' && Array.isArray(exprAny.values)) {
|
|
42
|
+
return exprAny.values.map((v: any) => renderExpression(v)).join('.')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Handle ExprList and ExprTuple
|
|
46
|
+
if ('elements' in exprAny && Array.isArray(exprAny.elements)) {
|
|
47
|
+
const inner = exprAny.elements.map((el: any) => renderExpression(el)).join(', ')
|
|
48
|
+
return exprAny.cls === 'ExprTuple' ? `(${inner})` : `[${inner}]`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Handle ExprDict
|
|
52
|
+
if (exprAny.cls === 'ExprDict' && Array.isArray(exprAny.keys) && Array.isArray(exprAny.values)) {
|
|
53
|
+
const pairs = exprAny.keys.map((k: any, i: number) =>
|
|
54
|
+
`${renderExpression(k)}: ${renderExpression(exprAny.values[i])}`
|
|
55
|
+
).join(', ')
|
|
56
|
+
return `{${pairs}}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Handle ExprSubscript (like Dict[str, int])
|
|
60
|
+
if (exprAny.left && exprAny.slice) {
|
|
61
|
+
const left = renderExpression(exprAny.left)
|
|
62
|
+
const slice = renderExpression(exprAny.slice)
|
|
63
|
+
return `${left}[${slice}]`
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Handle slice expressions
|
|
67
|
+
if ('slice' in exprAny && exprAny.slice && !exprAny.left) {
|
|
68
|
+
return renderExpression(exprAny.slice)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Fallback for unknown expressions
|
|
72
|
+
if (typeof expr === 'object') {
|
|
73
|
+
return JSON.stringify(expr)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return String(expr)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get parameter description from docstring sections
|
|
81
|
+
*/
|
|
82
|
+
function getParamDescription(
|
|
83
|
+
paramName: string,
|
|
84
|
+
docstringSections?: GriffeDocstringSection[]
|
|
85
|
+
): string | undefined {
|
|
86
|
+
if (!docstringSections) return undefined
|
|
87
|
+
|
|
88
|
+
for (const section of docstringSections) {
|
|
89
|
+
if (section.kind === 'parameters' && Array.isArray(section.value)) {
|
|
90
|
+
const param = (section.value as GriffeDocstringElement[]).find(
|
|
91
|
+
(p) => p.name === paramName
|
|
92
|
+
)
|
|
93
|
+
if (param) return param.description
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return undefined
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface ParameterTableProps {
|
|
100
|
+
parameters: GriffeParameter[]
|
|
101
|
+
/** Docstring sections for parameter descriptions */
|
|
102
|
+
docstringSections?: GriffeDocstringSection[]
|
|
103
|
+
/** Additional CSS class */
|
|
104
|
+
className?: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Renders a two-column parameter list matching strawberry.rocks design.
|
|
109
|
+
* Left column: parameter name badge
|
|
110
|
+
* Right column: description, type, and default value
|
|
111
|
+
*/
|
|
112
|
+
export function ParameterTable({ parameters, docstringSections, className = '' }: ParameterTableProps) {
|
|
113
|
+
if (!parameters || parameters.length === 0) return null
|
|
114
|
+
|
|
115
|
+
// Filter out 'self' parameter for cleaner display
|
|
116
|
+
const displayParams = parameters.filter(p => p.name !== 'self')
|
|
117
|
+
|
|
118
|
+
if (displayParams.length === 0) return null
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<ol className={`list-none p-0 ${className}`}>
|
|
122
|
+
{displayParams.map((param, index) => {
|
|
123
|
+
const description = getParamDescription(param.name, docstringSections)
|
|
124
|
+
const annotation = renderExpression(param.annotation)
|
|
125
|
+
const defaultValue = renderExpression(param.default)
|
|
126
|
+
const isLast = index === displayParams.length - 1
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<li
|
|
130
|
+
key={param.name}
|
|
131
|
+
className="contents"
|
|
132
|
+
>
|
|
133
|
+
<div className={`grid grid-cols-[max-content_1fr] items-baseline gap-x-8 gap-y-2 py-6 ${!isLast ? 'border-b border-gray-200 dark:border-gray-700' : ''}`}>
|
|
134
|
+
{/* Parameter name badge - left column */}
|
|
135
|
+
<div className="flex-shrink-0">
|
|
136
|
+
<CodeSpan>
|
|
137
|
+
{param.kind === 'var-positional' && '*'}
|
|
138
|
+
{param.kind === 'var-keyword' && '**'}
|
|
139
|
+
{param.name}:
|
|
140
|
+
</CodeSpan>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{/* Description and metadata - right column */}
|
|
144
|
+
<div className="space-y-3">
|
|
145
|
+
{/* Description */}
|
|
146
|
+
{description && (
|
|
147
|
+
<p className="text-gray-700 dark:text-gray-300 leading-relaxed">
|
|
148
|
+
{description}
|
|
149
|
+
</p>
|
|
150
|
+
)}
|
|
151
|
+
|
|
152
|
+
{/* Type and Default in definition list style */}
|
|
153
|
+
<dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2">
|
|
154
|
+
{annotation && (
|
|
155
|
+
<>
|
|
156
|
+
<dt className="font-semibold text-gray-500 dark:text-gray-400">
|
|
157
|
+
Type
|
|
158
|
+
</dt>
|
|
159
|
+
<dd className="m-0">
|
|
160
|
+
<CodeSpan>{annotation}</CodeSpan>
|
|
161
|
+
</dd>
|
|
162
|
+
</>
|
|
163
|
+
)}
|
|
164
|
+
|
|
165
|
+
{defaultValue && (
|
|
166
|
+
<>
|
|
167
|
+
<dt className="font-semibold text-gray-500 dark:text-gray-400">
|
|
168
|
+
Default
|
|
169
|
+
</dt>
|
|
170
|
+
<dd className="m-0">
|
|
171
|
+
<CodeSpan>{defaultValue}</CodeSpan>
|
|
172
|
+
</dd>
|
|
173
|
+
</>
|
|
174
|
+
)}
|
|
175
|
+
</dl>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</li>
|
|
179
|
+
)
|
|
180
|
+
})}
|
|
181
|
+
</ol>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import type { GriffeFunction, GriffeParameter, GriffeExpression } from '../../types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Render a type annotation expression to string
|
|
6
|
+
*/
|
|
7
|
+
function renderExpression(expr: GriffeExpression | string | undefined): string {
|
|
8
|
+
if (!expr) return ''
|
|
9
|
+
if (typeof expr === 'string') return expr
|
|
10
|
+
if (expr.str) return expr.str
|
|
11
|
+
if (expr.canonical) return expr.canonical
|
|
12
|
+
|
|
13
|
+
const exprAny = expr as any
|
|
14
|
+
|
|
15
|
+
// Handle ExprName with member reference
|
|
16
|
+
if (expr.name && typeof expr.name === 'string') return expr.name
|
|
17
|
+
|
|
18
|
+
// Handle ExprBoolOp (like `config or StrawberryConfig()`)
|
|
19
|
+
if (exprAny.cls === 'ExprBoolOp' && exprAny.operator && Array.isArray(exprAny.values)) {
|
|
20
|
+
return exprAny.values.map((v: any) => renderExpression(v)).join(` ${exprAny.operator} `)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Handle ExprBinOp (like `type | None`)
|
|
24
|
+
if (exprAny.cls === 'ExprBinOp' && exprAny.left && exprAny.right) {
|
|
25
|
+
const left = renderExpression(exprAny.left)
|
|
26
|
+
const right = renderExpression(exprAny.right)
|
|
27
|
+
const op = exprAny.operator || '|'
|
|
28
|
+
return `${left} ${op} ${right}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle ExprCall (like `StrawberryConfig()`)
|
|
32
|
+
if (exprAny.cls === 'ExprCall' && exprAny.function) {
|
|
33
|
+
const funcName = renderExpression(exprAny.function)
|
|
34
|
+
const args = Array.isArray(exprAny.arguments)
|
|
35
|
+
? exprAny.arguments.map((a: any) => renderExpression(a)).join(', ')
|
|
36
|
+
: ''
|
|
37
|
+
return `${funcName}(${args})`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Handle ExprAttribute (like contextlib.asynccontextmanager)
|
|
41
|
+
if (exprAny.cls === 'ExprAttribute' && Array.isArray(exprAny.values)) {
|
|
42
|
+
return exprAny.values.map((v: any) => renderExpression(v)).join('.')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Handle ExprList and ExprTuple
|
|
46
|
+
if ('elements' in exprAny && Array.isArray(exprAny.elements)) {
|
|
47
|
+
const inner = exprAny.elements.map((el: any) => renderExpression(el)).join(', ')
|
|
48
|
+
return exprAny.cls === 'ExprTuple' ? `(${inner})` : `[${inner}]`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Handle ExprDict
|
|
52
|
+
if (exprAny.cls === 'ExprDict' && Array.isArray(exprAny.keys) && Array.isArray(exprAny.values)) {
|
|
53
|
+
const pairs = exprAny.keys.map((k: any, i: number) =>
|
|
54
|
+
`${renderExpression(k)}: ${renderExpression(exprAny.values[i])}`
|
|
55
|
+
).join(', ')
|
|
56
|
+
return `{${pairs}}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Handle ExprSubscript (like Dict[str, int])
|
|
60
|
+
if (exprAny.left && exprAny.slice) {
|
|
61
|
+
const left = renderExpression(exprAny.left)
|
|
62
|
+
const slice = renderExpression(exprAny.slice)
|
|
63
|
+
return `${left}[${slice}]`
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Handle slice expressions
|
|
67
|
+
if ('slice' in exprAny && exprAny.slice && !exprAny.left) {
|
|
68
|
+
return renderExpression(exprAny.slice)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Fallback for unknown expressions
|
|
72
|
+
if (typeof expr === 'object') {
|
|
73
|
+
return JSON.stringify(expr)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return String(expr)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Render a parameter with its type annotation and default value
|
|
81
|
+
*/
|
|
82
|
+
function renderParameter(param: GriffeParameter): string {
|
|
83
|
+
let result = ''
|
|
84
|
+
|
|
85
|
+
// Handle special parameter kinds
|
|
86
|
+
if (param.kind === 'var-positional') {
|
|
87
|
+
result = `*${param.name}`
|
|
88
|
+
} else if (param.kind === 'var-keyword') {
|
|
89
|
+
result = `**${param.name}`
|
|
90
|
+
} else {
|
|
91
|
+
result = param.name
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Add type annotation
|
|
95
|
+
if (param.annotation) {
|
|
96
|
+
const annotation = renderExpression(param.annotation)
|
|
97
|
+
if (annotation) {
|
|
98
|
+
result += `: ${annotation}`
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Add default value
|
|
103
|
+
if (param.default) {
|
|
104
|
+
result += ` = ${renderExpression(param.default)}`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return result
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Copy icon component
|
|
112
|
+
*/
|
|
113
|
+
function CopyIcon() {
|
|
114
|
+
return (
|
|
115
|
+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
116
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
117
|
+
</svg>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check icon component
|
|
123
|
+
*/
|
|
124
|
+
function CheckIcon() {
|
|
125
|
+
return (
|
|
126
|
+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
127
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
128
|
+
</svg>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface SignatureProps {
|
|
133
|
+
fn: GriffeFunction
|
|
134
|
+
/** Show full path or just function name */
|
|
135
|
+
showPath?: boolean
|
|
136
|
+
/** Additional CSS class */
|
|
137
|
+
className?: string
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Renders a Python function/method signature with syntax highlighting.
|
|
142
|
+
* Uses dark background style matching strawberry.rocks.
|
|
143
|
+
*/
|
|
144
|
+
export function Signature({ fn, showPath = false, className = '' }: SignatureProps) {
|
|
145
|
+
const [copied, setCopied] = useState(false)
|
|
146
|
+
const name = showPath && fn.path ? fn.path : fn.name
|
|
147
|
+
const isAsync = fn.is_async
|
|
148
|
+
|
|
149
|
+
// Filter out 'self' for cleaner display
|
|
150
|
+
const displayParams = fn.parameters?.filter(p => p.name !== 'self') ?? []
|
|
151
|
+
|
|
152
|
+
// Render return type
|
|
153
|
+
const returnType = renderExpression(fn.returns)
|
|
154
|
+
|
|
155
|
+
// Build parameter string with proper separators for positional-only and keyword-only
|
|
156
|
+
const buildParamString = (params: GriffeParameter[]): string => {
|
|
157
|
+
const parts: string[] = []
|
|
158
|
+
const hasVarPositional = params.some(p => p.kind === 'var-positional')
|
|
159
|
+
let addedBareAsterisk = false
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < params.length; i++) {
|
|
162
|
+
const param = params[i]
|
|
163
|
+
const nextParam = params[i + 1]
|
|
164
|
+
|
|
165
|
+
// Add the parameter itself
|
|
166
|
+
parts.push(renderParameter(param))
|
|
167
|
+
|
|
168
|
+
// Add / after last positional-only parameter
|
|
169
|
+
if (param.kind === 'positional-only' && nextParam && nextParam.kind !== 'positional-only') {
|
|
170
|
+
parts.push('/')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Add bare * before first keyword-only parameter (if no *args)
|
|
174
|
+
if (!hasVarPositional && !addedBareAsterisk && nextParam?.kind === 'keyword-only' && param.kind !== 'keyword-only') {
|
|
175
|
+
parts.push('*')
|
|
176
|
+
addedBareAsterisk = true
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return parts.join(', ')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Build the plain text signature for copying
|
|
184
|
+
const plainSignature = (() => {
|
|
185
|
+
const params = buildParamString(displayParams)
|
|
186
|
+
const prefix = isAsync ? 'async def ' : 'def '
|
|
187
|
+
return returnType
|
|
188
|
+
? `${prefix}${name}(${params}) -> ${returnType}`
|
|
189
|
+
: `${prefix}${name}(${params})`
|
|
190
|
+
})()
|
|
191
|
+
|
|
192
|
+
const handleCopy = async () => {
|
|
193
|
+
await navigator.clipboard.writeText(plainSignature)
|
|
194
|
+
setCopied(true)
|
|
195
|
+
setTimeout(() => setCopied(false), 2000)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Build list of parameter tokens (params + separators like / and *)
|
|
199
|
+
type ParamToken = { type: 'param'; param: GriffeParameter } | { type: 'separator'; value: '/' | '*' }
|
|
200
|
+
const buildParamTokens = (params: GriffeParameter[]): ParamToken[] => {
|
|
201
|
+
const tokens: ParamToken[] = []
|
|
202
|
+
const hasVarPositional = params.some(p => p.kind === 'var-positional')
|
|
203
|
+
let addedBareAsterisk = false
|
|
204
|
+
|
|
205
|
+
for (let i = 0; i < params.length; i++) {
|
|
206
|
+
const param = params[i]
|
|
207
|
+
const nextParam = params[i + 1]
|
|
208
|
+
|
|
209
|
+
tokens.push({ type: 'param', param })
|
|
210
|
+
|
|
211
|
+
// Add / after last positional-only parameter
|
|
212
|
+
if (param.kind === 'positional-only' && nextParam && nextParam.kind !== 'positional-only') {
|
|
213
|
+
tokens.push({ type: 'separator', value: '/' })
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Add bare * before first keyword-only parameter (if no *args)
|
|
217
|
+
if (!hasVarPositional && !addedBareAsterisk && nextParam?.kind === 'keyword-only' && param.kind !== 'keyword-only') {
|
|
218
|
+
tokens.push({ type: 'separator', value: '*' })
|
|
219
|
+
addedBareAsterisk = true
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return tokens
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const paramTokens = buildParamTokens(displayParams)
|
|
227
|
+
|
|
228
|
+
// Render a single parameter element
|
|
229
|
+
const renderParamElement = (param: GriffeParameter, multiline: boolean) => (
|
|
230
|
+
<>
|
|
231
|
+
{param.kind === 'var-positional' && <span className="text-gray-400">*</span>}
|
|
232
|
+
{param.kind === 'var-keyword' && <span className="text-gray-400">**</span>}
|
|
233
|
+
<span className="text-orange-300">{param.name}</span>
|
|
234
|
+
{param.annotation && (
|
|
235
|
+
<>
|
|
236
|
+
<span className="text-gray-400">: </span>
|
|
237
|
+
<span className="text-emerald-400">{renderExpression(param.annotation)}</span>
|
|
238
|
+
</>
|
|
239
|
+
)}
|
|
240
|
+
{param.default && (
|
|
241
|
+
<>
|
|
242
|
+
<span className="text-gray-400"> = </span>
|
|
243
|
+
<span className="text-blue-300">{renderExpression(param.default)}</span>
|
|
244
|
+
</>
|
|
245
|
+
)}
|
|
246
|
+
{multiline && <span className="text-gray-400">,</span>}
|
|
247
|
+
</>
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
// Determine if we need multi-line formatting
|
|
251
|
+
const needsMultiline = displayParams.length > 3
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<div className={`relative group ${className}`}>
|
|
255
|
+
{/* Dark code block like strawberry.rocks */}
|
|
256
|
+
<div className="font-mono text-sm bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
|
|
257
|
+
<code className="text-gray-100">
|
|
258
|
+
{isAsync && <span className="text-purple-400">async </span>}
|
|
259
|
+
<span className="text-blue-400">def</span>
|
|
260
|
+
{' '}
|
|
261
|
+
<span className="text-yellow-300">{name}</span>
|
|
262
|
+
<span className="text-gray-400">(</span>
|
|
263
|
+
{paramTokens.length > 0 && (
|
|
264
|
+
needsMultiline ? (
|
|
265
|
+
// Multi-line for many parameters
|
|
266
|
+
<>
|
|
267
|
+
{paramTokens.map((token, i) => (
|
|
268
|
+
token.type === 'param' ? (
|
|
269
|
+
<span key={token.param.name} className="block pl-4">
|
|
270
|
+
{renderParamElement(token.param, true)}
|
|
271
|
+
</span>
|
|
272
|
+
) : (
|
|
273
|
+
<span key={`sep-${i}`} className="block pl-4">
|
|
274
|
+
<span className="text-gray-400">{token.value},</span>
|
|
275
|
+
</span>
|
|
276
|
+
)
|
|
277
|
+
))}
|
|
278
|
+
</>
|
|
279
|
+
) : (
|
|
280
|
+
// Single line for few parameters
|
|
281
|
+
paramTokens.map((token, i) => (
|
|
282
|
+
token.type === 'param' ? (
|
|
283
|
+
<span key={token.param.name}>
|
|
284
|
+
{i > 0 && <span className="text-gray-400">, </span>}
|
|
285
|
+
{renderParamElement(token.param, false)}
|
|
286
|
+
</span>
|
|
287
|
+
) : (
|
|
288
|
+
<span key={`sep-${i}`}>
|
|
289
|
+
<span className="text-gray-400">, {token.value}</span>
|
|
290
|
+
</span>
|
|
291
|
+
)
|
|
292
|
+
))
|
|
293
|
+
)
|
|
294
|
+
)}
|
|
295
|
+
<span className="text-gray-400">)</span>
|
|
296
|
+
{returnType && (
|
|
297
|
+
<>
|
|
298
|
+
<span className="text-gray-400"> -> </span>
|
|
299
|
+
<span className="text-emerald-400">{returnType}</span>
|
|
300
|
+
</>
|
|
301
|
+
)}
|
|
302
|
+
<span className="text-gray-400">:</span>
|
|
303
|
+
<span className="block pl-2 text-gray-500">...</span>
|
|
304
|
+
</code>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
{/* Copy button */}
|
|
308
|
+
<button
|
|
309
|
+
onClick={handleCopy}
|
|
310
|
+
className="absolute top-3 right-3 p-1.5 rounded bg-gray-700 hover:bg-gray-600 opacity-0 group-hover:opacity-100 transition-opacity text-gray-300 hover:text-white"
|
|
311
|
+
title="Copy to clipboard"
|
|
312
|
+
>
|
|
313
|
+
{copied ? <CheckIcon /> : <CopyIcon />}
|
|
314
|
+
</button>
|
|
315
|
+
</div>
|
|
316
|
+
)
|
|
317
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Re-export the shared TableOfContents component
|
|
2
|
+
export { TableOfContents } from '../TableOfContents'
|
|
3
|
+
export type { TOCItem as TocItem } from '../../types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate TOC items from a class's members
|
|
7
|
+
* Filters out private members (except __init__) to match ClassDoc rendering
|
|
8
|
+
*/
|
|
9
|
+
export function generateClassToc(cls: {
|
|
10
|
+
name: string
|
|
11
|
+
members?: Record<string, { kind: string; name: string }>
|
|
12
|
+
}): { id: string; title: string; level: number }[] {
|
|
13
|
+
const items: { id: string; title: string; level: number }[] = []
|
|
14
|
+
|
|
15
|
+
// Add class name as top item
|
|
16
|
+
items.push({ id: cls.name, title: cls.name, level: 1 })
|
|
17
|
+
|
|
18
|
+
if (!cls.members) return items
|
|
19
|
+
|
|
20
|
+
const members = Object.values(cls.members)
|
|
21
|
+
|
|
22
|
+
// Filter methods: __init__ is special, skip other private/dunder methods
|
|
23
|
+
const methods = members.filter(m => m.kind === 'function')
|
|
24
|
+
const initMethod = methods.find(m => m.name === '__init__')
|
|
25
|
+
const publicMethods = methods
|
|
26
|
+
.filter(m => m.name !== '__init__' && !m.name.startsWith('_'))
|
|
27
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
28
|
+
|
|
29
|
+
// Filter attributes: skip private ones
|
|
30
|
+
const publicAttributes = members
|
|
31
|
+
.filter(m => m.kind === 'attribute' && !m.name.startsWith('_'))
|
|
32
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
33
|
+
|
|
34
|
+
// Add constructor section if exists
|
|
35
|
+
if (initMethod) {
|
|
36
|
+
items.push({ id: 'constructor', title: 'Constructor', level: 2 })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Add methods section header if there are public methods
|
|
40
|
+
if (publicMethods.length > 0) {
|
|
41
|
+
items.push({ id: 'methods', title: 'Methods', level: 2 })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Add attributes section header if there are public attributes
|
|
45
|
+
if (publicAttributes.length > 0) {
|
|
46
|
+
items.push({ id: 'attributes', title: 'Attributes', level: 2 })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return items
|
|
50
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Documentation Components
|
|
3
|
+
*
|
|
4
|
+
* Components for rendering Python API documentation generated by Griffe.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { APIPage } from './APIPage'
|
|
8
|
+
export { APILayout } from './APILayout'
|
|
9
|
+
export { ModuleDoc } from './ModuleDoc'
|
|
10
|
+
export { ClassDoc } from './ClassDoc'
|
|
11
|
+
export { FunctionDoc } from './FunctionDoc'
|
|
12
|
+
export { Signature } from './Signature'
|
|
13
|
+
export { Docstring } from './Docstring'
|
|
14
|
+
export { ParameterTable } from './ParameterTable'
|
|
15
|
+
export { CodeSpan } from './CodeSpan'
|
|
16
|
+
export { TableOfContents, generateClassToc, type TocItem } from './TableOfContents'
|
|
17
|
+
export { Breadcrumb, generateBreadcrumb } from './Breadcrumb'
|
package/src/components/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { CodeBlock, InlineCode } from './CodeBlock'
|
|
2
2
|
export { DocSetSelector } from './DocSetSelector'
|
|
3
|
-
export { DocsLayout } from './DocsLayout'
|
|
3
|
+
export { DocsLayout, MobileMenuButton } from './DocsLayout'
|
|
4
4
|
export { DocsPage } from './DocsPage'
|
|
5
5
|
export { EmojiConfetti } from './EmojiConfetti'
|
|
6
6
|
export { HomePage } from './HomePage'
|
|
@@ -9,3 +9,15 @@ export { Sidebar } from './Sidebar'
|
|
|
9
9
|
export { TableOfContents } from './TableOfContents'
|
|
10
10
|
export { ThemeProvider, useTheme, themeInitScript } from './ThemeProvider'
|
|
11
11
|
export { ThemeToggle } from './ThemeToggle'
|
|
12
|
+
|
|
13
|
+
// API Documentation Components
|
|
14
|
+
export {
|
|
15
|
+
APIPage,
|
|
16
|
+
APILayout,
|
|
17
|
+
ModuleDoc,
|
|
18
|
+
ClassDoc,
|
|
19
|
+
FunctionDoc,
|
|
20
|
+
Signature,
|
|
21
|
+
Docstring,
|
|
22
|
+
ParameterTable,
|
|
23
|
+
} from './api'
|
package/src/index.ts
CHANGED
|
@@ -8,12 +8,22 @@ export {
|
|
|
8
8
|
HomePage,
|
|
9
9
|
InlineCode,
|
|
10
10
|
Markdown,
|
|
11
|
+
MobileMenuButton,
|
|
11
12
|
Sidebar,
|
|
12
13
|
TableOfContents,
|
|
13
14
|
ThemeProvider,
|
|
14
15
|
ThemeToggle,
|
|
15
16
|
useTheme,
|
|
16
17
|
themeInitScript,
|
|
18
|
+
// API Documentation Components
|
|
19
|
+
APIPage,
|
|
20
|
+
APILayout,
|
|
21
|
+
ModuleDoc,
|
|
22
|
+
ClassDoc,
|
|
23
|
+
FunctionDoc,
|
|
24
|
+
Signature,
|
|
25
|
+
Docstring,
|
|
26
|
+
ParameterTable,
|
|
17
27
|
} from './components'
|
|
18
28
|
|
|
19
29
|
// HomePage sub-components (for compound component pattern)
|
|
@@ -47,6 +57,28 @@ export type {
|
|
|
47
57
|
SidebarProps,
|
|
48
58
|
TableOfContentsProps,
|
|
49
59
|
TOCItem,
|
|
60
|
+
// API Documentation Types
|
|
61
|
+
GriffeKind,
|
|
62
|
+
GriffeDocstringSectionKind,
|
|
63
|
+
GriffeExpression,
|
|
64
|
+
GriffeParameter,
|
|
65
|
+
GriffeDocstringElement,
|
|
66
|
+
GriffeDocstringSection,
|
|
67
|
+
GriffeDocstring,
|
|
68
|
+
GriffeDecorator,
|
|
69
|
+
GriffeObjectBase,
|
|
70
|
+
GriffeFunction,
|
|
71
|
+
GriffeAttribute,
|
|
72
|
+
GriffeClass,
|
|
73
|
+
GriffeModule,
|
|
74
|
+
GriffeMember,
|
|
75
|
+
APIPageProps,
|
|
76
|
+
ModuleDocProps,
|
|
77
|
+
ClassDocProps,
|
|
78
|
+
FunctionDocProps,
|
|
79
|
+
SignatureProps,
|
|
80
|
+
DocstringProps,
|
|
81
|
+
ParameterTableProps,
|
|
50
82
|
} from './types'
|
|
51
83
|
|
|
52
84
|
export type { Theme, ResolvedTheme } from './components/ThemeProvider'
|