500 lines
17 KiB
TypeScript
500 lines
17 KiB
TypeScript
import React, { useMemo } from 'react'
|
|
import { graphql } from 'gatsby'
|
|
import { ExtendedTlObject } from '../types'
|
|
import {
|
|
Description,
|
|
Page,
|
|
Section,
|
|
SectionWithList,
|
|
usePageStyles,
|
|
} from '../components/page'
|
|
import {
|
|
Breadcrumbs,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableRow,
|
|
} from '@material-ui/core'
|
|
import {
|
|
createStyles,
|
|
Link as MuiLink,
|
|
makeStyles,
|
|
Typography,
|
|
} from '@material-ui/core'
|
|
import { Link } from 'gatsby'
|
|
import { LinkToTl } from '../components/objects/link-to-tl'
|
|
import { TableOfContentsItem } from '../components/table-of-contents'
|
|
import { Helmet } from 'react-helmet'
|
|
|
|
interface GraphqlResult {
|
|
self: ExtendedTlObject
|
|
parent: ExtendedTlObject
|
|
children: { nodes: ExtendedTlObject[] }
|
|
usageMethods: { nodes: ExtendedTlObject[] }
|
|
usageTypes: { nodes: ExtendedTlObject[] }
|
|
}
|
|
|
|
const useStyles = makeStyles((theme) =>
|
|
createStyles({
|
|
description: {
|
|
marginBottom: theme.spacing(2),
|
|
fontSize: 16,
|
|
},
|
|
table: {
|
|
'& th, & td': {
|
|
fontSize: 15,
|
|
},
|
|
},
|
|
mono: {
|
|
fontFamily: 'Fira Mono, Consolas, monospace',
|
|
},
|
|
// theme ported from one dark
|
|
code: {
|
|
fontFamily: 'Fira Mono, Consolas, monospace',
|
|
background: '#282c34',
|
|
color: '#bbbbbb',
|
|
fontSize: 16,
|
|
borderRadius: 4,
|
|
overflowX: 'auto',
|
|
padding: 8,
|
|
},
|
|
keyword: {
|
|
fontStyle: 'italic',
|
|
color: '#c678dd',
|
|
},
|
|
identifier: {
|
|
color: '#e5c07b',
|
|
},
|
|
property: {
|
|
color: '#e06c75',
|
|
},
|
|
comment: {
|
|
color: '#5c6370',
|
|
},
|
|
string: {
|
|
color: '#98c379',
|
|
},
|
|
bold: {
|
|
fontWeight: 'bold',
|
|
},
|
|
})
|
|
)
|
|
|
|
function useToc(obj: ExtendedTlObject): TableOfContentsItem[] {
|
|
return useMemo(() => {
|
|
const ret = [{ id: 'title', title: obj.prefix + obj.name }]
|
|
|
|
if (obj.type !== 'union') {
|
|
ret.push({ id: 'parameters', title: 'Parameters' })
|
|
} else {
|
|
ret.push({ id: 'subtypes', title: 'Subtypes' })
|
|
ret.push({ id: 'usage', title: 'Usage' })
|
|
}
|
|
|
|
if (obj.type === 'method' && obj.throws) {
|
|
ret.push({ id: 'throws', title: 'Throws' })
|
|
}
|
|
|
|
ret.push({ id: 'typescript', title: 'TypeScript' })
|
|
|
|
return ret
|
|
}, [obj])
|
|
}
|
|
|
|
export default function TlObject({ data }: { data: GraphqlResult }) {
|
|
const pageClasses = usePageStyles()
|
|
const classes = useStyles()
|
|
|
|
const obj = data.self
|
|
const toc = useToc(obj)
|
|
|
|
const keyword = (s: string) =>
|
|
`<span class='${classes.keyword}'>${s}</span>`
|
|
const identifier = (s: string) =>
|
|
`<span class='${classes.identifier}'>${s}</span>`
|
|
const property = (s: string) =>
|
|
`<span class='${classes.property}'>${s}</span>`
|
|
const comment = (s: string) =>
|
|
`<span class='${classes.comment}'>${s}</span>`
|
|
const _string = (s: string) => `<span class='${classes.string}'>${s}</span>`
|
|
|
|
const typeName = (s: string): string => {
|
|
if (
|
|
s === 'string' ||
|
|
s === 'number' ||
|
|
s === 'boolean' ||
|
|
s === 'true'
|
|
) {
|
|
return keyword(s)
|
|
}
|
|
|
|
if (s.substr(s.length - 2) === '[]')
|
|
return typeName(s.substr(0, s.length - 2)) + '[]'
|
|
|
|
return s.split('.').map(identifier).join('.')
|
|
}
|
|
|
|
const code = (s: string) => {
|
|
return (
|
|
<pre
|
|
className={classes.code}
|
|
dangerouslySetInnerHTML={{ __html: s }}
|
|
/>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Page toc={toc}>
|
|
<Helmet>
|
|
<title>
|
|
{obj.prefix}
|
|
{obj.name}
|
|
</title>
|
|
<meta
|
|
name="description"
|
|
content={
|
|
obj.description ||
|
|
obj.prefix +
|
|
obj.name +
|
|
" currently doesn't have a description."
|
|
}
|
|
/>
|
|
</Helmet>
|
|
|
|
<div className={pageClasses.heading0}>
|
|
<Breadcrumbs>
|
|
<MuiLink
|
|
component={Link}
|
|
to={`/${obj.prefix}${
|
|
obj.type === 'method' ? 'methods' : 'types'
|
|
}`}
|
|
>
|
|
{obj.prefix}
|
|
{obj.type === 'method' ? 'Methods' : 'Types'}
|
|
</MuiLink>
|
|
{obj.namespace !== '$root' && (
|
|
<MuiLink
|
|
component={Link}
|
|
to={`/${obj.prefix}${
|
|
obj.type === 'method' ? 'methods' : 'types'
|
|
}/${obj.namespace}`}
|
|
>
|
|
{obj.prefix}
|
|
{obj.namespace}
|
|
</MuiLink>
|
|
)}
|
|
<Typography color="textPrimary">{obj.name}</Typography>
|
|
</Breadcrumbs>
|
|
<Typography variant="h3" id="title">
|
|
{obj.prefix}
|
|
{obj.name}
|
|
</Typography>
|
|
<Typography variant="body2">
|
|
{obj.type === 'class' ? (
|
|
<>
|
|
constructor ID 0x{obj.tlId} / belongs to union{' '}
|
|
{LinkToTl(data.parent)}
|
|
</>
|
|
) : obj.type === 'union' ? (
|
|
<>
|
|
has{' '}
|
|
<MuiLink href="#subtypes">
|
|
{data.children.nodes.length} sub-types
|
|
</MuiLink>{' '}
|
|
and{' '}
|
|
<MuiLink href="#usage">
|
|
{data.usageTypes.nodes.length +
|
|
data.usageMethods.nodes.length}{' '}
|
|
usages
|
|
</MuiLink>
|
|
</>
|
|
) : (
|
|
obj.returns && (
|
|
<>
|
|
constructor ID 0x{obj.tlId} / returns{' '}
|
|
{LinkToTl(obj.returns)}
|
|
{obj.available &&
|
|
' / available for ' +
|
|
(obj.available === 'both'
|
|
? 'both users and bots'
|
|
: obj.available + 's only')}
|
|
</>
|
|
)
|
|
)}
|
|
</Typography>
|
|
</div>
|
|
<Description
|
|
description={obj.description}
|
|
className={classes.description}
|
|
/>
|
|
{obj.type !== 'union' && (
|
|
<Section id="parameters" title="Parameters">
|
|
<Table className={classes.table}>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell>Name</TableCell>
|
|
<TableCell>Type</TableCell>
|
|
<TableCell>Description</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{obj.arguments.map((arg) => (
|
|
<TableRow key={arg.name}>
|
|
<TableCell>
|
|
<code
|
|
className={
|
|
!arg.optional &&
|
|
arg.type !== '$FlagsBitField'
|
|
? classes.bold
|
|
: undefined
|
|
}
|
|
>
|
|
{arg.name}
|
|
</code>
|
|
</TableCell>
|
|
<TableCell className={classes.mono}>
|
|
{LinkToTl(arg.type)}
|
|
{arg.optional ? '?' : ''}
|
|
</TableCell>
|
|
<Description
|
|
description={arg.description}
|
|
component={TableCell}
|
|
/>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</Section>
|
|
)}
|
|
{obj.type === 'union' && (
|
|
<>
|
|
<SectionWithList
|
|
id="subtypes"
|
|
title="Subtypes"
|
|
nodes={data.children.nodes}
|
|
>
|
|
{obj.prefix}
|
|
{obj.name} can be represented with{' '}
|
|
{obj.subtypes.length > 1
|
|
? `one of ${obj.subtypes.length} classes`
|
|
: 'only one class'}
|
|
:
|
|
</SectionWithList>
|
|
|
|
<Section id="usage" title="Usage">
|
|
{data.usageMethods.nodes.length > 0 && (
|
|
<SectionWithList nodes={data.usageMethods.nodes}>
|
|
{obj.prefix}
|
|
{obj.name} is returned by{' '}
|
|
{data.usageMethods.nodes.length > 1
|
|
? `${data.usageMethods.nodes.length} methods`
|
|
: 'only one method'}
|
|
:
|
|
</SectionWithList>
|
|
)}
|
|
|
|
{data.usageTypes.nodes.length > 0 && (
|
|
<SectionWithList nodes={data.usageTypes.nodes}>
|
|
{obj.prefix}
|
|
{obj.name} is used in{' '}
|
|
{data.usageTypes.nodes.length > 1
|
|
? `${data.usageTypes.nodes.length} types`
|
|
: 'only one type'}
|
|
:
|
|
</SectionWithList>
|
|
)}
|
|
|
|
{data.usageMethods.nodes.length === 0 &&
|
|
data.usageTypes.nodes.length === 0 && (
|
|
<Typography color="textSecondary">
|
|
This union is never used :(
|
|
</Typography>
|
|
)}
|
|
</Section>
|
|
</>
|
|
)}
|
|
{obj.throws && (
|
|
<Section id="throws" title="Throws">
|
|
<Table className={classes.table}>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell>Code</TableCell>
|
|
<TableCell>Name</TableCell>
|
|
<TableCell>Description</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{obj.throws.map((err) => (
|
|
<TableRow key={err.name}>
|
|
<TableCell>
|
|
<code>{err.code}</code>
|
|
</TableCell>
|
|
<TableCell>
|
|
<code>{err.name}</code>
|
|
</TableCell>
|
|
<Description
|
|
description={err.description}
|
|
component={TableCell}
|
|
/>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</Section>
|
|
)}
|
|
<Typography
|
|
variant="h4"
|
|
id="typescript"
|
|
className={pageClasses.heading}
|
|
>
|
|
TypeScript declaration
|
|
</Typography>
|
|
|
|
{/* this is a mess, but who cares */}
|
|
{code(
|
|
obj.type === 'union'
|
|
? `${keyword('export type')} ${identifier(obj.ts)} =` +
|
|
data.children.nodes
|
|
.map(
|
|
(it) =>
|
|
`\n | ${typeName(
|
|
'tl.' +
|
|
(it.namespace === '$root'
|
|
? it.prefix === 'mtproto/'
|
|
? 'mtproto.'
|
|
: ''
|
|
: it.namespace + '.') +
|
|
it.ts
|
|
)}`
|
|
)
|
|
.join('')
|
|
: `${keyword('export interface')} ${identifier(obj.ts)} {` +
|
|
`\n ${property('_')}: ${_string(
|
|
`'${obj.prefix === 'mtproto/' ? 'mt_' : ''}${
|
|
obj.name
|
|
}'`
|
|
)}` +
|
|
obj.arguments
|
|
.map((arg) =>
|
|
arg.type === '$FlagsBitField'
|
|
? comment(
|
|
'\n // ' +
|
|
arg.name +
|
|
': TlFlags // handled automatically'
|
|
)
|
|
: `\n ${property(arg.name)}${
|
|
arg.optional ? '?' : ''
|
|
}: ${typeName(arg.ts)}${
|
|
arg.predicate
|
|
? ' ' +
|
|
comment(
|
|
'// present if ' +
|
|
arg.predicate
|
|
)
|
|
: ''
|
|
}`
|
|
)
|
|
.join('') +
|
|
'\n}'
|
|
)}
|
|
</Page>
|
|
)
|
|
}
|
|
|
|
export const query = graphql`
|
|
query(
|
|
$prefix: String!
|
|
$type: String!
|
|
$name: String!
|
|
$hasSubtypes: Boolean!
|
|
$subtypes: [String]
|
|
) {
|
|
self: tlObject(
|
|
prefix: { eq: $prefix }
|
|
type: { eq: $type }
|
|
name: { eq: $name }
|
|
) {
|
|
tlId
|
|
ts
|
|
prefix
|
|
type
|
|
name
|
|
description
|
|
namespace
|
|
returns
|
|
available
|
|
arguments {
|
|
name
|
|
ts
|
|
type
|
|
description
|
|
optional
|
|
predicate
|
|
}
|
|
subtypes
|
|
throws {
|
|
code
|
|
description
|
|
name
|
|
}
|
|
}
|
|
parent: tlObject(
|
|
prefix: { eq: $prefix }
|
|
type: { eq: "union" }
|
|
subtypes: { eq: $name }
|
|
) {
|
|
prefix
|
|
name
|
|
type
|
|
description
|
|
subtypes
|
|
}
|
|
children: allTlObject(
|
|
filter: {
|
|
prefix: { eq: $prefix }
|
|
type: { eq: "class" }
|
|
name: { in: $subtypes }
|
|
}
|
|
) @include(if: $hasSubtypes) {
|
|
nodes {
|
|
ts
|
|
id
|
|
namespace
|
|
prefix
|
|
name
|
|
type
|
|
description
|
|
}
|
|
}
|
|
usageMethods: allTlObject(
|
|
filter: {
|
|
prefix: { eq: $prefix }
|
|
type: { eq: "method" }
|
|
rawReturns: { eq: $name }
|
|
}
|
|
) @include(if: $hasSubtypes) {
|
|
nodes {
|
|
id
|
|
prefix
|
|
type
|
|
name
|
|
description
|
|
}
|
|
}
|
|
usageTypes: allTlObject(
|
|
filter: {
|
|
prefix: { eq: $prefix }
|
|
arguments: { elemMatch: { rawType: { eq: $name } } }
|
|
}
|
|
) {
|
|
nodes {
|
|
id
|
|
prefix
|
|
type
|
|
name
|
|
description
|
|
}
|
|
}
|
|
}
|
|
`
|