1
0
mirror of synced 2026-01-31 00:01:42 -05:00

Merge pull request #19510 from github/repo-sync

repo sync
This commit is contained in:
Octomerger Bot
2022-08-03 14:27:40 -04:00
committed by GitHub
79 changed files with 5514 additions and 47987 deletions

View File

@@ -87,7 +87,6 @@ ENV BUILD_SHA=$BUILD_SHA
# Copy only what's needed to run the server
COPY --chown=node:node package.json ./
COPY --chown=node:node assets ./assets
COPY --chown=node:node includes ./includes
COPY --chown=node:node content ./content
COPY --chown=node:node lib ./lib
COPY --chown=node:node middleware ./middleware

View File

@@ -0,0 +1,58 @@
import React from 'react'
import GithubSlugger from 'github-slugger'
import cx from 'classnames'
import { LinkIcon } from '@primer/octicons-react'
import { BreakingChangesT } from 'components/graphql/types'
import styles from 'components/ui/MarkdownContent/MarkdownContent.module.scss'
type Props = {
schema: BreakingChangesT
}
const slugger = new GithubSlugger()
export function BreakingChanges({ schema }: Props) {
const changes = Object.keys(schema).map((date) => {
const items = schema[date]
const heading = `Changes scheduled for ${date}`
const slug = slugger.slug(heading)
return (
<div className={cx(styles.markdownBody, styles.automatedPages)} key={date}>
<h2 id={slug}>
<a className="doctocat-link" href={`#${slug}`}>
<LinkIcon className="octicon-link" size="small" />
</a>
{heading}
</h2>
{items.map((item) => {
const criticalityStyles =
item.criticality === 'breaking'
? 'color-border-danger color-bg-danger'
: 'color-border-accent-emphasis color-bg-accent'
const criticality = item.criticality === 'breaking' ? 'Breaking' : 'Dangerous'
return (
<ul key={item.location}>
<li>
<span className={cx(criticalityStyles, 'border rounded-1 m-1 p-1')}>
{criticality}
</span>{' '}
A change will be made to <code>{item.location}</code>.
<p>
<b>Description: </b>
<span dangerouslySetInnerHTML={{ __html: item.description }} />
</p>
<p>
<b>Reason: </b> <span dangerouslySetInnerHTML={{ __html: item.reason }} />
</p>
</li>
</ul>
)
})}
</div>
)
})
return <div>{changes}</div>
}

View File

@@ -0,0 +1,69 @@
import React from 'react'
import GithubSlugger from 'github-slugger'
import cx from 'classnames'
import { LinkIcon } from '@primer/octicons-react'
import { ChangelogItemT } from 'components/graphql/types'
import styles from 'components/ui/MarkdownContent/MarkdownContent.module.scss'
type Props = {
changelogItems: ChangelogItemT[]
}
export function Changelog({ changelogItems }: Props) {
const changes = changelogItems.map((item) => {
const heading = `Schema changes for ${item.date}`
const slugger = new GithubSlugger()
const slug = slugger.slug(heading)
return (
<div className={cx(styles.markdownBody, styles.automatedPages)} key={item.date}>
<h2 id={slug}>
<a className="doctocat-link" href={`#${slug}`}>
<LinkIcon className="octicon-link" size="small" />
</a>
{heading}
</h2>
{item.schemaChanges &&
item.schemaChanges.map((change, index) => (
<React.Fragment key={`${item.date}-schema-changes-${index}`}>
<p>{change.title}</p>
<ul>
{change.changes.map((change) => (
<li key={`${item.date}-${change}`}>
<span dangerouslySetInnerHTML={{ __html: change }} />
</li>
))}
</ul>
</React.Fragment>
))}
{item.previewChanges &&
item.previewChanges.map((change, index) => (
<React.Fragment key={`${item.date}-preview-changes-${index}`}>
<p>{change.title}</p>
<ul>
{change.changes.map((change) => (
<li key={`${item.date}-${change}`}>
<span dangerouslySetInnerHTML={{ __html: change }} />
</li>
))}
</ul>
</React.Fragment>
))}
{item.upcomingChanges &&
item.upcomingChanges.map((change, index) => (
<React.Fragment key={`${item.date}-upcoming-changes-${index}`}>
<p>{change.title}</p>
{change.changes.map((change) => (
<li key={`${item.date}-${change}`}>
<span dangerouslySetInnerHTML={{ __html: change }} />
</li>
))}
</React.Fragment>
))}
</div>
)
})
return <div>{changes}</div>
}

View File

@@ -0,0 +1,31 @@
import React from 'react'
import { useTranslation } from 'components/hooks/useTranslation'
import { GraphqlItem } from './GraphqlItem'
import type { EnumT } from './types'
type Props = {
item: EnumT
}
export function Enum({ item }: Props) {
const { t } = useTranslation('products')
const heading = t('graphql.reference.values')
return (
<GraphqlItem item={item} heading={heading}>
{item.values.map((value) => (
<React.Fragment key={`${value.name}-${value.description}`}>
<p>
<strong>{value.name}</strong>
</p>
<div
dangerouslySetInnerHTML={{
__html: value.description,
}}
/>
</React.Fragment>
))}
</GraphqlItem>
)
}

View File

@@ -0,0 +1,48 @@
import { LinkIcon } from '@primer/octicons-react'
import type { GraphqlT } from './types'
import { Notice } from './Notice'
type Props = {
item: GraphqlT
heading?: string
headingLevel?: number
children?: React.ReactNode
}
export function GraphqlItem({ item, heading, children, headingLevel = 2 }: Props) {
const lowerCaseName = item.name.toLowerCase()
return (
<>
{headingLevel === 2 && (
<h2 id={lowerCaseName}>
<a className="doctocat-link" href={`#${lowerCaseName}`}>
<LinkIcon className="octicon-link" size="small" />
</a>
{item.name}
</h2>
)}
{headingLevel === 3 && (
<h3 id={lowerCaseName}>
<a className="doctocat-link" href={`#${lowerCaseName}`}>
<LinkIcon className="octicon-link" size="small" />
</a>
{item.name}
</h3>
)}
<p
dangerouslySetInnerHTML={{
__html: item.description,
}}
/>
<div>
{item.preview && <Notice item={item} variant="preview" />}
{item.isDeprecated && <Notice item={item} variant="deprecation" />}
</div>
<div>
{heading && <h4>{heading}</h4>}
{children}
</div>
</>
)
}

View File

@@ -0,0 +1,108 @@
import React from 'react'
import cx from 'classnames'
import { LinkIcon } from '@primer/octicons-react'
import { Enum } from 'components/graphql/Enum'
import { InputObject } from 'components/graphql/InputObject'
import { Interface } from 'components/graphql/Interface'
import { Scalar } from 'components/graphql/Scalar'
import { Mutation } from 'components/graphql/Mutation'
import { Object } from 'components/graphql/Object'
import { Query } from 'components/graphql/Query'
import { Union } from 'components/graphql/Union'
import type {
EnumT,
InputObjectT,
InterfaceT,
MutationT,
ObjectT,
QueryT,
ScalarT,
UnionT,
} from 'components/graphql/types'
import styles from 'components/ui/MarkdownContent/MarkdownContent.module.scss'
type Props = {
schema: Object
pageName: string
objects?: ObjectT[]
}
export const GraphqlPage = ({ schema, pageName, objects }: Props) => {
const graphqlItems: JSX.Element[] = [] // In the case of the H2s for Queries
// The queries page has two heading sections (connections and fields)
// So we need to add the heading component and the children under it
// for each section.
if (pageName === 'queries') {
graphqlItems.push(
<h2 id="connections" key="query-connections-heading">
<a className="doctocat-link" href="#connections">
<LinkIcon className="octicon-link" size="small" />
</a>
Connections
</h2>
)
graphqlItems.push(
...(schema as QueryT).connections.map((item) => (
<Query item={item} key={item.id + item.name} />
))
)
graphqlItems.push(
<h2 id="fields" key="query-fields-heading">
<a className="doctocat-link" href="#fields">
<LinkIcon className="octicon-link" size="small" />
</a>
Fields
</h2>
)
graphqlItems.push(
...(schema as QueryT).fields.map((item) => <Query item={item} key={item.id + item.name} />)
)
} else if (pageName === 'enums') {
graphqlItems.push(
...(schema as EnumT[]).map((item) => {
return <Enum key={item.id} item={item} />
})
)
} else if (pageName === 'inputObjects') {
graphqlItems.push(
...(schema as InputObjectT[]).map((item) => {
return <InputObject key={item.id} item={item} />
})
)
} else if (pageName === 'interfaces' && objects) {
graphqlItems.push(
...(schema as InterfaceT[]).map((item) => {
return <Interface key={item.id} item={item} objects={objects} />
})
)
} else if (pageName === 'mutations') {
graphqlItems.push(
...(schema as MutationT[]).map((item) => {
return <Mutation key={item.id} item={item} />
})
)
} else if (pageName === 'objects') {
graphqlItems.push(
...(schema as ObjectT[]).map((item) => {
return <Object key={item.id} item={item} />
})
)
} else if (pageName === 'scalars') {
graphqlItems.push(
...(schema as ScalarT[]).map((item) => {
return <Scalar key={item.id} item={item} />
})
)
} else if (pageName === 'unions') {
graphqlItems.push(
...(schema as UnionT[]).map((item) => {
return <Union key={item.id} item={item} />
})
)
}
return <div className={cx(styles.automatedPages, styles.markdownBody)}>{graphqlItems}</div>
}

View File

@@ -0,0 +1,18 @@
import { GraphqlItem } from './GraphqlItem'
import { Table } from './Table'
import { useTranslation } from 'components/hooks/useTranslation'
import type { InputObjectT } from './types'
type Props = {
item: InputObjectT
}
export function InputObject({ item }: Props) {
const { t } = useTranslation('products')
const heading = t('graphql.reference.input_fields')
return (
<GraphqlItem item={item} heading={heading}>
<Table fields={item.inputFields} />
</GraphqlItem>
)
}

View File

@@ -0,0 +1,47 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { GraphqlItem } from './GraphqlItem'
import { Table } from './Table'
import { useTranslation } from 'components/hooks/useTranslation'
import type { ObjectT, InterfaceT } from './types'
type Props = {
item: InterfaceT
objects: ObjectT[]
}
export function Interface({ item, objects }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
const heading = t('graphql.reference.implemented_by')
const heading2 = t('graphql.reference.fields')
const implementedBy = objects.filter(
(object) =>
object.implements &&
object.implements.some((implementsItem) => implementsItem.name === item.name)
)
return (
<GraphqlItem item={item} heading={heading}>
<ul>
{implementedBy.map((object) => (
<li key={`${item.id}-${item.name}-${object.href}-${object.name}`}>
<code>
<Link href={object.href} locale={locale}>
{object.name}
</Link>
</code>
</li>
))}
</ul>
{item.fields && (
<>
<h4>{heading2}</h4>
<Table fields={item.fields} />
</>
)}
</GraphqlItem>
)
}

View File

@@ -0,0 +1,45 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { GraphqlItem } from './GraphqlItem'
import { Notice } from './Notice'
import { useTranslation } from 'components/hooks/useTranslation'
import { Table } from './Table'
import type { MutationT } from './types'
import React from 'react'
type Props = {
item: MutationT
}
export function Mutation({ item }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
const heading = t('graphql.reference.input_fields')
const heading2 = t('graphql.reference.return_fields')
return (
<GraphqlItem item={item} heading={heading}>
{item.inputFields.map((input) => (
<React.Fragment key={input.id}>
<ul>
<li>
<code>{input.name}</code> (
<code>
<Link href={input.href} locale={locale}>
{input.type}
</Link>
</code>
)
</li>
</ul>
{input.preview && <Notice item={input} variant="preview" />}
{input.isDeprecated && <Notice item={input} variant="deprecation" />}
<h4>{heading2}</h4>
<Table fields={item.returnFields} />
</React.Fragment>
))}
</GraphqlItem>
)
}

View File

@@ -0,0 +1,51 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { useTranslation } from 'components/hooks/useTranslation'
import type { GraphqlT } from './types'
type Props = {
item: GraphqlT
variant: 'preview' | 'deprecation'
}
export function Notice({ item, variant = 'preview' }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
const previewTitle =
variant === 'preview'
? t('rest.reference.preview_notice')
: t('graphql.reference.deprecation_notice')
const noticeStyle =
variant === 'preview'
? 'note color-border-accent-emphasis color-bg-accent'
: 'warning color-border-danger color-bg-danger'
return (
<div className={`${noticeStyle} extended-markdown border rounded-1 my-3 p-3 f5`}>
<p>
<b>{previewTitle}</b>
</p>
{variant === 'preview' && item.preview ? (
<p>
<code>{item.name}</code> is available under the{' '}
<Link href={item.preview.href} locale={locale}>
{item.preview.title}
</Link>
. {t('graphql.reference.preview_period')}
</p>
) : item.deprecationReason ? (
<div>
<p>
<code>{item.name}</code> is deprecated.
</p>
<div
dangerouslySetInnerHTML={{
__html: item.deprecationReason,
}}
/>
</div>
) : null}
</div>
)
}

View File

@@ -0,0 +1,46 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { GraphqlItem } from './GraphqlItem'
import { Table } from './Table'
import { useTranslation } from 'components/hooks/useTranslation'
import type { ObjectT, ImplementsT } from './types'
type Props = {
item: ObjectT
}
export function Object({ item }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
const heading1 = t('graphql.reference.implements')
const heading2 = t('graphql.reference.fields')
return (
<GraphqlItem item={item}>
{item.implements && (
<>
<h3>{heading1}</h3>
<ul>
{item.implements.map((implement: ImplementsT) => (
<li key={`${implement.id}-${implement.href}-${implement.name}`}>
<code>
<Link href={implement.href} locale={locale}>
{implement.name}
</Link>
</code>
</li>
))}
</ul>
</>
)}
{item.fields && (
<>
<h3>{heading2}</h3>
<Table fields={item.fields} />
</>
)}
</GraphqlItem>
)
}

View File

@@ -0,0 +1,58 @@
import React from 'react'
import GithubSlugger from 'github-slugger'
import cx from 'classnames'
import { LinkIcon } from '@primer/octicons-react'
import { useTranslation } from 'components/hooks/useTranslation'
import { PreviewT } from 'components/graphql/types'
import styles from 'components/ui/MarkdownContent/MarkdownContent.module.scss'
type Props = {
schema: PreviewT[]
}
export function Previews({ schema }: Props) {
const previews = schema.map((item) => {
const slugger = new GithubSlugger()
const slug = slugger.slug(item.title)
const { t } = useTranslation('products')
return (
<div className={cx(styles.markdownBody, styles.automatedPages)} key={slug}>
<h2 id={slug}>
<a className="doctocat-link" href={`#${slug}`}>
<LinkIcon className="octicon-link" size="small" />
</a>
{item.title}
</h2>
<p>{item.description}</p>
<p>{t('graphql.overview.preview_header')}</p>
<pre>
<code>{item.accept_header}</code>
</pre>
<p>{t('graphql.overview.preview_schema_members')}:</p>
<ul>
{item.toggled_on.map((change) => (
<li key={change + slug}>
<code>{change}</code>
</li>
))}
</ul>
{item.announcement && (
<p>
<b>{t('graphql.overview.announced')}: </b>
<a href={item.announcement.url}>{item.announcement.date}</a>
</p>
)}
{item.updates && (
<p>
<b>{t('graphql.overview.updates')}: </b>
<a href={item.updates.url}>{item.updates.date}</a>
</p>
)}
</div>
)
})
return <div>{previews}</div>
}

View File

@@ -0,0 +1,38 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { GraphqlItem } from './GraphqlItem'
import { Table } from './Table'
import { useTranslation } from 'components/hooks/useTranslation'
import type { QueryItemT } from './types'
type Props = {
item: QueryItemT
}
export function Query({ item }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
return (
<GraphqlItem item={item} headingLevel={3}>
<div>
<p>
<b>{t('graphql.reference.type')}: </b>
<Link href={item.href} locale={locale}>
{item.type}
</Link>
</p>
</div>
<div>
{item.args.length > 0 && (
<>
<h4>{t('graphql.reference.arguments')}</h4>
<Table fields={item.args} />
</>
)}
</div>
</GraphqlItem>
)
}

View File

@@ -0,0 +1,10 @@
import { GraphqlItem } from './GraphqlItem'
import { ScalarT } from './types'
type Props = {
item: ScalarT
}
export function Scalar({ item }: Props) {
return <GraphqlItem item={item} />
}

View File

@@ -0,0 +1,100 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { Notice } from './Notice'
import { useTranslation } from 'components/hooks/useTranslation'
import { FieldT } from './types'
type Props = {
fields: FieldT[]
}
export function Table({ fields }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
const tableName = t('graphql.reference.name')
const tableDescription = t('graphql.reference.description')
return (
<table className="fields width-full">
<thead>
<tr>
<th>{tableName}</th>
<th>{tableDescription}</th>
</tr>
</thead>
<tbody>
{fields.map((field) => (
<tr key={field.name}>
<td>
<p>
<code>{field.name}</code> (
<code>
<Link href={field.href} locale={locale}>
{field.type}
</Link>
</code>
)
</p>
</td>
<td>
{field.description ? (
<span
dangerouslySetInnerHTML={{
__html: field.description,
}}
/>
) : (
'N/A'
)}
{field.defaultValue !== undefined && (
<p>
The default value is <code>{field.defaultValue.toString()}</code>.
</p>
)}
{field.preview && <Notice item={field} variant="preview" />}
{field.isDeprecated && <Notice item={field} variant="deprecation" />}
{field.arguments && (
<div className="border rounded-1 mt-3 mb-3 p-3 color-bg-subtle f5">
<h4 className="pt-0 mt-0">{t('graphql.reference.arguments')}</h4>
{field.arguments.map((argument, index) => (
<ul
key={`${index}-${argument.type.name}-${argument.type.href}`}
className="list-style-none pl-0"
>
<li className="border-top mt-2">
<p className="mt-2">
<code>{argument.name}</code> (
<code>
<Link href={argument.type.href} locale={locale}>
{argument.type.name}
</Link>
</code>
)
</p>
{
<span
dangerouslySetInnerHTML={{
__html: argument.description,
}}
/>
}
{argument.defaultValue !== undefined && (
<p>
The default value is <code>{argument.defaultValue.toString()}</code>.
</p>
)}
</li>
</ul>
))}
</div>
)}
</td>
</tr>
))}
</tbody>
</table>
)
}

View File

@@ -0,0 +1,30 @@
import { useRouter } from 'next/router'
import { Link } from 'components/Link'
import { GraphqlItem } from './GraphqlItem'
import { useTranslation } from 'components/hooks/useTranslation'
import type { UnionT } from './types'
type Props = {
item: UnionT
}
export function Union({ item }: Props) {
const { locale } = useRouter()
const { t } = useTranslation('products')
const heading = t('graphql.reference.possible_types')
return (
<GraphqlItem item={item} heading={heading}>
<ul>
{item.possibleTypes.map((type) => (
<li key={type.id}>
<Link href={type.href} locale={locale}>
{type.name}
</Link>
</li>
))}
</ul>
</GraphqlItem>
)
}

View File

@@ -0,0 +1,137 @@
export type PreviewT = {
title: string
description: string
toggled_by: string
toggled_on: []
owning_teams: []
accept_header: string
href: string
announcement: {
date: string
url: string
}
updates: {
date: string
url: string
}
}
export type UpcomingChangesT = {
location: string
description: string
reason: string
date: string
criticality: 'breaking' | 'dangerous'
owner: string
}
export type GraphqlT = {
name: string
kind: string
id: string
href: string
description: string
type?: string
size?: number
isDeprecated?: boolean
deprecationReason?: string
preview?: PreviewT
defaultValue?: boolean
}
export type ImplementsT = {
name: string
id: string
href: string
}
export type ArgumentT = {
name: string
description: string
defaultValue?: string | boolean
type: {
name: string
id: string
kind: string
href: string
}
}
export type FieldT = GraphqlT & {
arguments?: ArgumentT[]
}
export type QueryItemT = GraphqlT & {
args: GraphqlT[]
}
export type QueryT = { connections: QueryItemT[]; fields: QueryItemT[] }
export type MutationT = GraphqlT & {
inputFields: FieldT[]
returnFields: FieldT[]
}
export type ObjectT = GraphqlT & {
fields: FieldT[]
implements?: ImplementsT[]
}
export type InterfaceT = GraphqlT & {
fields: FieldT[]
}
export type EnumValuesT = {
name: string
description: string
}
export type EnumT = GraphqlT & {
values: EnumValuesT[]
}
export type UnionT = GraphqlT & {
possibleTypes: ImplementsT[]
}
export type InputFieldsT = GraphqlT & {
type: string
}
export type InputObjectT = GraphqlT & {
inputFields: FieldT[]
}
export type ScalarT = GraphqlT & {
kind?: string
}
export type AllVersionsT = {
[versions: string]: {
miscVersionName: string
}
}
type ChangeT = {
title: string
changes: string[]
}
export type ChangelogItemT = {
date: string
schemaChanges: ChangeT[]
previewChanges: ChangeT[]
upcomingChanges: ChangeT[]
}
export type BreakingChangeT = {
location: string
description: string
reason: string
date: string
criticality: string
}
export type BreakingChangesT = {
[date: string]: BreakingChangeT[]
}

View File

@@ -72,3 +72,14 @@
}
}
}
.automatedPages {
h2,
h3,
h4 {
a {
text-decoration: none;
color: var(--color-fg-default);
}
}
}

View File

@@ -1,13 +1,13 @@
---
title: Breaking changes
intro: 'Learn about recent and upcoming breaking changes to the {% data variables.product.prodname_dotcom %} GraphQL API.'
intro: "Learn about recent and upcoming breaking changes to the {% data variables.product.prodname_dotcom %} GraphQL API."
redirect_from:
- /v4/breaking_changes
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -16,25 +16,9 @@ topics:
Breaking changes are any changes that might require action from our integrators. We divide these changes into two categories:
- **Breaking:** Changes that will break existing queries to the GraphQL API. For example, removing a field would be a breaking change.
- **Dangerous:** Changes that won't break existing queries but could affect the runtime behavior of clients. Adding an enum value is an example of a dangerous change.
- **Breaking:** Changes that will break existing queries to the GraphQL API. For example, removing a field would be a breaking change.
- **Dangerous:** Changes that won't break existing queries but could affect the runtime behavior of clients. Adding an enum value is an example of a dangerous change.
We strive to provide stable APIs for our integrators. When a new feature is still evolving, we release it behind a [schema preview](/graphql/overview/schema-previews).
We'll announce upcoming breaking changes at least three months before making changes to the GraphQL schema, to give integrators time to make the necessary adjustments. Changes go into effect on the first day of a quarter (January 1st, April 1st, July 1st, or October 1st). For example, if we announce a change on January 15th, it will be made on July 1st.
{% for date in graphql.upcomingChangesForCurrentVersion %}
## Changes scheduled for {{ date[0] }}
{% for change in date[1] %}
<ul>
<li><span class="border rounded-1 m-1 p-1 {% if change.criticality == 'breaking' %}color-border-danger color-bg-danger{% else %}color-border-accent-emphasis color-bg-accent{% endif %}">{% if change.criticality == 'breaking' %}Breaking{% else %}Dangerous{% endif %}</span> A change will be made to <code>{{ change.location }}</code>.
<p><b>Description:</b> {{ change.description }}</p>
<p><b>Reason:</b> {{ change.reason }}</p>
</li>
</ul>
{% endfor %}
{% endfor %}

View File

@@ -1,44 +1,15 @@
---
title: Changelog
intro: 'The GraphQL schema changelog is a list of recent and upcoming changes to our GraphQL API schema. It includes backwards-compatible changes, schema previews, and upcoming breaking changes.'
intro: "The GraphQL schema changelog is a list of recent and upcoming changes to our GraphQL API schema. It includes backwards-compatible changes, schema previews, and upcoming breaking changes."
redirect_from:
- /v4/changelog
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
Breaking changes include changes that will break existing queries or could affect the runtime behavior of clients. For a list of breaking changes and when they will occur, see our [breaking changes log](/graphql/overview/breaking-changes).
{% for entry in graphql.changelog %}
## Schema Changes for {{ entry.date }}
{% for schemaChange in entry.schemaChanges %}
{{ schemaChange.title }}
{% for change in schemaChange.changes %}
* {{ change }}
{% endfor %}
{% endfor %}
{% for previewChange in entry.previewChanges %}
{{ previewChange.title }}
{% for change in previewChange.changes %}
* {{ change }}
{% endfor %}
{% endfor %}
{% for upcomingChange in entry.upcomingChanges %}
{{ upcomingChange.title }}
{% for change in upcomingChange.changes %}
* {{ change }}
{% endfor %}
{% endfor %}
{% endfor %}

View File

@@ -1,13 +1,13 @@
---
title: Schema previews
intro: 'You can preview upcoming features and changes to the {% data variables.product.prodname_dotcom %} GraphQL schema before they are added to the {% data variables.product.prodname_dotcom %} GraphQL API.'
intro: "You can preview upcoming features and changes to the {% data variables.product.prodname_dotcom %} GraphQL schema before they are added to the {% data variables.product.prodname_dotcom %} GraphQL API."
redirect_from:
- /v4/previews
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -23,32 +23,3 @@ To access a schema preview, you'll need to provide a custom [media type](/rest/o
**Note:** The GraphQL schema members under preview cannot be accessed via the Explorer at this time.
{% endnote %}
{% for preview in graphql.previewsForCurrentVersion %}
## {{ preview.title }}
{{ preview.description }}
To toggle this preview and access the following schema members, you must provide a custom media type in the `Accept` header:
```
{{ preview.accept_header }}
```
Previewed schema members:
{% for schemaMemberPath in preview.toggled_on %}
- `{{ schemaMemberPath }}`
{% endfor %}
{% if preview.announcement %}
**Announced:** [{{ preview.announcement.date }}]({{ preview.announcement.url }})
{% endif %}
{% if preview.updates %}
{% for update in preview.updates %}
**Updated:** [{{ update.date }}]({{ update.url }})
{% endfor %}
{% endif %}
{% endfor %}

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/enum
- /v4/reference/enum
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -20,6 +20,4 @@ For example, the [`Issue`](/graphql/reference/objects#issue) object has a field
For more information, see "[Introduction to GraphQL](/graphql/guides/introduction-to-graphql)."
{% for item in graphql.schemaForCurrentVersion.enums %}
{% include graphql-enum %}
{% endfor %}
<!-- Content after this section is automatically generated -->

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/input_object
- /v4/reference/input_object
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -20,5 +20,4 @@ For example, [`CommitAuthor`](/graphql/reference/input-objects#commitauthor) tak
For more information, see "[About mutations](/graphql/guides/forming-calls-with-graphql#about-mutations)."
<!-- this page is pre-rendered by scripts because it's too big to load dynamically -->
<!-- see lib/graphql/static/prerendered-input-objects.json -->
<!-- Content after this section is automatically generated -->

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/interface
- /v4/reference/interface
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -20,6 +20,4 @@ For example, [`Lockable`](/graphql/reference/interfaces#lockable) is an interfac
For more information, see "[Implementation](/graphql/guides/introduction-to-graphql#implementation)."
{% for item in graphql.schemaForCurrentVersion.interfaces %}
{% include graphql-interface %}
{% endfor %}
<!-- Content after this section is automatically generated -->

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/mutation
- /v4/reference/mutation
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -18,5 +18,4 @@ Every GraphQL schema has a root type for both queries and mutations. The [mutati
For more information, see "[About mutations](/graphql/guides/forming-calls-with-graphql#about-mutations)."
<!-- this page is pre-rendered by scripts because it's too big to load dynamically -->
<!-- see lib/graphql/static/prerendered-mutations.json -->
<!-- Content after this section is automatically generated -->

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/object
- /v4/reference/object
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -20,5 +20,4 @@ For example, the [`Repository`](/graphql/reference/objects#repository) object ha
For more information, see "[Introduction to GraphQL](/graphql/guides/introduction-to-graphql)."
<!-- this page is pre-rendered by scripts because it's too big to load dynamically -->
<!-- see lib/graphql/static/prerendered-objects.json -->
<!-- Content after this section is automatically generated -->

View File

@@ -1,14 +1,14 @@
---
title: Queries
miniTocMaxHeadingLevel: 2
miniTocMaxHeadingLevel: 3
redirect_from:
- /v4/query
- /v4/reference/query
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -25,14 +25,4 @@ For more information, see "[About queries](/graphql/guides/forming-calls-with-gr
{% endnote %}
## Connections
{% for item in graphql.schemaForCurrentVersion.queries.connections %}
{% include graphql-query %}
{% endfor %}
## Fields
{% for item in graphql.schemaForCurrentVersion.queries.fields %}
{% include graphql-query %}
{% endfor %}
<!-- Content after this section is automatically generated -->

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/scalar
- /v4/reference/scalar
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -18,8 +18,6 @@ topics:
When calling the GraphQL API, you must specify nested subfields until you return only scalars.
For more information, see "[Introduction to GraphQL](/graphql/guides/introduction-to-graphql#field)."
For more information, see "[Introduction to GraphQL](/graphql/guides/introduction-to-graphql#field)."
{% for item in graphql.schemaForCurrentVersion.scalars %}
{% include graphql-scalar %}
{% endfor %}
<!-- Content after this section is automatically generated -->

View File

@@ -4,10 +4,10 @@ redirect_from:
- /v4/union
- /v4/reference/union
versions:
fpt: '*'
ghec: '*'
ghes: '*'
ghae: '*'
fpt: "*"
ghec: "*"
ghes: "*"
ghae: "*"
topics:
- API
---
@@ -20,6 +20,4 @@ For example, a field marked as an [`ProjectCardItem`](/graphql/reference/unions#
For more information, see "[Introduction to GraphQL](/graphql/guides/introduction-to-graphql)."
{% for item in graphql.schemaForCurrentVersion.unions %}
{% include graphql-union %}
{% endfor %}
<!-- Content after this section is automatically generated -->

View File

@@ -106,6 +106,12 @@ products:
possible_types: Possible types
preview_notice: Preview notice
deprecation_notice: Deprecation notice
preview_period: During the preview period, the API may change without notice.
overview:
preview_header: 'To toggle this preview and access the following schema members, you must provide a custom media type in the `Accept` header:'
preview_schema_members: 'Previewed schema members'
announced: Announced
updates: Updates
rest:
reference:
default: Default

View File

@@ -1,18 +0,0 @@
# Includes
The files in this directory are "includes", snippets of HTML that can be
reused in multiple layouts or pages. In Ruby on Rails parlance, these are
called "partials".
## Using Includes
This example injects the contents of `includes/graphql-enum.html` into the
page:
```
{% include graphql-enum %}
```
## Writing Includes
Includes must have a `.html` extension.

View File

@@ -1,15 +0,0 @@
<svg
aria-hidden
role="img"
class="octicon-link"
viewBox="0 0 16 16"
width="16"
height="16"
fill="currentColor"
style="display: inline-block; user-select: none; vertical-align: middle"
>
<path
fill-rule="evenodd"
d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"
/>
</svg>

Before

Width:  |  Height:  |  Size: 606 B

View File

@@ -1,14 +0,0 @@
{% if field.arguments %}
<div class="border rounded-1 mt-3 mb-3 p-3 color-bg-subtle f5">
<h4 class="pt-0 mt-0">{% data ui.products.graphql.reference.arguments %}</h4>
{% for arg in arguments %}
<ul class="list-style-none pl-0">
<li class="border-top mt-2">
<p class="mt-2"><code>{{ arg.name }}</code> (<code><a href="/{{ currentLanguage }}{{ arg.type.href }}">{{ arg.type.name }}</a></code>)</p>
{{ arg.description }}
{% if arg.defaultValue or arg.defaultValue == false %}<p>The default value is <code>{{ arg.defaultValue }}</code>.</p>{% endif %}
</li>
</ul>
{% endfor %}
</div>
{% endif %}

View File

@@ -1,6 +0,0 @@
{% if item.isDeprecated %}
<div class="extended-markdown warning border rounded-1 mt-3 mb-4 p-3 color-border-danger color-bg-danger f5">
<p><b>{% data ui.products.graphql.reference.deprecation_notice %}</b></p>
<p><code>{{ item.name }}</code> is deprecated.</p>{{ item.deprecationReason }}
</div>
{% endif %}

View File

@@ -1,20 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
</div>
<div>
{% include graphql-preview %}
{% include graphql-deprecation %}
<h4>{% data ui.products.graphql.reference.values %}</h4>
{% for value in item.values %}
<p><strong>{{ value.name }}</strong></p>
{{ value.description }}
{% endfor %}
</div>
</div>

View File

@@ -1,25 +0,0 @@
<table class="fields width-full">
<thead>
<tr>
<th>{% data ui.products.graphql.reference.name %}</th>
<th>{% data ui.products.graphql.reference.description %}</th>
</tr>
</thead>
<tbody>
{% for field in fields %}
<tr>
<td><p><code>{{ field.name }}</code> (<code><a href="/{{ currentLanguage }}{{ field.href }}">{{ field.type }}</a></code>)</p></td>
<td>{% if field.description %}{{ field.description }}{% else %}N/A{% endif %}
{% if field.defaultValue or field.defaultValue == false %}<p>The default value is <code>{{ field.defaultValue }}</code>.</p>{% endif %}
{% assign item = field %}
{% include graphql-preview %}
{% include graphql-deprecation %}
{% assign arguments = field.arguments %}
{% include graphql-arguments %}
</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@@ -1,9 +0,0 @@
<h4>{% data ui.products.graphql.reference.input_fields %}</h4>
{% for inputField in inputFields %}
<ul>
<li><code>{{ inputField.name }}</code> (<code><a href="/{{ currentLanguage }}{{ inputField.href }}">{{ inputField.type }}</a></code>)</li>
</ul>
{% assign item = inputField %}
{% include graphql-preview %}
{% include graphql-deprecation %}
{% endfor %}

View File

@@ -1,16 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
</div>
<div>
{% include graphql-preview %} {% include graphql-deprecation %}
<h4>{% data ui.products.graphql.reference.input_fields %}</h4>
{% assign fields = item.inputFields %} {% include graphql-fields %}
</div>
</div>

View File

@@ -1,34 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
</div>
<div>
{% include graphql-preview %}
{% include graphql-deprecation %}
<!-- Calculate and render "Implemented By" section -->
<!-- TODO instead of calculating in layout, better to calculate in graphql-data? -->
<h4>{% data ui.products.graphql.reference.implemented_by %}</h4>
<ul>
<!-- Loop over objects, then loop over object interfaces, and find a match -->
{% for object in graphql.schemaForCurrentVersion.objects %}
{% for interface in object.implements %}
{% if interface.name == item.name %}
<li>
<code><a href="/{{ currentLanguage }}{{ object.href }}">{{ object.name }}</a></code>
</li>
{% endif %} {% endfor %} {% endfor %}
</ul>
{% if item.fields %}
<h4>{% data ui.products.graphql.reference.fields %}</h4>
{% assign fields = item.fields %}
{% include graphql-fields %}
{% endif %}
</div>
</div>

View File

@@ -1,18 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
</div>
<div>
{% include graphql-preview %}
{% include graphql-deprecation %}
{% assign inputFields = item.inputFields %}
{% assign returnFields = item.returnFields %}
{% include graphql-input-fields %}
{% include graphql-return-fields %}
</div>
</div>

View File

@@ -1,29 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
</div>
<div>
{% include graphql-preview %} {% include graphql-deprecation %} {% if
item.implements %}
<h4>{% data ui.products.graphql.reference.implements %}</h4>
<ul>
{% for interface in item.implements %}
<li>
<code
><a href="/{{ currentLanguage }}{{ interface.href }}"
>{{ interface.name }}</a
></code
>
</li>
{% endfor %}
</ul>
{% endif %} {% if item.fields %}
<h4>{% data ui.products.graphql.reference.fields %}</h4>
{% assign fields = item.fields %} {% include graphql-fields %} {% endif %}
</div>
</div>

View File

@@ -1,6 +0,0 @@
{% if item.preview %}
<div class="extended-markdown note border rounded-1 mt-3 mb-4 p-3 color-border-accent-emphasis color-bg-accent f5">
<p><b>{% data ui.products.graphql.reference.preview_notice %}</b></p>
<p><code>{{ item.name }}</code> is available under the <a href="/{{ currentLanguage }}{{ item.preview.href }}">{{ item.preview.title }}</a>. During the preview period, the API may change without notice.</p>
</div>
{% endif %}

View File

@@ -1,19 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" aria-hidden tabindex="-1" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
<p>
<b>{% data ui.products.graphql.reference.type %}:</b>
<a href="/{{ currentLanguage }}{{ item.href }}">{{ item.type }}</a>
</p>
{{ item.description }}
</div>
<div>
{% include graphql-preview %} {% include graphql-deprecation %} {% if item.args.size > 0 %}
<h4>{% data ui.products.graphql.reference.arguments %}</h4>
{% assign fields = item.args %} {% include graphql-fields %} {% endif %}
</div>
</div>

View File

@@ -1,22 +0,0 @@
<h4>{% data ui.products.graphql.reference.return_fields %}</h4>
<table class="fields width-full">
<thead>
<tr>
<th>{% data ui.products.graphql.reference.name %}</th>
<th>{% data ui.products.graphql.reference.description %}</th>
</tr>
</thead>
<tbody>
{% for returnField in returnFields %}
<tr>
<td><p><code>{{ returnField.name }}</code> (<code><a href="/{{ currentLanguage }}{{ returnField.href }}">{{ returnField.type }}</a></code>)</p></td>
<td>{% if returnField.description %}{{ returnField.description }}{% else %}N/A{% endif %}
{% assign item = returnField %}
{% include graphql-preview %}
{% include graphql-deprecation %}
</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@@ -1,12 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
{% include graphql-preview %}
{% include graphql-deprecation %}
</div>
</div>

View File

@@ -1,21 +0,0 @@
<div>
<div>
<h2 id="{{ item.id }}">
<a href="#{{ item.id }}" class="doctocat-link">{% include doctocat-link-icon %}</a>
{{- item.name -}}
</h2>
{{ item.description }}
</div>
<div>
{% include graphql-preview %}
{% include graphql-deprecation %}
<h4>{% data ui.products.graphql.reference.possible_types %}</h4>
<ul>
{% for possibleType in item.possibleTypes %}
<li><a href="/{{ currentLanguage }}{{ possibleType.href }}">{{ possibleType.name }}</a></li>
{% endfor %}
</ul>
</div>
</div>

View File

@@ -1,8 +0,0 @@
# Liquid Tags
This directory contains templates for our custom Liquid tags.
See also:
- [lib/liquid-tags/README.md](../../lib/liquid-tags/README.md)
- [contributing/liquid-helpers.md](../../contributing/liquid-helpers.md)

View File

@@ -1 +0,0 @@
{{ renderedReferenceWithIndent }}

90
lib/graphql/index.js Normal file
View File

@@ -0,0 +1,90 @@
import {
readCompressedJsonFileFallbackLazily,
readCompressedJsonFileFallback,
} from '../../lib/read-json-file.js'
import { getAutomatedPageMiniTocItems } from '../get-mini-toc-items.js'
import languages from '../languages.js'
import { allVersions } from '../all-versions.js'
/* ADD LANGUAGE KEY */
let previews
let upcomingChanges
const changelog = new Map()
const graphqlSchema = new Map()
const miniTocs = new Map()
Object.keys(languages).forEach((language) => {
miniTocs.set(language, new Map())
})
export function getGraphqlSchema(version, type) {
const graphqlVersion = getGraphqlVersion(version)
if (!graphqlSchema.has(graphqlVersion)) {
graphqlSchema.set(
graphqlVersion,
readCompressedJsonFileFallback(`lib/graphql/static/schema-${graphqlVersion}.json`)
)
}
return graphqlSchema.get(graphqlVersion)[type]
}
export function getGraphqlChangelog() {
if (!changelog.has('schema')) {
changelog.set(
'schema',
readCompressedJsonFileFallbackLazily('./lib/graphql/static/changelog.json')()
)
}
return changelog.get('schema')
}
export function getGraphqlBreakingChanges(version) {
const graphqlVersion = getGraphqlVersion(version)
if (!upcomingChanges) {
upcomingChanges = readCompressedJsonFileFallbackLazily(
'./lib/graphql/static/upcoming-changes.json'
)()
}
return upcomingChanges[graphqlVersion]
}
export function getPreviews(version) {
const graphqlVersion = getGraphqlVersion(version)
if (!previews) {
previews = readCompressedJsonFileFallbackLazily('./lib/graphql/static/previews.json')()
}
return previews[graphqlVersion]
}
export async function getMiniToc(context, type, items, depth = 2, markdownHeading = '') {
const { currentLanguage, currentVersion } = context
const graphqlVersion = getGraphqlVersion(currentVersion)
if (!miniTocs.get(currentLanguage).has(graphqlVersion)) {
miniTocs.get(currentLanguage).set(graphqlVersion, new Map())
}
if (!miniTocs.get(currentLanguage).get(graphqlVersion).has(type)) {
const graphqlMiniTocItems = await getAutomatedPageMiniTocItems(
items,
context,
depth,
markdownHeading
)
miniTocs.get(currentLanguage).get(graphqlVersion).set(type, graphqlMiniTocItems)
}
return miniTocs.get(currentLanguage).get(graphqlVersion).get(type)
}
export async function getChangelogMiniTocs(items, context, depth = 2, markdownHeading = '') {
if (!changelog.has('toc')) {
changelog.set('toc', await getAutomatedPageMiniTocItems(items, context, depth, markdownHeading))
}
return changelog.get('toc')
}
function getGraphqlVersion(version) {
if (!(version in allVersions)) {
throw new Error(`Unrecognized version '${version}'. Not found in ${Object.keys(allVersions)}`)
}
return allVersions[version].miscVersionName
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -90272,7 +90272,7 @@
},
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -90292,7 +90292,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -90349,13 +90349,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -90368,7 +90368,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -73488,7 +73488,7 @@
},
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -73508,7 +73508,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -73565,13 +73565,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -73584,7 +73584,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -90272,7 +90272,7 @@
},
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -90292,7 +90292,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -90349,13 +90349,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -90368,7 +90368,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -73150,7 +73150,7 @@
"scalars": [
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -73170,7 +73170,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -73227,13 +73227,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -73246,7 +73246,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -72887,7 +72887,7 @@
},
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -72907,7 +72907,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -72964,13 +72964,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -72983,7 +72983,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -73735,7 +73735,7 @@
},
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -73755,7 +73755,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -73812,13 +73812,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -73831,7 +73831,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -74968,7 +74968,7 @@
},
{
"name": "Boolean",
"description": "Represents `true` or `false` values.",
"description": "<p>Represents <code>true</code> or <code>false</code> values.</p>",
"id": "boolean",
"href": "/graphql/reference/scalars#boolean"
},
@@ -74988,7 +74988,7 @@
},
{
"name": "Float",
"description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
"description": "<p>Represents signed double-precision fractional values as specified by <a href=\"https://en.wikipedia.org/wiki/IEEE_floating_point\">IEEE 754</a>.</p>",
"id": "float",
"href": "/graphql/reference/scalars#float"
},
@@ -75045,13 +75045,13 @@
},
{
"name": "ID",
"description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
"description": "<p>Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as <code>\"VXNlci0xMA==\"</code>) or integer (such as <code>4</code>) input value will be accepted as an ID.</p>",
"id": "id",
"href": "/graphql/reference/scalars#id"
},
{
"name": "Int",
"description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
"description": "<p>Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.</p>",
"id": "int",
"href": "/graphql/reference/scalars#int"
},
@@ -75064,7 +75064,7 @@
},
{
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
"description": "<p>Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.</p>",
"id": "string",
"href": "/graphql/reference/scalars#string"
},

View File

@@ -18,7 +18,7 @@ const contentPath = path.join(process.cwd(), 'content/rest')
Example:
{
version: {
[version]: {
category: {
subcategory: [operations],
}

View File

@@ -1,62 +0,0 @@
import {
readCompressedJsonFileFallbackLazily,
readCompressedJsonFileFallback,
} from '../../lib/read-json-file.js'
import { allVersions } from '../../lib/all-versions.js'
const previews = readCompressedJsonFileFallbackLazily('./lib/graphql/static/previews.json')
const upcomingChanges = readCompressedJsonFileFallbackLazily(
'./lib/graphql/static/upcoming-changes.json'
)
const changelog = readCompressedJsonFileFallbackLazily('./lib/graphql/static/changelog.json')
const prerenderedObjects = readCompressedJsonFileFallbackLazily(
'./lib/graphql/static/prerendered-objects.json'
)
const prerenderedInputObjects = readCompressedJsonFileFallbackLazily(
'./lib/graphql/static/prerendered-input-objects.json'
)
const prerenderedMutations = readCompressedJsonFileFallbackLazily(
'./lib/graphql/static/prerendered-mutations.json'
)
const explorerUrl =
process.env.NODE_ENV === 'production'
? 'https://graphql.github.com/explorer'
: 'http://localhost:3000'
const graphQLVersionSchemaCache = new Map()
function readGraphQLVersionSchema(graphqlVersion) {
if (!graphQLVersionSchemaCache.has(graphqlVersion)) {
graphQLVersionSchemaCache.set(
graphqlVersion,
readCompressedJsonFileFallback(`lib/graphql/static/schema-${graphqlVersion}.json`)
)
}
return graphQLVersionSchemaCache.get(graphqlVersion)
}
export default function graphqlContext(req, res, next) {
const currentVersionObj = allVersions[req.context.currentVersion]
// ignore requests to non-GraphQL reference paths
// and to versions that don't exist
if (!req.pagePath.includes('/graphql/') || !currentVersionObj) {
return next()
}
// Get the relevant name of the GraphQL schema files for the current version
// For example, free-pro-team@latest corresponds to dotcom,
// enterprise-server@2.22 corresponds to ghes-2.22,
// and github-ae@latest corresponds to ghae
const graphqlVersion = currentVersionObj.miscVersionName
req.context.graphql = {
schemaForCurrentVersion: readGraphQLVersionSchema(graphqlVersion),
previewsForCurrentVersion: previews()[graphqlVersion],
upcomingChangesForCurrentVersion: upcomingChanges()[graphqlVersion],
prerenderedObjectsForCurrentVersion: prerenderedObjects()[graphqlVersion],
prerenderedInputObjectsForCurrentVersion: prerenderedInputObjects()[graphqlVersion],
prerenderedMutationsForCurrentVersion: prerenderedMutations()[graphqlVersion],
explorerUrl,
changelog: changelog(),
}
return next()
}

View File

@@ -40,7 +40,6 @@ import categoriesForSupport from './categories-for-support.js'
import triggerError from './trigger-error.js'
import releaseNotes from './contextualizers/release-notes.js'
import whatsNewChangelog from './contextualizers/whats-new-changelog.js'
import graphQL from './contextualizers/graphql.js'
import webhooks from './contextualizers/webhooks.js'
import layout from './contextualizers/layout.js'
import currentProductTree from './contextualizers/current-product-tree.js'
@@ -282,7 +281,6 @@ export default function (app) {
// *** Preparation for render-page: contextualizers ***
app.use(asyncMiddleware(instrument(releaseNotes, './contextualizers/release-notes')))
app.use(instrument(graphQL, './contextualizers/graphql'))
app.use(instrument(webhooks, './contextualizers/webhooks'))
app.use(asyncMiddleware(instrument(whatsNewChangelog, './contextualizers/whats-new-changelog')))
app.use(instrument(layout, './contextualizers/layout'))

View File

@@ -24,21 +24,6 @@ async function buildRenderedPage(req) {
const renderedPage = await pageRenderTimed(context)
// handle special-case prerendered GraphQL objects page
if (path.endsWith('graphql/reference/objects')) {
return renderedPage + context.graphql.prerenderedObjectsForCurrentVersion.html
}
// handle special-case prerendered GraphQL input objects page
if (path.endsWith('graphql/reference/input-objects')) {
return renderedPage + context.graphql.prerenderedInputObjectsForCurrentVersion.html
}
// handle special-case prerendered GraphQL mutations page
if (path.endsWith('graphql/reference/mutations')) {
return renderedPage + context.graphql.prerenderedMutationsForCurrentVersion.html
}
return renderedPage
}

View File

@@ -0,0 +1,61 @@
import { GetServerSideProps } from 'next'
import React from 'react'
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
import { AutomatedPage } from 'components/article/AutomatedPage'
import {
AutomatedPageContext,
AutomatedPageContextT,
getAutomatedPageContextFromRequest,
} from 'components/context/AutomatedPageContext'
import { getAutomatedPageMiniTocItems } from 'lib/get-mini-toc-items.js'
import { BreakingChanges } from 'components/graphql/BreakingChanges'
import { BreakingChangesT } from 'components/graphql/types'
import { getGraphqlBreakingChanges } from 'lib/graphql/index.js'
type Props = {
mainContext: MainContextT
schema: BreakingChangesT
automatedPageContext: AutomatedPageContextT
}
export default function GraphqlBreakingChanges({
mainContext,
schema,
automatedPageContext,
}: Props) {
return (
<MainContext.Provider value={mainContext}>
<AutomatedPageContext.Provider value={automatedPageContext}>
<AutomatedPage>
<BreakingChanges schema={schema} />
</AutomatedPage>
</AutomatedPageContext.Provider>
</MainContext.Provider>
)
}
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any
const res = context.res as any
const currentVersion = context.query.versionId as string
const schema = getGraphqlBreakingChanges(currentVersion)
if (!schema) throw new Error(`No graphql breaking changes schema found for ${currentVersion}`)
// Gets the miniTocItems in the article context. At this point it will only
// include miniTocItems that exist in Markdown pages in
// content/graphql/reference/*
const automatedPageContext = getAutomatedPageContextFromRequest(req)
const titles = Object.keys(schema).map((item) => `Changes scheduled for ${item}`)
const changelogMiniTocItems = await getAutomatedPageMiniTocItems(titles, req.context.context, 2)
// Update the existing context to include the miniTocItems from GraphQL
automatedPageContext.miniTocItems.push(...changelogMiniTocItems)
return {
props: {
mainContext: getMainContext(req, res),
automatedPageContext,
schema,
},
}
}

View File

@@ -0,0 +1,54 @@
import { GetServerSideProps } from 'next'
import React from 'react'
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
import { AutomatedPage } from 'components/article/AutomatedPage'
import {
AutomatedPageContext,
AutomatedPageContextT,
getAutomatedPageContextFromRequest,
} from 'components/context/AutomatedPageContext'
import { getAutomatedPageMiniTocItems } from 'lib/get-mini-toc-items.js'
import { Changelog } from 'components/graphql/Changelog'
import { ChangelogItemT } from 'components/graphql/types'
import { getGraphqlChangelog } from 'lib/graphql/index.js'
type Props = {
mainContext: MainContextT
schema: ChangelogItemT[]
automatedPageContext: AutomatedPageContextT
}
export default function GraphqlChangelog({ mainContext, schema, automatedPageContext }: Props) {
const content = <Changelog changelogItems={schema} />
return (
<MainContext.Provider value={mainContext}>
<AutomatedPageContext.Provider value={automatedPageContext}>
<AutomatedPage>{content}</AutomatedPage>
</AutomatedPageContext.Provider>
</MainContext.Provider>
)
}
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any
const res = context.res as any
const schema = getGraphqlChangelog() as ChangelogItemT[]
if (!schema) throw new Error('No graphql free-pro-team changelog schema found.')
// Gets the miniTocItems in the article context. At this point it will only
// include miniTocItems that exist in Markdown pages in
// content/graphql/reference/*
const automatedPageContext = getAutomatedPageContextFromRequest(req)
const titles = schema.map((item) => `Schema changes for ${item.date}`)
const changelogMiniTocItems = await getAutomatedPageMiniTocItems(titles, req.context.context, 2)
// Update the existing context to include the miniTocItems from GraphQL
automatedPageContext.miniTocItems.push(...changelogMiniTocItems)
return {
props: {
mainContext: getMainContext(req, res),
automatedPageContext,
schema,
},
}
}

View File

@@ -49,11 +49,15 @@ export default function GQLExplorer({ mainContext, graphqlExplorerUrl }: Props)
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any
const res = context.res as any
const graphqlExplorerUrl =
process.env.NODE_ENV === 'production'
? 'https://graphql.github.com/explorer'
: 'http://localhost:3000'
return {
props: {
mainContext: getMainContext(req, res),
graphqlExplorerUrl: req.context.graphql.explorerUrl,
graphqlExplorerUrl,
},
}
}

View File

@@ -0,0 +1,56 @@
import { GetServerSideProps } from 'next'
import React from 'react'
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
import { AutomatedPage } from 'components/article/AutomatedPage'
import {
AutomatedPageContext,
AutomatedPageContextT,
getAutomatedPageContextFromRequest,
} from 'components/context/AutomatedPageContext'
import { getAutomatedPageMiniTocItems } from 'lib/get-mini-toc-items.js'
import { Previews } from 'components/graphql/Previews'
import { PreviewT } from 'components/graphql/types'
import { getPreviews } from 'lib/graphql/index.js'
type Props = {
mainContext: MainContextT
schema: PreviewT[]
automatedPageContext: AutomatedPageContextT
}
export default function GraphqlPreviews({ mainContext, schema, automatedPageContext }: Props) {
const content = <Previews schema={schema} />
return (
<MainContext.Provider value={mainContext}>
<AutomatedPageContext.Provider value={automatedPageContext}>
<AutomatedPage>{content}</AutomatedPage>
</AutomatedPageContext.Provider>
</MainContext.Provider>
)
}
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any
const res = context.res as any
const currentVersion = context.query.versionId as string
const schema = getPreviews(currentVersion) as PreviewT[]
if (!schema) throw new Error(`No graphql preview schema found for ${currentVersion}`)
// Gets the miniTocItems in the article context. At this point it will only
// include miniTocItems that exist in Markdown pages in
// content/graphql/reference/*
const automatedPageContext = getAutomatedPageContextFromRequest(req)
const titles = schema.map((item) => item.title)
const changelogMiniTocItems = await getAutomatedPageMiniTocItems(titles, req.context.context, 2)
// Update the existing context to include the miniTocItems from GraphQL
automatedPageContext.miniTocItems.push(...changelogMiniTocItems)
return {
props: {
mainContext: getMainContext(req, res),
automatedPageContext,
schema,
},
}
}

View File

@@ -0,0 +1,91 @@
import { GetServerSideProps } from 'next'
import React from 'react'
import { GraphqlPage } from 'components/graphql/GraphqlPage'
import { getGraphqlSchema, getMiniToc } from 'lib/graphql/index.js'
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
import type { ObjectT, QueryItemT, GraphqlT } from 'components/graphql/types'
import { AutomatedPage } from 'components/article/AutomatedPage'
import {
AutomatedPageContext,
AutomatedPageContextT,
getAutomatedPageContextFromRequest,
} from 'components/context/AutomatedPageContext'
type Props = {
mainContext: MainContextT
automatedPageContext: AutomatedPageContextT
schema: Object
language: string
graphqlPageName: string
objects?: ObjectT[]
}
export default function GraphqlReferencePage({
mainContext,
automatedPageContext,
schema,
graphqlPageName,
objects,
}: Props) {
const content = (
<GraphqlPage schema={schema} pageName={graphqlPageName} objects={objects || undefined} />
)
return (
<MainContext.Provider value={mainContext}>
<AutomatedPageContext.Provider value={automatedPageContext}>
<AutomatedPage>{content}</AutomatedPage>
</AutomatedPageContext.Provider>
</MainContext.Provider>
)
}
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any
const res = context.res as any
const language = req.context.currentLanguage as string
const currentVersion = req.context.currentVersion as string
const page = context.query.page as string
const graphqlPageName = page === 'input-objects' ? 'inputObjects' : page
const schema = getGraphqlSchema(currentVersion, graphqlPageName)
// When the page is 'interfaces', we need to make another call to
// get the objects page properties too.
const objects =
graphqlPageName === 'interfaces' ? getGraphqlSchema(currentVersion, 'objects') : null
// Gets the miniTocItems in the article context. At this point it will only
// include miniTocItems that exist in Markdown pages in
// content/graphql/reference/*
const automatedPageContext = getAutomatedPageContextFromRequest(req)
if (graphqlPageName === 'queries') {
const connectionItems = schema.connections.map((item: QueryItemT) => item.name)
const connectionMiniToc = await getMiniToc(
req.context,
'connections',
connectionItems,
3,
'## Connections\n'
)
const fieldItems = schema.fields.map((item: QueryItemT) => item.name)
const fieldMiniToc = await getMiniToc(req.context, 'fields', fieldItems, 3, '## Fields\n')
automatedPageContext.miniTocItems.push(...connectionMiniToc, ...fieldMiniToc)
} else {
const items = schema.map((item: GraphqlT) => item.name)
const graphqlMiniTocItems = await getMiniToc(req.context, graphqlPageName, items)
// Update the existing context to include the miniTocItems from GraphQL
automatedPageContext.miniTocItems.push(...graphqlMiniTocItems)
}
return {
props: {
mainContext: getMainContext(req, res),
automatedPageContext,
schema,
language,
graphqlPageName,
objects,
},
}
}

View File

@@ -2,6 +2,7 @@
import { diff, ChangeType } from '@graphql-inspector/core'
import { loadSchema } from '@graphql-tools/load'
import fs from 'fs'
import renderContent from '../../lib/render-content'
/**
* Tag `changelogEntry` with `date: YYYY-mm-dd`, then prepend it to the JSON
@@ -91,15 +92,27 @@ export async function createChangelogEntry(
upcomingChanges: [],
}
const cleanedSchemaChanges = cleanMessagesFromChanges(schemaChangesToReport)
const renderedScheamChanges = await Promise.all(
cleanedSchemaChanges.map(async (change) => {
return await renderContent(change)
})
)
const schemaChange = {
title: 'The GraphQL schema includes these changes:',
// Replace single quotes which wrap field/argument/type names with backticks
changes: cleanMessagesFromChanges(schemaChangesToReport),
changes: renderedScheamChanges,
}
changelogEntry.schemaChanges.push(schemaChange)
for (const previewTitle in previewChangesToReport) {
const previewChanges = previewChangesToReport[previewTitle]
const cleanedPreviewChanges = cleanMessagesFromChanges(previewChanges.changes)
const renderedPreviewChanges = await Promise.all(
cleanedPreviewChanges.map(async (change) => {
return renderContent(change)
})
)
const cleanTitle = cleanPreviewTitle(previewTitle)
const entryTitle =
'The [' +
@@ -109,19 +122,25 @@ export async function createChangelogEntry(
') includes these changes:'
changelogEntry.previewChanges.push({
title: entryTitle,
changes: cleanMessagesFromChanges(previewChanges.changes),
changes: renderedPreviewChanges,
})
}
if (addedUpcomingChanges.length > 0) {
const cleanedUpcomingChanges = addedUpcomingChanges.map((change) => {
const location = change.location
const description = change.description
const date = change.date.split('T')[0]
return 'On member `' + location + '`:' + description + ' **Effective ' + date + '**.'
})
const renderedUpcomingChanges = await Promise.all(
cleanedUpcomingChanges.map(async (change) => {
return await renderContent(change)
})
)
changelogEntry.upcomingChanges.push({
title: 'The following changes will be made to the schema:',
changes: addedUpcomingChanges.map(function (change) {
const location = change.location
const description = change.description
const date = change.date.split('T')[0]
return 'On member `' + location + '`:' + description + ' **Effective ' + date + '**.'
}),
changes: renderedUpcomingChanges,
})
}

View File

@@ -9,7 +9,6 @@ import { allVersions } from '../../lib/all-versions.js'
import processPreviews from './utils/process-previews.js'
import processUpcomingChanges from './utils/process-upcoming-changes.js'
import processSchemas from './utils/process-schemas.js'
import prerender from './utils/prerender-graphql.js'
import { prependDatedEntry, createChangelogEntry } from './build-changelog.js'
import loadData from '../../lib/site-data.js'
@@ -33,9 +32,6 @@ main()
async function main() {
const previewsJson = {}
const upcomingChangesJson = {}
const prerenderedObjects = {}
const prerenderedInputObjects = {}
const prerenderedMutations = {}
const siteData = loadData()
@@ -81,26 +77,7 @@ async function main() {
context.graphql = { schemaForCurrentVersion: schemaJsonPerVersion }
context.currentVersion = version
// 4. PRERENDER OBJECTS HTML
// because the objects page is too big to render on page load
prerenderedObjects[graphqlVersion] = await prerender(context, 'objects', 'graphql-object.html')
// 5. PRERENDER INPUT OBJECTS HTML
// because the objects page is too big to render on page load
prerenderedInputObjects[graphqlVersion] = await prerender(
context,
'inputObjects',
'graphql-input-object.html'
)
// Prerender mutations
prerenderedMutations[graphqlVersion] = await prerender(
context,
'mutations',
'graphql-mutation.html'
)
// 6. UPDATE CHANGELOG
// 4. UPDATE CHANGELOG
if (allVersions[version].nonEnterpriseDefault) {
// The Changelog is only build for free-pro-team@latest
const changelogEntry = await createChangelogEntry(
@@ -121,18 +98,6 @@ async function main() {
await updateStaticFile(previewsJson, path.join(graphqlStaticDir, 'previews.json'))
await updateStaticFile(upcomingChangesJson, path.join(graphqlStaticDir, 'upcoming-changes.json'))
await updateStaticFile(
prerenderedObjects,
path.join(graphqlStaticDir, 'prerendered-objects.json')
)
await updateStaticFile(
prerenderedInputObjects,
path.join(graphqlStaticDir, 'prerendered-input-objects.json')
)
await updateStaticFile(
prerenderedMutations,
path.join(graphqlStaticDir, 'prerendered-mutations.json')
)
// Ensure the YAML linter runs before checkinging in files
execSync('npx prettier -w "**/*.{yml,yaml}"')

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env node
import fs from 'fs/promises'
import path from 'path'
import cheerio from 'cheerio'
import { liquid } from '../../../lib/render-content/index.js'
import getMiniTocItems from '../../../lib/get-mini-toc-items.js'
import rewriteLocalLinks from '../../../lib/rewrite-local-links.js'
const includes = path.join(process.cwd(), 'includes')
export default async function prerender(context, type, includeFilename) {
const htmlArray = []
const includeFile = await fs.readFile(path.join(includes, includeFilename), 'utf8')
// render the layout for every object
for (const item of context.graphql.schemaForCurrentVersion[type]) {
context.item = item
const itemHtml = await liquid.parseAndRender(includeFile, context)
const $ = cheerio.load(itemHtml, { xmlMode: true })
rewriteLocalLinks($, context.currentVersion, context.currentLanguage)
const htmlWithVersionedLinks = $.html()
htmlArray.push(htmlWithVersionedLinks)
}
const html = htmlArray.join('\n')
return {
html,
miniToc: getMiniTocItems(html),
}
}

View File

@@ -1,33 +0,0 @@
#!/usr/bin/env node
import fs from 'fs/promises'
import path from 'path'
import cheerio from 'cheerio'
import { liquid } from '../../../lib/render-content/index.js'
import getMiniTocItems from '../../../lib/get-mini-toc-items.js'
import rewriteLocalLinks from '../../../lib/rewrite-local-links.js'
const includes = path.join(process.cwd(), 'includes')
const inputObjectIncludeFile = await fs.readFile(
path.join(includes, 'graphql-input-object.html'),
'utf8'
)
export default async function prerenderInputObjects(context) {
const inputObjectsArray = []
// render the graphql-object.html layout for every object
for (const inputObject of context.graphql.schemaForCurrentVersion.inputObjects) {
context.item = inputObject
const inputObjectHtml = await liquid.parseAndRender(inputObjectIncludeFile, context)
const $ = cheerio.load(inputObjectHtml, { xmlMode: true })
rewriteLocalLinks($, context.currentVersion, context.currentLanguage)
const htmlWithVersionedLinks = $.html()
inputObjectsArray.push(htmlWithVersionedLinks)
}
const inputObjectsHtml = inputObjectsArray.join('\n')
return {
html: inputObjectsHtml,
miniToc: getMiniTocItems(inputObjectsHtml),
}
}

View File

@@ -1,30 +0,0 @@
#!/usr/bin/env node
import fs from 'fs/promises'
import path from 'path'
import cheerio from 'cheerio'
import { liquid } from '../../../lib/render-content/index.js'
import getMiniTocItems from '../../../lib/get-mini-toc-items.js'
import rewriteLocalLinks from '../../../lib/rewrite-local-links.js'
const includes = path.join(process.cwd(), 'includes')
const objectIncludeFile = await fs.readFile(path.join(includes, 'graphql-object.html'), 'utf8')
export default async function prerenderObjects(context) {
const objectsArray = []
// render the graphql-object.html layout for every object
for (const object of context.graphql.schemaForCurrentVersion.objects) {
context.item = object
const objectHtml = await liquid.parseAndRender(objectIncludeFile, context)
const $ = cheerio.load(objectHtml, { xmlMode: true })
rewriteLocalLinks($, context.currentVersion, context.currentLanguage)
const htmlWithVersionedLinks = $.html()
objectsArray.push(htmlWithVersionedLinks)
}
const objectsHtml = objectsArray.join('\n')
return {
html: objectsHtml,
miniToc: getMiniTocItems(objectsHtml),
}
}

View File

@@ -5,13 +5,17 @@ import helpers from './schema-helpers.js'
import fs from 'fs/promises'
import path from 'path'
const externalScalars = JSON.parse(
const externalScalarsJSON = JSON.parse(
await fs.readFile(path.join(process.cwd(), './lib/graphql/non-schema-scalars.json'))
).map((scalar) => {
scalar.id = helpers.getId(scalar.name)
scalar.href = helpers.getFullLink('scalars', scalar.id)
return scalar
})
)
const externalScalars = await Promise.all(
externalScalarsJSON.map(async (scalar) => {
scalar.description = await helpers.getDescription(scalar.description)
scalar.id = helpers.getId(scalar.name)
scalar.href = helpers.getFullLink('scalars', scalar.id)
return scalar
})
)
// select and format all the data from the schema that we need for the docs
// used in the build step by script/graphql/build-static-files.js

View File

@@ -10,7 +10,6 @@ import { jest } from '@jest/globals'
const previewsJson = readJsonFile('./lib/graphql/static/previews.json')
const upcomingChangesJson = readJsonFile('./lib/graphql/static/upcoming-changes.json')
const prerenderedObjectsJson = readJsonFile('./lib/graphql/static/prerendered-objects.json')
const allVersionValues = Object.values(allVersions)
const graphqlVersions = allVersionValues.map((v) => v.miscVersionName)
const graphqlTypes = readJsonFile('./lib/graphql/types.json').map((t) => t.kind)
@@ -22,7 +21,6 @@ describe('graphql json files', () => {
graphqlVersions.forEach((version) => {
expect(version in previewsJson).toBe(true)
expect(version in upcomingChangesJson).toBe(true)
expect(version in prerenderedObjectsJson).toBe(true)
})
})
@@ -86,26 +84,4 @@ describe('graphql json files', () => {
})
})
})
test('prerendered objects validation', () => {
graphqlVersions.forEach((version) => {
// TODO: Is this still true?
//
// shape of prerenderedObject: {
// html: <div>foo</div>,
// miniToc: {contents: '<a>bar</a>', headingLevel: N, indentationLevel: N}
// }
const prerenderedHtml = prerenderedObjectsJson[version].html
expect(typeof prerenderedHtml).toBe('string')
expect(prerenderedHtml.startsWith('<div>')).toBe(true)
const prerenderedMiniToc = prerenderedObjectsJson[version].miniToc
expect(Array.isArray(prerenderedMiniToc)).toBe(true)
expect(prerenderedMiniToc.length).toBeGreaterThan(0)
expect(typeof prerenderedMiniToc[0].contents).toBe('object')
// TODO: Check whether the following should be removed or updated.
// expect(typeof prerenderedMiniToc[0].headingLevel).toBe('number')
// expect(typeof prerenderedMiniToc[0].indentationLevel).toBe('number')
})
})
})

View File

@@ -2,8 +2,8 @@
"previewChanges": [
{
"changes": [
"Type for argument `changeTypeArgument` on field 'PreviewType.field1` changed from `Int` to `Float'",
"Field `Query.previewField` changed type from `PreviewType` to `PreviewType!`"
"<p>Type for argument <code>changeTypeArgument</code> on field 'PreviewType.field1<code>changed from</code>Int<code>to</code>Float'</p>",
"<p>Field <code>Query.previewField</code> changed type from <code>PreviewType</code> to <code>PreviewType!</code></p>"
],
"title": "The [Test preview](/graphql/overview/schema-previews#test-preview) includes these changes:"
}
@@ -11,11 +11,11 @@
"schemaChanges": [
{
"changes": [
"Field `removedField` was removed from object type `Query`",
"Argument `removedRequiredArgument: Int!` was removed from field `Query.argumentsField`",
"Argument `removedOptionalArgument: Int!` was removed from field `Query.argumentsField`",
"Type for argument `argumentMadeRequired` on field `Query.argumentsField` changed from `Int` to `Int!`",
"Type for argument `argumentMadeOptional` on field `Query.argumentsField` changed from `Int!` to `Int`"
"<p>Field <code>removedField</code> was removed from object type <code>Query</code></p>",
"<p>Argument <code>removedRequiredArgument: Int!</code> was removed from field <code>Query.argumentsField</code></p>",
"<p>Argument <code>removedOptionalArgument: Int!</code> was removed from field <code>Query.argumentsField</code></p>",
"<p>Type for argument <code>argumentMadeRequired</code> on field <code>Query.argumentsField</code> changed from <code>Int</code> to <code>Int!</code></p>",
"<p>Type for argument <code>argumentMadeOptional</code> on field <code>Query.argumentsField</code> changed from <code>Int!</code> to <code>Int</code></p>"
],
"title": "The GraphQL schema includes these changes:"
}
@@ -23,7 +23,7 @@
"upcomingChanges": [
{
"changes": [
"On member `Query.stableField`:`stableField` will be removed. **Effective 2021-06-01**."
"<p>On member <code>Query.stableField</code>:<code>stableField</code> will be removed. <strong>Effective 2021-06-01</strong>.</p>"
],
"title": "The following changes will be made to the schema:"
}

41
tests/unit/graphql.js Normal file
View File

@@ -0,0 +1,41 @@
import { describe } from '@jest/globals'
import { readFileSync } from 'fs'
import { allVersions } from '../../lib/all-versions.js'
import {
getGraphqlSchema,
getGraphqlChangelog,
getGraphqlBreakingChanges,
getPreviews,
} from '../../lib/graphql/index.js'
describe('graphql schema', () => {
const graphqlTypes = JSON.parse(readFileSync('lib/graphql/types.json')).map((item) => item.kind)
for (const version in allVersions) {
for (const type of graphqlTypes) {
test(`getting the GraphQL ${type} schema works for ${version}`, async () => {
const schema = getGraphqlSchema(version, type)
expect(schema).toBeDefined()
})
}
}
test('getting the graphql changelog works for dotcom', async () => {
const defaultVersion = allVersions.defaultVersion
const schema = getGraphqlChangelog(defaultVersion)
expect(schema).toBeDefined()
})
test('getting the graphql breaking changes works for every version', async () => {
for (const version in allVersions) {
const schema = getGraphqlBreakingChanges(version)
expect(schema).toBeDefined()
}
})
test('getting the graphql previews works for every version', async () => {
for (const version in allVersions) {
const schema = getPreviews(version)
expect(schema).toBeDefined()
}
})
})

View File

@@ -4,14 +4,12 @@ import cheerio from 'cheerio'
import { describe, expect } from '@jest/globals'
import Page from '../../lib/page.js'
import readJsonFile from '../../lib/read-json-file.js'
import { allVersions } from '../../lib/all-versions.js'
import enterpriseServerReleases, { latest } from '../../lib/enterprise-server-releases.js'
import nonEnterpriseDefaultVersion from '../../lib/non-enterprise-default-version.js'
import loadSiteData from '../../lib/site-data.js'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const prerenderedObjects = readJsonFile('./lib/graphql/static/prerendered-objects.json')
const enterpriseServerVersions = Object.keys(allVersions).filter((v) =>
v.startsWith('enterprise-server@')
)
@@ -144,18 +142,6 @@ describe('Page class', () => {
expect(last.attr('href')).toBe('/en/enterprise-server@3.2')
})
test('rewrites links on prerendered GraphQL page include the current language prefix and version', async () => {
const graphqlVersion =
allVersions[`enterprise-server@${enterpriseServerReleases.latest}`].miscVersionName
const $ = cheerio.load(prerenderedObjects[graphqlVersion].html)
expect($('a[href^="/graphql/reference/input-objects"]').length).toBe(0)
expect(
$(
`a[href^="/en/enterprise-server@${enterpriseServerReleases.latest}/graphql/reference/input-objects"]`
).length
).toBeGreaterThan(0)
})
test('rewrites links in the intro to include the current language prefix and version', async () => {
const page = await Page.init(opts)
page.rawIntro =