Upgrade Grats enable semantic nullability

This commit is contained in:
Jordan Eldredge 2024-04-26 08:32:33 -07:00
parent 823720fd43
commit 86f2e694b4
5 changed files with 11104 additions and 10809 deletions

View file

@ -1,5 +1,38 @@
# Schema generated by Grats (https://grats.capt.dev)
# Do not manually edit. Regenerate by running `npx grats`.
"""
Indicates that a position is semantically non null: it is only null if there is a matching error in the `errors` array.
In all other cases, the position is non-null.
Tools doing code generation may use this information to generate the position as non-null if field errors are handled out of band:
```graphql
type User {
# email is semantically non-null and can be generated as non-null by error-handling clients.
email: String @semanticNonNull
}
```
The `levels` argument indicates what levels are semantically non null in case of lists:
```graphql
type User {
# friends is semantically non null
friends: [User] @semanticNonNull # same as @semanticNonNull(levels: [0])
# every friends[k] is semantically non null
friends: [User] @semanticNonNull(levels: [1])
# friends as well as every friends[k] is semantically non null
friends: [User] @semanticNonNull(levels: [0, 1])
}
```
`levels` are zero indexed.
Passing a negative level or a level greater than the list dimension is an error.
"""
directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION
"""The judgement made about a skin by a moderator"""
enum Rating {
APPROVED
@ -49,11 +82,11 @@ interface Node {
"""A Winamp skin. Could be modern or classic."""
interface Skin {
"""List of files contained within the skin's .wsz archive"""
archive_files: [ArchiveFile]
archive_files: [ArchiveFile] @semanticNonNull
"""String representation (rgb usually) of the skin's average color"""
average_color: String
"""URL to download the skin"""
download_url: String
download_url: String @semanticNonNull
"""
Filename of skin when uploaded to the Museum. Note: In some cases a skin
has been uploaded under multiple names. Here we just pick one.
@ -64,13 +97,13 @@ interface Skin {
Otherwise, the original user-uploaded file extension will be used.
"""
normalize_extension: Boolean! = false
): String
): String @semanticNonNull
"""GraphQL ID of the skin"""
id: ID!
"""The skin's "item" at archive.org"""
internet_archive_item: InternetArchiveItem
"""MD5 hash of the skin's file"""
md5: String
md5: String @semanticNonNull
"""URL of the skin on the Winamp Skin Museum"""
museum_url: String
"""
@ -83,13 +116,13 @@ interface Skin {
Times that the skin has been reviewed either on the Museum's Tinder-style
review page, or via the Discord bot.
"""
reviews: [Review]
reviews: [Review] @semanticNonNull
"""URL of a screenshot of the skin"""
screenshot_url: String
"""Has the skin been tweeted?"""
tweeted: Boolean
tweeted: Boolean @semanticNonNull
"""List of"""
tweets: [Tweet]
tweets: [Tweet] @semanticNonNull
"""URL of webamp.org with the skin loaded"""
webamp_url: String
}
@ -106,13 +139,13 @@ type ArchiveFile {
The date on the file inside the archive. Given in simplified extended ISO
format (ISO 8601).
"""
date: String
date: String @semanticNonNull
"""The md5 hash of the file within the archive"""
file_md5: String
file_md5: String @semanticNonNull
"""Filename of the file within the archive"""
filename: String
filename: String @semanticNonNull
"""Is the file a directory?"""
is_directory: Boolean
is_directory: Boolean @semanticNonNull
"""
The uncompressed size of the file in bytes.
@ -128,17 +161,17 @@ type ArchiveFile {
serverless Cloudflare function which tries to exctact the file on the fly.
It may not work for all files.
"""
url: String
url: String @semanticNonNull
}
"""A classic Winamp skin"""
type ClassicSkin implements Node & Skin {
"""List of files contained within the skin's .wsz archive"""
archive_files: [ArchiveFile]
archive_files: [ArchiveFile] @semanticNonNull
"""String representation (rgb usually) of the skin's average color"""
average_color: String
"""URL to download the skin"""
download_url: String
download_url: String @semanticNonNull
"""
Filename of skin when uploaded to the Museum. Note: In some cases a skin
has been uploaded under multiple names. Here we just pick one.
@ -149,9 +182,9 @@ type ClassicSkin implements Node & Skin {
Otherwise, the original user-uploaded file extension will be used.
"""
normalize_extension: Boolean! = false
): String
): String @semanticNonNull
"""Does the skin include sprite sheets for the media library?"""
has_media_library: Boolean
has_media_library: Boolean @semanticNonNull
"""GraphQL ID of the skin"""
id: ID!
"""The skin's "item" at archive.org"""
@ -162,7 +195,7 @@ type ClassicSkin implements Node & Skin {
"""
last_algolia_index_update_date: String
"""MD5 hash of the skin's file"""
md5: String
md5: String @semanticNonNull
"""URL of the skin on the Winamp Skin Museum"""
museum_url: String
"""
@ -175,15 +208,15 @@ type ClassicSkin implements Node & Skin {
Times that the skin has been reviewed either on the Museum's Tinder-style
review page, or via the Discord bot.
"""
reviews: [Review]
reviews: [Review] @semanticNonNull
"""URL of a screenshot of the skin"""
screenshot_url: String
"""The number of transparent pixels rendered by the skin."""
transparent_pixels: Int
transparent_pixels: Int @semanticNonNull
"""Has the skin been tweeted?"""
tweeted: Boolean
tweeted: Boolean @semanticNonNull
"""List of"""
tweets: [Tweet]
tweets: [Tweet] @semanticNonNull
"""URL of webamp.org with the skin loaded"""
webamp_url: String
}
@ -196,48 +229,48 @@ type DatabaseStatistics {
**Note:** Skins can be both approved and rejected by different users.
"""
approved_skins_count: Int
approved_skins_count: Int @semanticNonNull
"""
The number of skins that have been marked as NSFW.
**Note:** Skins can be approved and rejected by different users.
**Note:** Generally skins that have been marked NSFW are also marked as rejected.
"""
nsfw_skins_count: Int
nsfw_skins_count: Int @semanticNonNull
"""
The number of skins that have been rejected for tweeting.
**Note:** Skins can be both approved and rejected by different users.
**Note:** Generally skins that have been marked NSFW are also marked as rejected.
"""
rejected_skins_count: Int
rejected_skins_count: Int @semanticNonNull
"""
The number of skins that have been approved for tweeting, but not yet tweeted.
"""
tweetable_skins_count: Int
tweetable_skins_count: Int @semanticNonNull
"""The number of skins in the Museum that have been tweeted by"""
tweeted_skins_count: Int
tweeted_skins_count: Int @semanticNonNull
"""The total number of classic skins in the Museum's database"""
unique_classic_skins_count: Int
unique_classic_skins_count: Int @semanticNonNull
"""The number of skins that have never been reviewed."""
unreviewed_skins_count: Int
unreviewed_skins_count: Int @semanticNonNull
"""Skins uploads that have errored during processing."""
uploads_in_error_state_count: Int
uploads_in_error_state_count: Int @semanticNonNull
"""
Skins uplaods awaiting processing. This can happen when there are a large
number of skin uplaods at the same time, or when the skin uploading processing
pipeline gets stuck.
"""
uploads_pending_processing_count: Int
uploads_pending_processing_count: Int @semanticNonNull
"""
Number of skins that have been uploaded to the Museum via the web interface.
"""
web_uploads_count: Int
web_uploads_count: Int @semanticNonNull
}
type InternetArchiveItem {
"""The Internet Archive's unique identifier for this item"""
identifier: String
identifier: String @semanticNonNull
"""
The date and time that we last scraped this item's metadata.
**Note:** This field is temporary and will be removed in the future.
@ -245,7 +278,7 @@ type InternetArchiveItem {
"""
last_metadata_scrape_date_UNSTABLE: String
"""URL to get the Internet Archive's metadata for this item in JSON form."""
metadata_url: String
metadata_url: String @semanticNonNull
"""
Our cached version of the metadata available at \`metadata_url\` (above)
"""
@ -253,7 +286,7 @@ type InternetArchiveItem {
"""The skin that this item contains"""
skin: Skin
"""The URL where this item can be viewed on the Internet Archive"""
url: String
url: String @semanticNonNull
}
"""
@ -264,11 +297,11 @@ which are currently called just `Skin` in this schema.
"""
type ModernSkin implements Node & Skin {
"""List of files contained within the skin's .wsz archive"""
archive_files: [ArchiveFile]
archive_files: [ArchiveFile] @semanticNonNull
"""String representation (rgb usually) of the skin's average color"""
average_color: String
"""URL to download the skin"""
download_url: String
download_url: String @semanticNonNull
"""
Filename of skin when uploaded to the Museum. Note: In some cases a skin
has been uploaded under multiple names. Here we just pick one.
@ -279,13 +312,13 @@ type ModernSkin implements Node & Skin {
Otherwise, the original user-uploaded file extension will be used.
"""
normalize_extension: Boolean! = false
): String
): String @semanticNonNull
"""GraphQL ID of the skin"""
id: ID!
"""The skin's "item" at archive.org"""
internet_archive_item: InternetArchiveItem
"""MD5 hash of the skin's file"""
md5: String
md5: String @semanticNonNull
"""URL of the skin on the Winamp Skin Museum"""
museum_url: String
"""
@ -298,13 +331,13 @@ type ModernSkin implements Node & Skin {
Times that the skin has been reviewed either on the Museum's Tinder-style
review page, or via the Discord bot.
"""
reviews: [Review]
reviews: [Review] @semanticNonNull
"""URL of a screenshot of the skin"""
screenshot_url: String
"""Has the skin been tweeted?"""
tweeted: Boolean
tweeted: Boolean @semanticNonNull
"""List of"""
tweets: [Tweet]
tweets: [Tweet] @semanticNonNull
"""URL of webamp.org with the skin loaded"""
webamp_url: String
}
@ -312,9 +345,9 @@ type ModernSkin implements Node & Skin {
"""A collection of "modern" Winamp skins"""
type ModernSkinsConnection {
"""The total number of skins matching the filter"""
count: Int
count: Int @semanticNonNull
"""The list of skins"""
nodes: [ModernSkin]
nodes: [ModernSkin] @semanticNonNull
}
type Mutation {
@ -323,31 +356,31 @@ type Mutation {
**Note:** Requires being logged in
"""
approve_skin(md5: String!): Boolean
approve_skin(md5: String!): Boolean @semanticNonNull
"""
Mark a skin as NSFW
**Note:** Requires being logged in
"""
mark_skin_nsfw(md5: String!): Boolean
mark_skin_nsfw(md5: String!): Boolean @semanticNonNull
"""
Reject skin for tweeting
**Note:** Requires being logged in
"""
reject_skin(md5: String!): Boolean
reject_skin(md5: String!): Boolean @semanticNonNull
"""
Request that an admin check if this skin is NSFW.
Unlike other review mutation endpoints, this one does not require being logged
in.
"""
request_nsfw_review_for_skin(md5: String!): Boolean
request_nsfw_review_for_skin(md5: String!): Boolean @semanticNonNull
"""
Send a message to the admin of the site. Currently this appears in Discord.
"""
send_feedback(email: String, message: String!, url: String): Boolean
send_feedback(email: String, message: String!, url: String): Boolean @semanticNonNull
"""Mutations for the upload flow"""
upload: UploadMutations
upload: UploadMutations @semanticNonNull
}
type Query {
@ -370,7 +403,7 @@ type Query {
"""The currently authenticated user, if any."""
me: User
"""All modern skins in the database"""
modern_skins(first: Int! = 10, offset: Int! = 0): ModernSkinsConnection
modern_skins(first: Int! = 10, offset: Int! = 0): ModernSkinsConnection @semanticNonNull
"""
Get a globally unique object by its ID.
@ -382,7 +415,7 @@ type Query {
Useful for locating a particular skin.
"""
search_skins(first: Int! = 10, offset: Int! = 0, query: String!): [Skin]
search_skins(first: Int! = 10, offset: Int! = 0, query: String!): [Skin] @semanticNonNull
"""A random skin that needs to be reviewed"""
skin_to_review: Skin
"""
@ -390,15 +423,15 @@ type Query {
**Note:** We don't currently support combining sorting and filtering.
"""
skins(filter: SkinsFilterOption, first: Int! = 10, offset: Int! = 0, sort: SkinsSortOption): SkinsConnection
skins(filter: SkinsFilterOption, first: Int! = 10, offset: Int! = 0, sort: SkinsSortOption): SkinsConnection @semanticNonNull
"""A namespace for statistics about the database"""
statistics: DatabaseStatistics
statistics: DatabaseStatistics @semanticNonNull
"""Tweets tweeted by"""
tweets(first: Int! = 10, offset: Int! = 0, sort: TweetsSortOption): TweetsConnection
tweets(first: Int! = 10, offset: Int! = 0, sort: TweetsSortOption): TweetsConnection @semanticNonNull
"""Get the status of a batch of uploads by ids"""
upload_statuses(ids: [String!]!): [SkinUpload]
upload_statuses(ids: [String!]!): [SkinUpload] @semanticNonNull
"""Get the status of a batch of uploads by md5s"""
upload_statuses_by_md5(md5s: [String!]!): [SkinUpload] @deprecated(reason: "Prefer `upload_statuses` instead, were we operate on ids.")
upload_statuses_by_md5(md5s: [String!]!): [SkinUpload] @deprecated(reason: "Prefer `upload_statuses` instead, were we operate on ids.") @semanticNonNull
}
"""
@ -407,35 +440,35 @@ reivew page, or via the Discord bot.
"""
type Review {
"""The rating that the user gave the skin"""
rating: Rating
rating: Rating @semanticNonNull
"""
The user who made the review (if known). **Note:** In the early days we didn't
track this, so many will be null.
"""
reviewer: String
reviewer: String @semanticNonNull
"""The skin that was reviewed"""
skin: Skin
}
"""Information about an attempt to upload a skin to the Museum."""
type SkinUpload {
id: String
id: String @semanticNonNull
"""
Skin that was uploaded. **Note:** This is null if the skin has not yet been
fully processed. (status == ARCHIVED)
"""
skin: Skin
status: SkinUploadStatus
status: SkinUploadStatus @semanticNonNull
"""Md5 hash given when requesting the upload URL."""
upload_md5: String
upload_md5: String @semanticNonNull
}
"""A collection of classic Winamp skins"""
type SkinsConnection {
"""The total number of skins matching the filter"""
count: Int
count: Int @semanticNonNull
"""The list of skins"""
nodes: [Skin]
nodes: [Skin] @semanticNonNull
}
"""A tweet made by"""
@ -443,11 +476,11 @@ type Tweet {
"""
Number of likes the tweet has received. Updated nightly. (Note: Recent likes on older tweets may not be reflected here)
"""
likes: Int
likes: Int @semanticNonNull
"""
Number of retweets the tweet has received. Updated nightly. (Note: Recent retweets on older tweets may not be reflected here)
"""
retweets: Int
retweets: Int @semanticNonNull
"""The skin featured in this Tweet"""
skin: Skin
"""
@ -461,9 +494,9 @@ type Tweet {
"""A collection of tweets made by the"""
type TweetsConnection {
"""The total number of tweets"""
count: Int
count: Int @semanticNonNull
"""The list of tweets"""
nodes: [Tweet]
nodes: [Tweet] @semanticNonNull
}
"""
@ -482,9 +515,9 @@ type UploadMutations {
UploadUrl is not returned for a given hash, it means the file is already in
the collection.
"""
get_upload_urls(files: [UploadUrlRequest!]!): [UploadUrl]
get_upload_urls(files: [UploadUrlRequest!]!): [UploadUrl] @semanticNonNull
"""Notify the server that the user is done uploading."""
report_skin_uploaded(id: String!, md5: String!): Boolean
report_skin_uploaded(id: String!, md5: String!): Boolean @semanticNonNull
}
"""
@ -492,9 +525,9 @@ A URL that the client can use to upload a skin to S3, and then notify the server
when they're done.
"""
type UploadUrl {
id: String
md5: String
url: String
id: String @semanticNonNull
md5: String @semanticNonNull
url: String @semanticNonNull
}
type User {

View file

@ -52,7 +52,13 @@ import { screenshot_url as classicSkinScreenshot_urlResolver } from "./resolvers
import { tweeted as classicSkinTweetedResolver } from "./resolvers/CommonSkinResolver";
import { tweets as classicSkinTweetsResolver } from "./resolvers/CommonSkinResolver";
import { webamp_url as classicSkinWebamp_urlResolver } from "./resolvers/CommonSkinResolver";
import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLID, GraphQLEnumType, GraphQLInputObjectType } from "graphql";
import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLID, GraphQLEnumType, defaultFieldResolver, GraphQLInputObjectType } from "graphql";
async function assertNonNull<T>(value: T | Promise<T>): Promise<T> {
const awaited = await value;
if (awaited == null)
throw new Error("Cannot return null for semantically non-nullable field.");
return awaited;
}
export function getSchema(): GraphQLSchema {
const InternetArchiveItemType: GraphQLObjectType = new GraphQLObjectType({
name: "InternetArchiveItem",
@ -63,7 +69,7 @@ export function getSchema(): GraphQLSchema {
name: "identifier",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getIdentifier(source, args, context, info);
return assertNonNull(source.getIdentifier(source, args, context, info));
}
},
last_metadata_scrape_date_UNSTABLE: {
@ -79,7 +85,7 @@ export function getSchema(): GraphQLSchema {
name: "metadata_url",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getMetadataUrl(source, args, context, info);
return assertNonNull(source.getMetadataUrl(source, args, context, info));
}
},
raw_metadata_json: {
@ -100,7 +106,7 @@ export function getSchema(): GraphQLSchema {
name: "url",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getUrl(source, args, context, info);
return assertNonNull(source.getUrl(source, args, context, info));
}
}
};
@ -129,12 +135,18 @@ export function getSchema(): GraphQLSchema {
rating: {
description: "The rating that the user gave the skin",
name: "rating",
type: RatingType
type: RatingType,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
reviewer: {
description: "The user who made the review (if known). **Note:** In the early days we didn't\ntrack this, so many will be null.",
name: "reviewer",
type: GraphQLString
type: GraphQLString,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
skin: {
description: "The skin that was reviewed",
@ -154,7 +166,7 @@ export function getSchema(): GraphQLSchema {
name: "likes",
type: GraphQLInt,
resolve(source, args, context, info) {
return source.getLikes(source, args, context, info);
return assertNonNull(source.getLikes(source, args, context, info));
}
},
retweets: {
@ -162,7 +174,7 @@ export function getSchema(): GraphQLSchema {
name: "retweets",
type: GraphQLInt,
resolve(source, args, context, info) {
return source.getRetweets(source, args, context, info);
return assertNonNull(source.getRetweets(source, args, context, info));
}
},
skin: {
@ -282,7 +294,7 @@ export function getSchema(): GraphQLSchema {
name: "date",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getIsoDate(source, args, context, info);
return assertNonNull(source.getIsoDate(source, args, context, info));
}
},
file_md5: {
@ -290,7 +302,7 @@ export function getSchema(): GraphQLSchema {
name: "file_md5",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getFileMd5(source, args, context, info);
return assertNonNull(source.getFileMd5(source, args, context, info));
}
},
filename: {
@ -298,7 +310,7 @@ export function getSchema(): GraphQLSchema {
name: "filename",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getFileName(source, args, context, info);
return assertNonNull(source.getFileName(source, args, context, info));
}
},
is_directory: {
@ -306,7 +318,7 @@ export function getSchema(): GraphQLSchema {
name: "is_directory",
type: GraphQLBoolean,
resolve(source, args, context, info) {
return source.getIsDirectory(source, args, context, info);
return assertNonNull(source.getIsDirectory(source, args, context, info));
}
},
size: {
@ -335,7 +347,7 @@ export function getSchema(): GraphQLSchema {
name: "url",
type: GraphQLString,
resolve(source, args, context, info) {
return source.getUrl(source, args, context, info);
return assertNonNull(source.getUrl(source, args, context, info));
}
}
};
@ -374,7 +386,7 @@ export function getSchema(): GraphQLSchema {
name: "archive_files",
type: new GraphQLList(ArchiveFileType),
resolve(source) {
return modernSkinArchive_filesResolver(source);
return assertNonNull(modernSkinArchive_filesResolver(source));
}
},
average_color: {
@ -390,7 +402,7 @@ export function getSchema(): GraphQLSchema {
name: "download_url",
type: GraphQLString,
resolve(source) {
return modernSkinDownload_urlResolver(source);
return assertNonNull(modernSkinDownload_urlResolver(source));
}
},
filename: {
@ -406,7 +418,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args) {
return modernSkinFilenameResolver(source, args);
return assertNonNull(modernSkinFilenameResolver(source, args));
}
},
id: {
@ -430,7 +442,7 @@ export function getSchema(): GraphQLSchema {
name: "md5",
type: GraphQLString,
resolve(source) {
return modernSkinMd5Resolver(source);
return assertNonNull(modernSkinMd5Resolver(source));
}
},
museum_url: {
@ -462,7 +474,7 @@ export function getSchema(): GraphQLSchema {
name: "reviews",
type: new GraphQLList(ReviewType),
resolve(source) {
return modernSkinReviewsResolver(source);
return assertNonNull(modernSkinReviewsResolver(source));
}
},
screenshot_url: {
@ -478,7 +490,7 @@ export function getSchema(): GraphQLSchema {
name: "tweeted",
type: GraphQLBoolean,
resolve(source) {
return modernSkinTweetedResolver(source);
return assertNonNull(modernSkinTweetedResolver(source));
}
},
tweets: {
@ -486,7 +498,7 @@ export function getSchema(): GraphQLSchema {
name: "tweets",
type: new GraphQLList(TweetType),
resolve(source) {
return modernSkinTweetsResolver(source);
return assertNonNull(modernSkinTweetsResolver(source));
}
},
webamp_url: {
@ -511,12 +523,18 @@ export function getSchema(): GraphQLSchema {
count: {
description: "The total number of skins matching the filter",
name: "count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
nodes: {
description: "The list of skins",
name: "nodes",
type: new GraphQLList(ModernSkinType)
type: new GraphQLList(ModernSkinType),
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
}
@ -529,12 +547,18 @@ export function getSchema(): GraphQLSchema {
count: {
description: "The total number of skins matching the filter",
name: "count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
nodes: {
description: "The list of skins",
name: "nodes",
type: new GraphQLList(SkinType)
type: new GraphQLList(SkinType),
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
}
@ -572,52 +596,82 @@ export function getSchema(): GraphQLSchema {
approved_skins_count: {
description: "The number of skins that have been approved for tweeting. This includes both\ntweeted and untweeted skins.\n\n**Note:** Skins can be both approved and rejected by different users.",
name: "approved_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
nsfw_skins_count: {
description: "The number of skins that have been marked as NSFW.\n\n**Note:** Skins can be approved and rejected by different users.\n**Note:** Generally skins that have been marked NSFW are also marked as rejected.",
name: "nsfw_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
rejected_skins_count: {
description: "The number of skins that have been rejected for tweeting.\n\n**Note:** Skins can be both approved and rejected by different users.\n**Note:** Generally skins that have been marked NSFW are also marked as rejected.",
name: "rejected_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
tweetable_skins_count: {
description: "The number of skins that have been approved for tweeting, but not yet tweeted.",
name: "tweetable_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
tweeted_skins_count: {
description: "The number of skins in the Museum that have been tweeted by",
name: "tweeted_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
unique_classic_skins_count: {
description: "The total number of classic skins in the Museum's database",
name: "unique_classic_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
unreviewed_skins_count: {
description: "The number of skins that have never been reviewed.",
name: "unreviewed_skins_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
uploads_in_error_state_count: {
description: "Skins uploads that have errored during processing.",
name: "uploads_in_error_state_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
uploads_pending_processing_count: {
description: "Skins uplaods awaiting processing. This can happen when there are a large\nnumber of skin uplaods at the same time, or when the skin uploading processing\npipeline gets stuck.",
name: "uploads_pending_processing_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
web_uploads_count: {
description: "Number of skins that have been uploaded to the Museum via the web interface.",
name: "web_uploads_count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
}
@ -630,12 +684,18 @@ export function getSchema(): GraphQLSchema {
count: {
description: "The total number of tweets",
name: "count",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
nodes: {
description: "The list of tweets",
name: "nodes",
type: new GraphQLList(TweetType)
type: new GraphQLList(TweetType),
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
}
@ -679,7 +739,10 @@ export function getSchema(): GraphQLSchema {
return {
id: {
name: "id",
type: GraphQLString
type: GraphQLString,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
skin: {
description: "Skin that was uploaded. **Note:** This is null if the skin has not yet been\nfully processed. (status == ARCHIVED)",
@ -688,12 +751,18 @@ export function getSchema(): GraphQLSchema {
},
status: {
name: "status",
type: SkinUploadStatusType
type: SkinUploadStatusType,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
upload_md5: {
description: "Md5 hash given when requesting the upload URL.",
name: "upload_md5",
type: GraphQLString
type: GraphQLString,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
}
@ -783,7 +852,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args) {
return queryModern_skinsResolver(source, args);
return assertNonNull(queryModern_skinsResolver(source, args));
}
},
node: {
@ -821,7 +890,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return querySearch_skinsResolver(source, args, context);
return assertNonNull(querySearch_skinsResolver(source, args, context));
}
},
skin_to_review: {
@ -857,7 +926,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args) {
return querySkinsResolver(source, args);
return assertNonNull(querySkinsResolver(source, args));
}
},
statistics: {
@ -865,7 +934,7 @@ export function getSchema(): GraphQLSchema {
name: "statistics",
type: DatabaseStatisticsType,
resolve(source) {
return queryStatisticsResolver(source);
return assertNonNull(queryStatisticsResolver(source));
}
},
tweets: {
@ -889,7 +958,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args) {
return queryTweetsResolver(source, args);
return assertNonNull(queryTweetsResolver(source, args));
}
},
upload_statuses: {
@ -903,7 +972,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return queryUpload_statusesResolver(source, args, context);
return assertNonNull(queryUpload_statusesResolver(source, args, context));
}
},
upload_statuses_by_md5: {
@ -918,7 +987,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return queryUpload_statuses_by_md5Resolver(source, args, context);
return assertNonNull(queryUpload_statuses_by_md5Resolver(source, args, context));
}
}
};
@ -931,15 +1000,24 @@ export function getSchema(): GraphQLSchema {
return {
id: {
name: "id",
type: GraphQLString
type: GraphQLString,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
md5: {
name: "md5",
type: GraphQLString
type: GraphQLString,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
url: {
name: "url",
type: GraphQLString
type: GraphQLString,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
}
@ -974,6 +1052,9 @@ export function getSchema(): GraphQLSchema {
name: "files",
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(UploadUrlRequestType)))
}
},
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
report_skin_uploaded: {
@ -989,6 +1070,9 @@ export function getSchema(): GraphQLSchema {
name: "md5",
type: new GraphQLNonNull(GraphQLString)
}
},
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
}
};
@ -1009,7 +1093,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return mutationApprove_skinResolver(source, args, context);
return assertNonNull(mutationApprove_skinResolver(source, args, context));
}
},
mark_skin_nsfw: {
@ -1023,7 +1107,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return mutationMark_skin_nsfwResolver(source, args, context);
return assertNonNull(mutationMark_skin_nsfwResolver(source, args, context));
}
},
reject_skin: {
@ -1037,7 +1121,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return mutationReject_skinResolver(source, args, context);
return assertNonNull(mutationReject_skinResolver(source, args, context));
}
},
request_nsfw_review_for_skin: {
@ -1051,7 +1135,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return mutationRequest_nsfw_review_for_skinResolver(source, args, context);
return assertNonNull(mutationRequest_nsfw_review_for_skinResolver(source, args, context));
}
},
send_feedback: {
@ -1073,7 +1157,7 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args, context) {
return mutationSend_feedbackResolver(source, args, context);
return assertNonNull(mutationSend_feedbackResolver(source, args, context));
}
},
upload: {
@ -1081,7 +1165,7 @@ export function getSchema(): GraphQLSchema {
name: "upload",
type: UploadMutationsType,
resolve(source) {
return mutationUploadResolver(source);
return assertNonNull(mutationUploadResolver(source));
}
}
};
@ -1097,7 +1181,7 @@ export function getSchema(): GraphQLSchema {
name: "archive_files",
type: new GraphQLList(ArchiveFileType),
resolve(source) {
return classicSkinArchive_filesResolver(source);
return assertNonNull(classicSkinArchive_filesResolver(source));
}
},
average_color: {
@ -1113,7 +1197,7 @@ export function getSchema(): GraphQLSchema {
name: "download_url",
type: GraphQLString,
resolve(source) {
return classicSkinDownload_urlResolver(source);
return assertNonNull(classicSkinDownload_urlResolver(source));
}
},
filename: {
@ -1129,13 +1213,16 @@ export function getSchema(): GraphQLSchema {
}
},
resolve(source, args) {
return classicSkinFilenameResolver(source, args);
return assertNonNull(classicSkinFilenameResolver(source, args));
}
},
has_media_library: {
description: "Does the skin include sprite sheets for the media library?",
name: "has_media_library",
type: GraphQLBoolean
type: GraphQLBoolean,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
id: {
description: "GraphQL ID of the skin",
@ -1163,7 +1250,7 @@ export function getSchema(): GraphQLSchema {
name: "md5",
type: GraphQLString,
resolve(source) {
return classicSkinMd5Resolver(source);
return assertNonNull(classicSkinMd5Resolver(source));
}
},
museum_url: {
@ -1195,7 +1282,7 @@ export function getSchema(): GraphQLSchema {
name: "reviews",
type: new GraphQLList(ReviewType),
resolve(source) {
return classicSkinReviewsResolver(source);
return assertNonNull(classicSkinReviewsResolver(source));
}
},
screenshot_url: {
@ -1209,14 +1296,17 @@ export function getSchema(): GraphQLSchema {
transparent_pixels: {
description: "The number of transparent pixels rendered by the skin.",
name: "transparent_pixels",
type: GraphQLInt
type: GraphQLInt,
resolve(source, args, context, info) {
return assertNonNull(defaultFieldResolver(source, args, context, info));
}
},
tweeted: {
description: "Has the skin been tweeted?",
name: "tweeted",
type: GraphQLBoolean,
resolve(source) {
return classicSkinTweetedResolver(source);
return assertNonNull(classicSkinTweetedResolver(source));
}
},
tweets: {
@ -1224,7 +1314,7 @@ export function getSchema(): GraphQLSchema {
name: "tweets",
type: new GraphQLList(TweetType),
resolve(source) {
return classicSkinTweetsResolver(source);
return assertNonNull(classicSkinTweetsResolver(source));
}
},
webamp_url: {

View file

@ -65,7 +65,7 @@
"@types/supertest": "^2.0.10",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"grats": "^0.0.23",
"grats": "^0.0.25",
"supertest": "^6.0.1",
"typescript": "^5.3.3"
},

View file

@ -2,7 +2,8 @@
"grats": {
"nullableByDefault": true,
"graphqlSchema": "./api/graphql/schema.graphql",
"tsSchema": "./api/graphql/schema.ts"
"tsSchema": "./api/graphql/schema.ts",
"strictSemanticNullability": true
},
"compilerOptions": {
"plugins": [{ "name": "grats-ts-plugin" }],

21513
yarn.lock

File diff suppressed because it is too large Load diff