Annotations for supermassive v3 ast (#359)

* Remove supermassive-ast

* Change files

* Add to def

* Address review comments
This commit is contained in:
Mikhail Novikov 2023-09-27 10:42:01 +02:00 коммит произвёл GitHub
Родитель 1babca8d4f
Коммит 04e7dffa35
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 471 добавлений и 291 удалений

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Support supermassive v3 annotations",
"packageName": "@graphitation/apollo-react-relay-duct-tape-compiler",
"email": "mnovikov@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Support supermassive v3 annotations",
"packageName": "@graphitation/graphql-codegen-supermassive-typed-document-node-plugin",
"email": "mnovikov@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add supermassive v3 annotations",
"packageName": "@graphitation/supermassive",
"email": "mnovikov@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -38,7 +38,7 @@
"devDependencies": {
"@graphitation/apollo-react-relay-duct-tape-compiler": "^1.2.4",
"@graphitation/embedded-document-artefact-loader": "^0.6.4",
"@graphitation/supermassive-ast": "^2.0.1",
"@graphitation/supermassive": "^3.0.1",
"@graphql-codegen/cli": "2.2.0",
"@graphql-codegen/typescript": "2.2.2",
"@graphql-codegen/typescript-resolvers": "^2.2.1",

Просмотреть файл

@ -41,7 +41,7 @@
},
"peerDependencies": {
"graphql": "^15.0.0",
"@graphitation/supermassive-ast": "^2.0.1",
"@graphitation/supermassive": "^3.0.1",
"typescript": "^4.3.5"
},
"publishConfig": {

Просмотреть файл

@ -219,6 +219,93 @@ describe("formatModule", () => {
`);
});
it("adds supermassive MVS to the execution doc", async () => {
expect(
await formatModule(
{
emitDocuments: true,
emitSupermassiveDocuments: true,
emitNarrowObservables: false,
supermassiveDocumentNodeOutputType: "V3",
},
{
definition: {
kind: "Request",
} as Request,
typeText: `
export type MessageComponent_message = {
id: string;
};
`,
docText: `
fragment MessageComponent_message on Message {
id
}
`,
},
),
).toMatchInlineSnapshot(`
"/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
export type MessageComponent_message = {
id: string;
};
export const documents: import("@graphitation/apollo-react-relay-duct-tape-compiler").CompiledArtefactModule = {
"executionQueryDocument": {
"kind": "Document",
"definitions": [
{
"kind": "FragmentDefinition",
"name": {
"kind": "Name",
"value": "MessageComponent_message"
},
"typeCondition": {
"kind": "NamedType",
"name": {
"kind": "Name",
"value": "Message"
}
},
"selectionSet": {
"kind": "SelectionSet",
"selections": [
{
"kind": "Field",
"name": {
"kind": "Name",
"value": "id"
}
}
]
},
"__defs": {
"types": {
"Message": [
2,
{
"id": 10
},
[
"Node"
]
]
}
}
}
]
}
};
export default documents;"
`);
});
it("also prints the watch query doc when emitting narrow observables", async () => {
expect(
await formatModule(

Просмотреть файл

@ -105,6 +105,23 @@ async function main() {
default: false,
type: "boolean",
},
supermassiveDocumentNodeOutputType: {
demandOption: false,
default: "V2",
type: "string",
coerce: (value) => {
switch (value) {
case "V2":
return "V2";
case "V3":
return "V3";
case "BOTH":
return "BOTH";
default:
return "V2";
}
},
},
})
.help().argv;

Просмотреть файл

@ -8,16 +8,19 @@ import { buildSchema, Source } from "graphql";
import { readFileSync } from "fs";
import dedupeJSONStringify from "relay-compiler/lib/util/dedupeJSONStringify";
import type { DocumentNode } from "graphql";
import type { DocumentNode, GraphQLSchema } from "graphql";
import type { FormatModule } from "relay-compiler/lib/language/RelayLanguagePluginInterface";
import type { CompiledArtefactModule } from "./types";
import { Fragment } from "relay-compiler";
export type SupermassiveOutputType = "V3" | "V2" | "BOTH";
export interface FormatModuleOptions {
emitDocuments: boolean;
emitNarrowObservables: boolean;
emitQueryDebugComments: boolean;
emitSupermassiveDocuments: boolean;
supermassiveDocumentNodeOutputType: SupermassiveOutputType;
schema: string;
}
@ -35,13 +38,17 @@ export async function formatModuleFactory(
)
: null;
let addTypesToRequestDocument:
let addSupermassiveLegacyTypesToRequestDocument:
| undefined
| typeof import("@graphitation/supermassive-ast").addTypesToRequestDocument;
| typeof import("@graphitation/supermassive").addSupermassiveLegacyTypesToRequestDocument;
let addMinimalViableSchemaToRequestDocument:
| undefined
| typeof import("@graphitation/supermassive").addMinimalViableSchemaToRequestDocument;
if (options.emitSupermassiveDocuments) {
({ addTypesToRequestDocument } = await import(
"@graphitation/supermassive-ast"
));
({
addSupermassiveLegacyTypesToRequestDocument,
addMinimalViableSchemaToRequestDocument,
} = await import("@graphitation/supermassive"));
}
function generateExports(
@ -70,11 +77,14 @@ export async function formatModuleFactory(
exports.metadata = extractMetadataTransform(exports.watchQueryDocument);
}
if (addTypesToRequestDocument && exports.executionQueryDocument) {
if (options.emitSupermassiveDocuments && exports.executionQueryDocument) {
invariant(schema, "Expected a schema instance");
exports.executionQueryDocument = addTypesToRequestDocument(
schema,
exports.executionQueryDocument,
options.supermassiveDocumentNodeOutputType,
addMinimalViableSchemaToRequestDocument,
addSupermassiveLegacyTypesToRequestDocument,
) as DocumentNode;
}
@ -143,3 +153,33 @@ function printExports(exports: CompiledArtefactModule) {
exports,
)};\n\nexport default documents;`;
}
function addTypesToRequestDocument(
schema: GraphQLSchema,
document: DocumentNode,
supermassiveDocumentNodeOutputType: SupermassiveOutputType,
addMinimalViableSchemaToRequestDocument: any,
addSupermassiveLegacyTypesToRequestDocument: any,
) {
let finalDocument = document;
if (
supermassiveDocumentNodeOutputType === "V3" ||
supermassiveDocumentNodeOutputType === "BOTH"
) {
finalDocument = addMinimalViableSchemaToRequestDocument(schema, document, {
addTo: "PROPERTY",
});
}
if (
supermassiveDocumentNodeOutputType === "V2" ||
supermassiveDocumentNodeOutputType === "BOTH" ||
!supermassiveDocumentNodeOutputType
) {
finalDocument = addSupermassiveLegacyTypesToRequestDocument(
schema,
document,
) as unknown as DocumentNode;
}
return finalDocument;
}

Просмотреть файл

@ -28,7 +28,7 @@
"@graphql-codegen/visitor-plugin-common": ">= ^1.17.0 < 2",
"graphql-tag": ">= 2.11.0 < 3",
"@graphql-tools/optimize": "^1.0.1",
"@graphitation/supermassive-ast": "^2.0.1"
"@graphitation/supermassive": "^3.0.1"
},
"sideEffects": false,
"access": "public",

Просмотреть файл

@ -20,15 +20,22 @@ import {
Kind,
OperationDefinitionNode,
} from "graphql";
import { addTypesToRequestDocument } from "@graphitation/supermassive-ast";
import {
addSupermassiveLegacyTypesToRequestDocument,
addMinimalViableSchemaToRequestDocument,
} from "@graphitation/supermassive";
import { optimizeDocumentNode } from "@graphql-tools/optimize";
import gqlTag from "graphql-tag";
export type SupermassiveOutputType = "V3" | "V2" | "BOTH";
type RawClientSidePluginConfig = RawClientSideBasePluginConfig & {
supermassiveDocumentNodeConditional?: string;
supermassiveDocumentNodeOutputType?: SupermassiveOutputType;
};
type ClientSidePluginConfig = ClientSideBasePluginConfig & {
supermassiveDocumentNodeConditional?: string;
supermassiveDocumentNodeOutputType?: SupermassiveOutputType;
};
export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
@ -53,6 +60,8 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
{
supermassiveDocumentNodeConditional:
rawConfig.supermassiveDocumentNodeConditional,
supermassiveDocumentNodeOutputType:
rawConfig.supermassiveDocumentNodeOutputType || "V3",
},
documents,
);
@ -88,7 +97,7 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
node: FragmentDefinitionNode | OperationDefinitionNode,
annotate = false,
): string {
const supermassiveNode = addTypesToRequestDocument(this._schema, {
const supermassiveNode = this.addTypesToRequestDocument(this._schema, {
kind: Kind.DOCUMENT,
definitions: [node],
}).definitions[0] as FragmentDefinitionNode | OperationDefinitionNode;
@ -128,7 +137,7 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
...gqlObj.definitions.map((t) =>
JSON.stringify(
annotate
? addTypesToRequestDocument(this._schema, {
? this.addTypesToRequestDocument(this._schema, {
kind: Kind.DOCUMENT,
definitions: [t],
}).definitions[0]
@ -159,7 +168,7 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
...document,
definitions: document.definitions.map(
(t) =>
addTypesToRequestDocument(this._schema, {
this.addTypesToRequestDocument(this._schema, {
kind: Kind.DOCUMENT,
definitions: [t],
}).definitions[0],
@ -181,4 +190,34 @@ export class TypeScriptDocumentNodesVisitor extends ClientSideBaseVisitor<
return super.getDocumentNodeSignature(resultType, variablesTypes, node);
}
private addTypesToRequestDocument(
schema: GraphQLSchema,
document: DocumentNode,
) {
let finalDocument = document;
if (
this.config.supermassiveDocumentNodeOutputType === "V3" ||
this.config.supermassiveDocumentNodeOutputType === "BOTH"
) {
finalDocument = addMinimalViableSchemaToRequestDocument(
schema,
document,
{
addTo: "PROPERTY",
},
);
}
if (
this.config.supermassiveDocumentNodeOutputType === "V2" ||
this.config.supermassiveDocumentNodeOutputType === "BOTH"
) {
finalDocument = addSupermassiveLegacyTypesToRequestDocument(
schema,
document,
) as unknown as DocumentNode;
}
return finalDocument;
}
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"extends": ["../../.eslintrc.json"],
"root": true
}

Просмотреть файл

@ -1,35 +0,0 @@
{
"name": "@graphitation/supermassive-ast",
"entries": [
{
"date": "Thu, 21 Sep 2023 06:28:45 GMT",
"tag": "@graphitation/supermassive-ast_v2.0.1",
"version": "2.0.1",
"comments": {
"patch": [
{
"author": "sverre.johansen@gmail.com",
"package": "@graphitation/supermassive-ast",
"commit": "9faf12099c9af82b4e353e84fcee78e0659fb919",
"comment": "Add exports entry for types to package.json"
}
]
}
},
{
"date": "Mon, 19 Jun 2023 12:22:22 GMT",
"tag": "@graphitation/supermassive-ast_v2.0.0",
"version": "2.0.0",
"comments": {
"major": [
{
"author": "mnovikov@microsoft.com",
"package": "@graphitation/supermassive-ast",
"commit": "77593c97a1aeb72bcdbb095fe9fd803836517fe2",
"comment": "Separate ast annotator from supermassive"
}
]
}
}
]
}

Просмотреть файл

@ -1,21 +0,0 @@
# Change Log - @graphitation/supermassive-ast
This log was last generated on Thu, 21 Sep 2023 06:28:45 GMT and should not be manually modified.
<!-- Start content -->
## 2.0.1
Thu, 21 Sep 2023 06:28:45 GMT
### Patches
- Add exports entry for types to package.json (sverre.johansen@gmail.com)
## 2.0.0
Mon, 19 Jun 2023 12:22:22 GMT
### Major changes
- Separate ast annotator from supermassive (mnovikov@microsoft.com)

Просмотреть файл

@ -1,47 +0,0 @@
# @graphitation/supermassive-ast
AST definitions and AST transform for supermassive. Annotates a document so a supermassive can execute it without runtime schema.
## Transform
`addTypesToRequestDocument` converts untyped graphql-js AST node into a Supermassive typed one.
```js
function addTypesToRequestDocument(
schema: GraphQLSchema,
document: TypelessAST.DocumentNode
): TypedAST.DocumentNode
```
With `@graphitation/graphql-js-tag` and `@graphitation/ts-transform-graphql-js-tag` (in webpack config)
```js
import { buildASTSchema } from 'graphql'
import { getTransformer } from "@graphitation/ts-transform-graphql-js-tag";
import { annotateDocumentGraphQLTransform } from "@graphitation/supermassive";
// ...
{
test: /\.tsx?$/,
loader: "ts-loader",
options: {
getCustomTransformers: () => ({
before: [
getTransformer({
graphqlTagModuleExport: "graphql",
transformer: annotateDocumentGraphQLTransform(
buildASTSchema({
fs.readFileSync(
"PATH_TO_SCHEMA_TYPEDEFS.graphql",
{ encoding: "utf-8" }
),
)
),
}),
],
}),
},
},
}
```

Просмотреть файл

@ -1,45 +0,0 @@
{
"name": "@graphitation/supermassive-ast",
"license": "MIT",
"version": "2.0.1",
"main": "./src/index.ts",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/graphitation.git",
"directory": "packages/supermassive-ast"
},
"scripts": {
"build": "monorepo-scripts build",
"lint": "monorepo-scripts lint",
"test": "monorepo-scripts test",
"types": "monorepo-scripts types",
"just": "monorepo-scripts"
},
"dependencies": {},
"peerDependencies": {
"graphql": "^15.0.0 || ^16.0.0 || ^17.0.0"
},
"devDependencies": {
"graphql": "^15.6.1",
"@types/jest": "^26.0.22",
"monorepo-scripts": "*",
"ts-node": "^10.4.0"
},
"sideEffects": false,
"access": "public",
"publishConfig": {
"main": "./lib/index",
"types": "./lib/index.d.ts",
"module": "./lib/index.mjs",
"exports": {
".": {
"import": "./lib/index.mjs",
"require": "./lib/index.js",
"types": "./lib/index.d.ts"
}
},
"bin": {
"template": "./lib/cli.js"
}
}
}

Просмотреть файл

@ -1,16 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": ".tsbuildinfo",
"rootDir": "src",
"outDir": "lib"
},
"include": ["src"],
"references": [],
"ts-node": {
"transpileOnly": true,
"target": "es5",
"module": "commonjs"
}
}

Просмотреть файл

@ -1,140 +1,144 @@
export { executeWithSchema } from "./executeWithSchema";
export {
executeWithoutSchema,
isTotalExecutionResult,
isIncrementalExecutionResult,
isTotalExecutionResult,
} from "./executeWithoutSchema";
export { executeWithSchema } from "./executeWithSchema";
export { subscribeWithSchema } from "./subscribeWithSchema";
export { subscribeWithoutSchema } from "./subscribeWithoutSchema";
export { encodeASTSchema } from "./utilities/encodeASTSchema";
export { decodeASTSchema } from "./utilities/decodeASTSchema";
export { mergeSchemaDefinitions } from "./utilities/mergeSchemaDefinitions";
export { mergeResolvers } from "./utilities/mergeResolvers";
export { annotateDocumentGraphQLTransform } from "./utilities/annotateDocumentGraphQLTransform";
export {
addMinimalViableSchemaToRequestDocument,
addMinimalViableSchemaToExecutableDefinitionNode,
} from "./utilities/addMinimalViableSchemaToRequestDocument";
export { extractMinimalViableSchemaForRequestDocument } from "./utilities/extractMinimalViableSchemaForRequestDocument";
export { specifiedScalarResolvers } from "./schema/resolvers";
export {
isListType,
isNonNullType,
typeNameFromReference,
typeReferenceFromName,
typeReferenceFromNode,
isNonNullType,
isListType,
unwrap,
unwrapAll,
} from "./schema/reference";
export type {
TypeReference,
TypeName,
SpecTypeIndex,
TypeName,
TypeReference,
} from "./schema/reference";
export { specifiedScalarResolvers } from "./schema/resolvers";
export { subscribeWithSchema } from "./subscribeWithSchema";
export { subscribeWithoutSchema } from "./subscribeWithoutSchema";
export {
addMinimalViableSchemaToExecutableDefinitionNode,
addMinimalViableSchemaToRequestDocument,
} from "./utilities/addMinimalViableSchemaToRequestDocument";
export { annotateDocumentGraphQLTransform } from "./utilities/annotateDocumentGraphQLTransform";
export { decodeASTSchema } from "./utilities/decodeASTSchema";
export { encodeASTSchema } from "./utilities/encodeASTSchema";
export { extractMinimalViableSchemaForRequestDocument } from "./utilities/extractMinimalViableSchemaForRequestDocument";
export { mergeResolvers } from "./utilities/mergeResolvers";
export { mergeSchemaDefinitions } from "./utilities/mergeSchemaDefinitions";
export type { ExtractMinimalViableSchemaResult } from "./utilities/extractMinimalViableSchemaForRequestDocument";
export type {
CompositeTypeTuple,
DirectiveDefinitionTuple,
DirectiveName,
DirectiveTuple,
EnumTypeDefinitionTuple,
FieldDefinition,
FieldDefinitionRecord,
FieldDefinitionTuple,
InputObjectTypeDefinitionTuple,
InputValueDefinition,
InputValueDefinitionRecord,
InputValueDefinitionTuple,
InterfaceImplementationsRecord,
InterfaceTypeDefinitionTuple,
ObjectTypeDefinitionTuple,
OperationTypes,
ScalarTypeDefinitionTuple,
SchemaDefinitions,
TypeDefinitionTuple,
TypeDefinitionsRecord,
UnionTypeDefinitionTuple,
} from "./schema/definition";
export type {
AddMinimalViableSchemaToRequestDocumentOptions,
ExecutableDefinitionNodeWithInlinedSchema,
} from "./utilities/addMinimalViableSchemaToRequestDocument";
export type {
SchemaDefinitions,
OperationTypes,
TypeDefinitionsRecord,
TypeDefinitionTuple,
DirectiveDefinitionTuple,
InterfaceTypeDefinitionTuple,
ObjectTypeDefinitionTuple,
InputValueDefinition,
InputValueDefinitionRecord,
UnionTypeDefinitionTuple,
EnumTypeDefinitionTuple,
ScalarTypeDefinitionTuple,
InputObjectTypeDefinitionTuple,
FieldDefinition,
FieldDefinitionTuple,
CompositeTypeTuple,
FieldDefinitionRecord,
InputValueDefinitionTuple,
DirectiveTuple,
InterfaceImplementationsRecord,
DirectiveName,
} from "./schema/definition";
export type { ExtractMinimalViableSchemaResult } from "./utilities/extractMinimalViableSchemaForRequestDocument";
export type {
ObjectTypeResolver,
ScalarTypeResolver,
EnumTypeResolver,
FunctionFieldResolver,
Resolvers,
UserResolvers,
ResolveInfo,
TotalExecutionResult,
ExecutionResult,
SubscriptionExecutionResult,
FunctionFieldResolver,
IncrementalExecutionResult,
ObjectTypeResolver,
ResolveInfo,
Resolvers,
ScalarTypeResolver,
SchemaFragment,
SchemaFragmentForReturnTypeRequest,
SchemaFragmentForRuntimeTypeRequest,
SchemaFragmentLoader,
SchemaFragmentLoaderResult,
SchemaFragmentRequest,
SchemaFragmentForReturnTypeRequest,
SchemaFragmentForRuntimeTypeRequest,
SubscriptionExecutionResult,
TotalExecutionResult,
UserResolvers,
} from "./types";
export type { PromiseOrValue } from "./jsutils/PromiseOrValue";
export type {
NameNode,
DocumentNode,
OperationDefinitionNode,
VariableDefinitionNode,
VariableNode,
SelectionSetNode,
FieldNode,
ArgumentNode,
BooleanValueNode,
DirectiveDefinitionNode,
DirectiveNode,
DocumentNode,
EnumTypeDefinitionNode,
EnumTypeExtensionNode,
EnumValueDefinitionNode,
EnumValueNode,
FieldDefinitionNode,
FieldNode,
FloatValueNode,
FragmentDefinitionNode,
FragmentSpreadNode,
InlineFragmentNode,
FragmentDefinitionNode,
InputObjectTypeDefinitionNode,
InputObjectTypeExtensionNode,
InputValueDefinitionNode,
IntValueNode,
FloatValueNode,
StringValueNode,
BooleanValueNode,
NullValueNode,
EnumValueNode,
ListValueNode,
ObjectValueNode,
ObjectFieldNode,
DirectiveNode,
NamedTypeNode,
InterfaceTypeDefinitionNode,
InterfaceTypeExtensionNode,
ListTypeNode,
ListValueNode,
NameNode,
NamedTypeNode,
NonNullTypeNode,
SchemaDefinitionNode,
NullValueNode,
ObjectFieldNode,
ObjectTypeDefinitionNode,
ObjectTypeExtensionNode,
ObjectValueNode,
OperationDefinitionNode,
OperationTypeDefinitionNode,
ScalarTypeDefinitionNode,
ObjectTypeDefinitionNode,
FieldDefinitionNode,
InputValueDefinitionNode,
InterfaceTypeDefinitionNode,
UnionTypeDefinitionNode,
EnumTypeDefinitionNode,
EnumValueDefinitionNode,
InputObjectTypeDefinitionNode,
DirectiveDefinitionNode,
SchemaExtensionNode,
ScalarTypeExtensionNode,
ObjectTypeExtensionNode,
InterfaceTypeExtensionNode,
SchemaDefinitionNode,
SchemaExtensionNode,
SelectionSetNode,
StringValueNode,
UnionTypeDefinitionNode,
UnionTypeExtensionNode,
EnumTypeExtensionNode,
InputObjectTypeExtensionNode,
VariableDefinitionNode,
VariableNode,
} from "graphql";
export type {
BeforeFieldResolveHookArgs,
AfterFieldResolveHookArgs,
AfterFieldCompleteHookArgs,
BeforeFieldResolveHook,
AfterFieldResolveHook,
AfterFieldCompleteHook,
AfterFieldCompleteHookArgs,
AfterFieldResolveHook,
AfterFieldResolveHookArgs,
BeforeFieldResolveHook,
BeforeFieldResolveHookArgs,
ExecutionHooks,
} from "./hooks/types";
export * as LegacyTypedAST from "./legacyAST/TypedAST";
export { addTypesToRequestDocument as addSupermassiveLegacyTypesToRequestDocument } from "./legacyAST/addTypesToRequestDocument";
export { annotateDocumentGraphQLTransform as annotateDocumentWithSupermassiveLegacyTypesGraphQLTransform } from "./legacyAST/annotateDocumentGraphQLTransform";

Просмотреть файл

@ -1,3 +1,7 @@
import {
DirectiveLocation as GraphQLDirectiveLocation,
DirectiveLocationEnum,
} from "graphql";
import { isSpecifiedScalarType } from "./resolvers";
import { TypeName, TypeReference, typeNameFromReference } from "./reference";
@ -103,18 +107,67 @@ const enum InputValueKeys {
export type InputValueDefinition = TypeReference | InputValueDefinitionTuple;
export type InputValueDefinitionRecord = Record<string, InputValueDefinition>;
const DirectiveLocation = {
QUERY: 1,
MUTATION: 2,
SUBSCRIPTION: 3,
FIELD: 4,
FRAGMENT_DEFINITION: 5,
FRAGMENT_SPREAD: 6,
INLINE_FRAGMENT: 7,
VARIABLE_DEFINITION: 8,
/** Type System Definitions */
SCHEMA: 9,
SCALAR: 10,
OBJECT: 11,
FIELD_DEFINITION: 12,
ARGUMENT_DEFINITION: 13,
INTERFACE: 14,
UNION: 15,
ENUM: 16,
ENUM_VALUE: 17,
INPUT_OBJECT: 18,
INPUT_FIELD_DEFINITION: 19,
} as const;
type DirectiveLocation =
(typeof DirectiveLocation)[keyof typeof DirectiveLocation];
const DirectiveLocationToGraphQL = {
1: GraphQLDirectiveLocation.QUERY,
2: GraphQLDirectiveLocation.MUTATION,
3: GraphQLDirectiveLocation.SUBSCRIPTION,
4: GraphQLDirectiveLocation.FIELD,
5: GraphQLDirectiveLocation.FRAGMENT_DEFINITION,
6: GraphQLDirectiveLocation.FRAGMENT_SPREAD,
7: GraphQLDirectiveLocation.INLINE_FRAGMENT,
8: GraphQLDirectiveLocation.VARIABLE_DEFINITION,
/** Type System Definitions */
9: GraphQLDirectiveLocation.SCHEMA,
10: GraphQLDirectiveLocation.SCALAR,
11: GraphQLDirectiveLocation.OBJECT,
12: GraphQLDirectiveLocation.FIELD_DEFINITION,
13: GraphQLDirectiveLocation.ARGUMENT_DEFINITION,
14: GraphQLDirectiveLocation.INTERFACE,
15: GraphQLDirectiveLocation.UNION,
16: GraphQLDirectiveLocation.ENUM,
17: GraphQLDirectiveLocation.ENUM_VALUE,
18: GraphQLDirectiveLocation.INPUT_OBJECT,
19: GraphQLDirectiveLocation.INPUT_FIELD_DEFINITION,
} as const;
export type DirectiveName = string;
export type DirectiveTuple = [
name: DirectiveName,
arguments?: Record<string, unknown>, // JS values (cannot be a variable inside schema definition, so it is fine)
arguments: Record<string, unknown>, // JS values (cannot be a variable inside schema definition, so it is fine)
];
export type DirectiveDefinitionTuple = [
name: DirectiveName,
locations: DirectiveLocation[],
arguments?: InputValueDefinitionRecord,
];
const enum DirectiveKeys {
name = 0,
arguments = 1,
locations = 1,
arguments = 2,
}
export type TypeDefinitionsRecord = Record<TypeName, TypeDefinitionTuple>;
@ -372,6 +425,23 @@ export function getDirectiveName(tuple: DirectiveDefinitionTuple): string {
return tuple[DirectiveKeys.name];
}
export function getDirectiveLocations(
tuple: DirectiveDefinitionTuple,
): DirectiveLocation[] {
return tuple[DirectiveKeys.locations];
}
export function encodeDirectiveLocation(
location: DirectiveLocationEnum,
): DirectiveLocation {
return DirectiveLocation[location];
}
export function decodeDirectiveLocation(
location: DirectiveLocation,
): DirectiveLocationEnum {
return DirectiveLocationToGraphQL[location];
}
export function isObjectTypeDefinition(
type: TypeDefinitionTuple,
): type is ObjectTypeDefinitionTuple {
@ -532,9 +602,14 @@ export function getUnionTypeMembers(
return tuple[UnionKeys.types];
}
export function getDefinitionArguments(
def: FieldDefinition | DirectiveDefinitionTuple,
export function getFieldArguments(
def: FieldDefinition,
): InputValueDefinitionRecord | undefined {
// Note: both FieldDefinition and DirectiveDefinition store arguments at the same position
return Array.isArray(def) ? def[FieldKeys.arguments] : undefined;
}
export function getDirectiveArguments(
def: DirectiveDefinitionTuple,
): InputValueDefinitionRecord | undefined {
return Array.isArray(def) ? def[DirectiveKeys.arguments] : undefined;
}

Просмотреть файл

@ -1,6 +1,8 @@
import { DirectiveLocation } from "graphql";
import {
DirectiveDefinitionTuple,
DirectiveName,
encodeDirectiveLocation,
getDirectiveName,
} from "./definition";
@ -9,8 +11,12 @@ import {
*/
export const GraphQLIncludeDirective: DirectiveDefinitionTuple = [
"include",
[
DirectiveLocation.FIELD,
DirectiveLocation.FRAGMENT_SPREAD,
DirectiveLocation.INLINE_FRAGMENT,
].map(encodeDirectiveLocation),
{ if: "Boolean!" },
// TODO: locations for all directives (maybe not - they are irrelevant for runtime)?
];
/**
@ -18,6 +24,11 @@ export const GraphQLIncludeDirective: DirectiveDefinitionTuple = [
*/
export const GraphQLSkipDirective: DirectiveDefinitionTuple = [
"skip",
[
DirectiveLocation.FIELD,
DirectiveLocation.FRAGMENT_SPREAD,
DirectiveLocation.INLINE_FRAGMENT,
].map(encodeDirectiveLocation),
{ if: "Boolean!" },
];
@ -25,12 +36,12 @@ export const GraphQLSkipDirective: DirectiveDefinitionTuple = [
* Constant string used for default reason for a deprecation.
*/
export const DEFAULT_DEPRECATION_REASON = "No longer supported";
/**
* Used to declare element of a GraphQL schema as deprecated.
*/
export const GraphQLDeprecatedDirective: DirectiveDefinitionTuple = [
"deprecated",
[DirectiveLocation.FIELD_DEFINITION].map(encodeDirectiveLocation),
{ reason: ["String", DEFAULT_DEPRECATION_REASON] },
];
@ -39,6 +50,7 @@ export const GraphQLDeprecatedDirective: DirectiveDefinitionTuple = [
*/
export const GraphQLSpecifiedByDirective: DirectiveDefinitionTuple = [
"specifiedBy",
[DirectiveLocation.INPUT_OBJECT].map(encodeDirectiveLocation),
{ url: "String!" },
];
@ -47,6 +59,9 @@ export const GraphQLSpecifiedByDirective: DirectiveDefinitionTuple = [
*/
export const GraphQLDeferDirective: DirectiveDefinitionTuple = [
"defer",
[DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT].map(
encodeDirectiveLocation,
),
{ if: ["Boolean!", true], label: "String" },
];
@ -55,6 +70,7 @@ export const GraphQLDeferDirective: DirectiveDefinitionTuple = [
*/
export const GraphQLStreamDirective: DirectiveDefinitionTuple = [
"stream",
[DirectiveLocation.FIELD].map(encodeDirectiveLocation),
{ if: ["Boolean!", true], label: "String", initialCount: ["Int", 0] },
];
@ -70,16 +86,19 @@ export const specifiedDirectives: ReadonlyArray<DirectiveDefinitionTuple> =
GraphQLDeferDirective,
GraphQLStreamDirective,
]);
export const SUPERMASSIVE_SCHEMA_DIRECTIVE_NAME = "schema";
export const SUPERMASSIVE_SCHEMA_DIRECTIVE_DEFINITIONS_ARGUMENT_NAME =
"definitions";
/**
* Used to conditionally stream list fields.
*/
export const SupermassiveSchemaDirective: DirectiveDefinitionTuple = [
SUPERMASSIVE_SCHEMA_DIRECTIVE_NAME,
[
DirectiveLocation.QUERY,
DirectiveLocation.MUTATION,
DirectiveLocation.SUBSCRIPTION,
].map(encodeDirectiveLocation),
{ [SUPERMASSIVE_SCHEMA_DIRECTIVE_DEFINITIONS_ARGUMENT_NAME]: "String!" }, // Essentially JSON
];
@ -93,7 +112,6 @@ export function isKnownDirective(
name === SUPERMASSIVE_SCHEMA_DIRECTIVE_NAME
);
}
export function isSpecifiedDirective(
directive: DirectiveName | DirectiveDefinitionTuple,
): boolean {

Просмотреть файл

@ -6,24 +6,43 @@ exports[`encodeASTSchema correctly encodes kitchen sink AST schema 1`] = `
"directives": [
[
"skip",
[
4,
6,
7,
],
{
"if": 7,
},
],
[
"include",
[
4,
6,
7,
],
{
"if": 7,
},
],
[
"include2",
[
4,
6,
7,
],
{
"if": 7,
},
],
[
"myRepeatableDir",
[
11,
14,
],
{
"name": 6,
},
@ -341,6 +360,9 @@ exports[`encodeASTSchema correctly encodes swapi AST schema 1`] = `
"directives": [
[
"i18n",
[
1,
],
{
"locale": 1,
},

Просмотреть файл

@ -37,7 +37,7 @@ describe(addMinimalViableSchemaToRequestDocument, () => {
}`,
);
expect(printedDoc).toMatchInlineSnapshot(`
"query @i18n(locale: "en_US") @schema(definitions: "{\\"types\\":{\\"Query\\":[2,{\\"film\\":[\\"Film\\",{\\"id\\":10}]}],\\"Film\\":[2,{},[\\"Node\\"]]},\\"directives\\":[[\\"i18n\\",{\\"locale\\":1}]]}") {
"query @i18n(locale: "en_US") @schema(definitions: "{\\"types\\":{\\"Query\\":[2,{\\"film\\":[\\"Film\\",{\\"id\\":10}]}],\\"Film\\":[2,{},[\\"Node\\"]]},\\"directives\\":[[\\"i18n\\",[1],{\\"locale\\":1}]]}") {
film(id: 42) {
__typename
}

Просмотреть файл

@ -15,6 +15,7 @@ import {
UnionTypeExtensionNode,
EnumTypeExtensionNode,
ScalarTypeExtensionNode,
DirectiveLocationEnum,
} from "graphql";
import {
DirectiveDefinitionTuple,
@ -35,6 +36,7 @@ import {
createInputObjectTypeDefinition,
createInterfaceTypeDefinition,
createUnionTypeDefinition,
encodeDirectiveLocation,
} from "../schema/definition";
import { typeReferenceFromNode, TypeReference } from "../schema/reference";
import { valueFromASTUntyped } from "./valueFromASTUntyped";
@ -194,7 +196,20 @@ function encodeInputValue(
function encodeDirective(
node: DirectiveDefinitionNode,
): DirectiveDefinitionTuple {
return !node.arguments?.length
? [node.name.value]
: [node.name.value, encodeArguments(node)];
if (node.arguments?.length) {
return [
node.name.value,
node.locations.map((node) =>
encodeDirectiveLocation(node.value as DirectiveLocationEnum),
),
encodeArguments(node),
];
} else {
return [
node.name.value,
node.locations.map((node) =>
encodeDirectiveLocation(node.value as DirectiveLocationEnum),
),
];
}
}

Просмотреть файл

@ -36,6 +36,7 @@ import {
createScalarTypeDefinition,
createUnionTypeDefinition,
DirectiveDefinitionTuple,
encodeDirectiveLocation,
EnumTypeDefinitionTuple,
FieldDefinition,
getDirectiveDefinitionArgs,
@ -76,7 +77,7 @@ export function extractMinimalViableSchemaForRequestDocument(
schema: GraphQLSchema,
requestDocument: DocumentNode,
): ExtractMinimalViableSchemaResult {
const types: TypeDefinitionsRecord = Object.create(null);
const types: TypeDefinitionsRecord = {};
const directives: DirectiveDefinitionTuple[] = [];
const unknownDirectives: DirectiveNode[] = [];
@ -244,7 +245,7 @@ function addDirective(
const name = directive.name;
let tuple = directives.find((d) => getDirectiveName(d) === name);
if (!tuple) {
tuple = [directive.name];
tuple = [directive.name, directive.locations.map(encodeDirectiveLocation)];
directives.push(tuple);
}

Просмотреть файл

@ -13,12 +13,13 @@ import { ExecutionContext } from "./executeWithoutSchema";
import {
DirectiveDefinitionTuple,
FieldDefinition,
getDefinitionArguments,
getFieldArguments,
getDirectiveName,
getInputDefaultValue,
getInputValueTypeReference,
isDefined,
isInputType,
getDirectiveArguments,
} from "./schema/definition";
import { valueFromAST } from "./utilities/valueFromAST";
import { coerceInputValue } from "./utilities/coerceInputValue";
@ -168,7 +169,10 @@ export function getArgumentValues(
): { [argument: string]: unknown } {
const definitions = exeContext.schemaFragment.definitions;
const coercedValues: { [argument: string]: unknown } = {};
const argumentDefs = getDefinitionArguments(def);
const argumentDefs =
node.kind === Kind.FIELD
? getFieldArguments(def as FieldDefinition)
: getDirectiveArguments(def as DirectiveDefinitionTuple);
if (!argumentDefs) {
return coercedValues;
}

Просмотреть файл

@ -1692,6 +1692,11 @@
"@n1ru4l/push-pull-async-iterable-iterator" "^3.1.0"
meros "^1.1.4"
"@graphitation/supermassive-ast@*":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@graphitation/supermassive-ast/-/supermassive-ast-2.0.0.tgz#d49155c6b7213811d99b8609d496d6c460a4d1e2"
integrity sha512-YXguoTpIMI/ISavl98CrSOLohYVMr3JmPRhT6Qg4q6MfaonSKajvva9OUFOxxEmuAaEXfjhZ33ySWaNSu/XcLQ==
"@graphql-codegen/add@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-3.1.0.tgz#cd02fd6d80a7f62839cb27160b62e48366a237c5"