From 079167dcdf80121556c9f6ea6096d0b9e4fd1304 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 22 Nov 2024 09:02:47 -0500 Subject: [PATCH] refactor: treeshakable kind enum (#4270) closes https://github.com/graphql/graphql-js/issues/4253 --- integrationTests/ts/package.json | 5 - src/index.ts | 4 +- src/language/__tests__/kind-test.ts | 30 ++++++ src/language/__tests__/predicates-test.ts | 78 +++++++-------- src/language/index.ts | 2 + src/language/kinds.ts | 74 +-------------- src/language/kinds_.ts | 110 ++++++++++++++++++++++ 7 files changed, 188 insertions(+), 115 deletions(-) create mode 100644 src/language/__tests__/kind-test.ts create mode 100644 src/language/kinds_.ts diff --git a/integrationTests/ts/package.json b/integrationTests/ts/package.json index 9019b51b68..6e5bfb367d 100644 --- a/integrationTests/ts/package.json +++ b/integrationTests/ts/package.json @@ -8,11 +8,6 @@ "dependencies": { "graphql": "file:../graphql.tgz", "graphql-esm": "file:../graphql-esm.tgz", - "typescript-4.4": "npm:typescript@4.4.x", - "typescript-4.5": "npm:typescript@4.5.x", - "typescript-4.6": "npm:typescript@4.6.x", - "typescript-4.7": "npm:typescript@4.7.x", - "typescript-4.8": "npm:typescript@4.8.x", "typescript-4.9": "npm:typescript@4.9.x", "typescript-5.0": "npm:typescript@5.0.x", "typescript-5.1": "npm:typescript@5.1.x", diff --git a/src/index.ts b/src/index.ts index aef9d75b16..aa3153b5f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -206,6 +206,9 @@ export type { } from './type/index.js'; // Parse and operate on GraphQL language source files. +// @see https://github.com/typescript-eslint/typescript-eslint/issues/10313 +// eslint-disable-next-line @typescript-eslint/consistent-type-exports +export { Kind } from './language/kinds.js'; export { Token, Source, @@ -230,7 +233,6 @@ export { visitInParallel, getEnterLeaveForKind, BREAK, - Kind, DirectiveLocation, // Predicates isDefinitionNode, diff --git a/src/language/__tests__/kind-test.ts b/src/language/__tests__/kind-test.ts new file mode 100644 index 0000000000..febea2414f --- /dev/null +++ b/src/language/__tests__/kind-test.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ +import { describe, it } from 'mocha'; + +import { Kind } from '../index.js'; + +describe('Kind', () => { + it('is a term level namespace with term level enum members', () => { + const a: Kind.NAME = Kind.NAME; + a; + const b: Kind = Kind.NAME; + b; + const c: Kind = Kind.ARGUMENT; + c; + }); + + it('is a type level namespace with type level enum members', () => { + // @ts-expect-error + const a: Kind.NAME = 'bad'; + a; + const b: Kind.NAME = 'Name'; + b; + // @ts-expect-error + const c: Kind = 'bad'; + c; + const d: Kind = 'Name'; + d; + const e: Kind = 'Argument'; + e; + }); +}); diff --git a/src/language/__tests__/predicates-test.ts b/src/language/__tests__/predicates-test.ts index 350e3f1a6b..7eeb682f3f 100644 --- a/src/language/__tests__/predicates-test.ts +++ b/src/language/__tests__/predicates-test.ts @@ -27,30 +27,30 @@ function filterNodes(predicate: (node: ASTNode) => boolean): Array { describe('AST node predicates', () => { it('isDefinitionNode', () => { expect(filterNodes(isDefinitionNode)).to.deep.equal([ - 'OperationDefinition', - 'FragmentDefinition', - 'SchemaDefinition', - 'ScalarTypeDefinition', - 'ObjectTypeDefinition', - 'InterfaceTypeDefinition', - 'UnionTypeDefinition', + 'DirectiveDefinition', 'EnumTypeDefinition', + 'EnumTypeExtension', + 'FragmentDefinition', 'InputObjectTypeDefinition', - 'DirectiveDefinition', - 'SchemaExtension', - 'ScalarTypeExtension', - 'ObjectTypeExtension', + 'InputObjectTypeExtension', + 'InterfaceTypeDefinition', 'InterfaceTypeExtension', + 'ObjectTypeDefinition', + 'ObjectTypeExtension', + 'OperationDefinition', + 'ScalarTypeDefinition', + 'ScalarTypeExtension', + 'SchemaDefinition', + 'SchemaExtension', + 'UnionTypeDefinition', 'UnionTypeExtension', - 'EnumTypeExtension', - 'InputObjectTypeExtension', ]); }); it('isExecutableDefinitionNode', () => { expect(filterNodes(isExecutableDefinitionNode)).to.deep.equal([ - 'OperationDefinition', 'FragmentDefinition', + 'OperationDefinition', ]); }); @@ -64,15 +64,15 @@ describe('AST node predicates', () => { it('isValueNode', () => { expect(filterNodes(isValueNode)).to.deep.equal([ - 'Variable', - 'IntValue', - 'FloatValue', - 'StringValue', 'BooleanValue', - 'NullValue', 'EnumValue', + 'FloatValue', + 'IntValue', 'ListValue', + 'NullValue', 'ObjectValue', + 'StringValue', + 'Variable', ]); }); @@ -89,56 +89,56 @@ describe('AST node predicates', () => { it('isTypeNode', () => { expect(filterNodes(isTypeNode)).to.deep.equal([ - 'NamedType', 'ListType', + 'NamedType', 'NonNullType', ]); }); it('isTypeSystemDefinitionNode', () => { expect(filterNodes(isTypeSystemDefinitionNode)).to.deep.equal([ - 'SchemaDefinition', - 'ScalarTypeDefinition', - 'ObjectTypeDefinition', - 'InterfaceTypeDefinition', - 'UnionTypeDefinition', + 'DirectiveDefinition', 'EnumTypeDefinition', 'InputObjectTypeDefinition', - 'DirectiveDefinition', + 'InterfaceTypeDefinition', + 'ObjectTypeDefinition', + 'ScalarTypeDefinition', + 'SchemaDefinition', + 'UnionTypeDefinition', ]); }); it('isTypeDefinitionNode', () => { expect(filterNodes(isTypeDefinitionNode)).to.deep.equal([ - 'ScalarTypeDefinition', - 'ObjectTypeDefinition', - 'InterfaceTypeDefinition', - 'UnionTypeDefinition', 'EnumTypeDefinition', 'InputObjectTypeDefinition', + 'InterfaceTypeDefinition', + 'ObjectTypeDefinition', + 'ScalarTypeDefinition', + 'UnionTypeDefinition', ]); }); it('isTypeSystemExtensionNode', () => { expect(filterNodes(isTypeSystemExtensionNode)).to.deep.equal([ - 'SchemaExtension', - 'ScalarTypeExtension', - 'ObjectTypeExtension', - 'InterfaceTypeExtension', - 'UnionTypeExtension', 'EnumTypeExtension', 'InputObjectTypeExtension', + 'InterfaceTypeExtension', + 'ObjectTypeExtension', + 'ScalarTypeExtension', + 'SchemaExtension', + 'UnionTypeExtension', ]); }); it('isTypeExtensionNode', () => { expect(filterNodes(isTypeExtensionNode)).to.deep.equal([ - 'ScalarTypeExtension', - 'ObjectTypeExtension', - 'InterfaceTypeExtension', - 'UnionTypeExtension', 'EnumTypeExtension', 'InputObjectTypeExtension', + 'InterfaceTypeExtension', + 'ObjectTypeExtension', + 'ScalarTypeExtension', + 'UnionTypeExtension', ]); }); }); diff --git a/src/language/index.ts b/src/language/index.ts index 4d96766abc..706072a75b 100644 --- a/src/language/index.ts +++ b/src/language/index.ts @@ -5,6 +5,8 @@ export type { SourceLocation } from './location.js'; export { printLocation, printSourceLocation } from './printLocation.js'; +// @see https://github.com/typescript-eslint/typescript-eslint/issues/10313 +// eslint-disable-next-line @typescript-eslint/consistent-type-exports export { Kind } from './kinds.js'; export { TokenKind } from './tokenKind.js'; diff --git a/src/language/kinds.ts b/src/language/kinds.ts index d41eccecfc..36231d3135 100644 --- a/src/language/kinds.ts +++ b/src/language/kinds.ts @@ -1,72 +1,6 @@ -/** - * The set of allowed kind values for AST nodes. - */ -export const Kind = { - /** Name */ - NAME: 'Name' as const, +/* eslint-disable import/no-namespace */ +import type * as Kind_ from './kinds_.js'; - /** Document */ - DOCUMENT: 'Document' as const, - OPERATION_DEFINITION: 'OperationDefinition' as const, - VARIABLE_DEFINITION: 'VariableDefinition' as const, - SELECTION_SET: 'SelectionSet' as const, - FIELD: 'Field' as const, - ARGUMENT: 'Argument' as const, - FRAGMENT_ARGUMENT: 'FragmentArgument' as const, +export * as Kind from './kinds_.js'; - /** Fragments */ - FRAGMENT_SPREAD: 'FragmentSpread' as const, - INLINE_FRAGMENT: 'InlineFragment' as const, - FRAGMENT_DEFINITION: 'FragmentDefinition' as const, - - /** Values */ - VARIABLE: 'Variable' as const, - INT: 'IntValue' as const, - FLOAT: 'FloatValue' as const, - STRING: 'StringValue' as const, - BOOLEAN: 'BooleanValue' as const, - NULL: 'NullValue' as const, - ENUM: 'EnumValue' as const, - LIST: 'ListValue' as const, - OBJECT: 'ObjectValue' as const, - OBJECT_FIELD: 'ObjectField' as const, - - /** Directives */ - DIRECTIVE: 'Directive' as const, - - /** Types */ - NAMED_TYPE: 'NamedType' as const, - LIST_TYPE: 'ListType' as const, - NON_NULL_TYPE: 'NonNullType' as const, - - /** Type System Definitions */ - SCHEMA_DEFINITION: 'SchemaDefinition' as const, - OPERATION_TYPE_DEFINITION: 'OperationTypeDefinition' as const, - - /** Type Definitions */ - SCALAR_TYPE_DEFINITION: 'ScalarTypeDefinition' as const, - OBJECT_TYPE_DEFINITION: 'ObjectTypeDefinition' as const, - FIELD_DEFINITION: 'FieldDefinition' as const, - INPUT_VALUE_DEFINITION: 'InputValueDefinition' as const, - INTERFACE_TYPE_DEFINITION: 'InterfaceTypeDefinition' as const, - UNION_TYPE_DEFINITION: 'UnionTypeDefinition' as const, - ENUM_TYPE_DEFINITION: 'EnumTypeDefinition' as const, - ENUM_VALUE_DEFINITION: 'EnumValueDefinition' as const, - INPUT_OBJECT_TYPE_DEFINITION: 'InputObjectTypeDefinition' as const, - - /** Directive Definitions */ - DIRECTIVE_DEFINITION: 'DirectiveDefinition' as const, - - /** Type System Extensions */ - SCHEMA_EXTENSION: 'SchemaExtension' as const, - - /** Type Extensions */ - SCALAR_TYPE_EXTENSION: 'ScalarTypeExtension' as const, - OBJECT_TYPE_EXTENSION: 'ObjectTypeExtension' as const, - INTERFACE_TYPE_EXTENSION: 'InterfaceTypeExtension' as const, - UNION_TYPE_EXTENSION: 'UnionTypeExtension' as const, - ENUM_TYPE_EXTENSION: 'EnumTypeExtension' as const, - INPUT_OBJECT_TYPE_EXTENSION: 'InputObjectTypeExtension' as const, -}; -// eslint-disable-next-line @typescript-eslint/no-redeclare -export type Kind = (typeof Kind)[keyof typeof Kind]; +export type Kind = (typeof Kind_)[keyof typeof Kind_]; diff --git a/src/language/kinds_.ts b/src/language/kinds_.ts new file mode 100644 index 0000000000..0389c60c75 --- /dev/null +++ b/src/language/kinds_.ts @@ -0,0 +1,110 @@ +/* eslint-disable @typescript-eslint/no-redeclare */ + +/** Name */ +export const NAME = 'Name'; +export type NAME = typeof NAME; + +/** Document */ +export const DOCUMENT = 'Document'; +export type DOCUMENT = typeof DOCUMENT; +export const OPERATION_DEFINITION = 'OperationDefinition'; +export type OPERATION_DEFINITION = typeof OPERATION_DEFINITION; +export const VARIABLE_DEFINITION = 'VariableDefinition'; +export type VARIABLE_DEFINITION = typeof VARIABLE_DEFINITION; +export const SELECTION_SET = 'SelectionSet'; +export type SELECTION_SET = typeof SELECTION_SET; +export const FIELD = 'Field'; +export type FIELD = typeof FIELD; +export const ARGUMENT = 'Argument'; +export type ARGUMENT = typeof ARGUMENT; +export const FRAGMENT_ARGUMENT = 'FragmentArgument'; +export type FRAGMENT_ARGUMENT = typeof FRAGMENT_ARGUMENT; + +/** Fragments */ +export const FRAGMENT_SPREAD = 'FragmentSpread'; +export type FRAGMENT_SPREAD = typeof FRAGMENT_SPREAD; +export const INLINE_FRAGMENT = 'InlineFragment'; +export type INLINE_FRAGMENT = typeof INLINE_FRAGMENT; +export const FRAGMENT_DEFINITION = 'FragmentDefinition'; +export type FRAGMENT_DEFINITION = typeof FRAGMENT_DEFINITION; + +/** Values */ +export const VARIABLE = 'Variable'; +export type VARIABLE = typeof VARIABLE; +export const INT = 'IntValue'; +export type INT = typeof INT; +export const FLOAT = 'FloatValue'; +export type FLOAT = typeof FLOAT; +export const STRING = 'StringValue'; +export type STRING = typeof STRING; +export const BOOLEAN = 'BooleanValue'; +export type BOOLEAN = typeof BOOLEAN; +export const NULL = 'NullValue'; +export type NULL = typeof NULL; +export const ENUM = 'EnumValue'; +export type ENUM = typeof ENUM; +export const LIST = 'ListValue'; +export type LIST = typeof LIST; +export const OBJECT = 'ObjectValue'; +export type OBJECT = typeof OBJECT; +export const OBJECT_FIELD = 'ObjectField'; +export type OBJECT_FIELD = typeof OBJECT_FIELD; + +/** Directives */ +export const DIRECTIVE = 'Directive'; +export type DIRECTIVE = typeof DIRECTIVE; + +/** Types */ +export const NAMED_TYPE = 'NamedType'; +export type NAMED_TYPE = typeof NAMED_TYPE; +export const LIST_TYPE = 'ListType'; +export type LIST_TYPE = typeof LIST_TYPE; +export const NON_NULL_TYPE = 'NonNullType'; +export type NON_NULL_TYPE = typeof NON_NULL_TYPE; + +/** Type System Definitions */ +export const SCHEMA_DEFINITION = 'SchemaDefinition'; +export type SCHEMA_DEFINITION = typeof SCHEMA_DEFINITION; +export const OPERATION_TYPE_DEFINITION = 'OperationTypeDefinition'; +export type OPERATION_TYPE_DEFINITION = typeof OPERATION_TYPE_DEFINITION; + +/** Type Definitions */ +export const SCALAR_TYPE_DEFINITION = 'ScalarTypeDefinition'; +export type SCALAR_TYPE_DEFINITION = typeof SCALAR_TYPE_DEFINITION; +export const OBJECT_TYPE_DEFINITION = 'ObjectTypeDefinition'; +export type OBJECT_TYPE_DEFINITION = typeof OBJECT_TYPE_DEFINITION; +export const FIELD_DEFINITION = 'FieldDefinition'; +export type FIELD_DEFINITION = typeof FIELD_DEFINITION; +export const INPUT_VALUE_DEFINITION = 'InputValueDefinition'; +export type INPUT_VALUE_DEFINITION = typeof INPUT_VALUE_DEFINITION; +export const INTERFACE_TYPE_DEFINITION = 'InterfaceTypeDefinition'; +export type INTERFACE_TYPE_DEFINITION = typeof INTERFACE_TYPE_DEFINITION; +export const UNION_TYPE_DEFINITION = 'UnionTypeDefinition'; +export type UNION_TYPE_DEFINITION = typeof UNION_TYPE_DEFINITION; +export const ENUM_TYPE_DEFINITION = 'EnumTypeDefinition'; +export const ENUM_VALUE_DEFINITION = 'EnumValueDefinition'; +export type ENUM_VALUE_DEFINITION = typeof ENUM_VALUE_DEFINITION; +export const INPUT_OBJECT_TYPE_DEFINITION = 'InputObjectTypeDefinition'; +export type INPUT_OBJECT_TYPE_DEFINITION = typeof INPUT_OBJECT_TYPE_DEFINITION; + +/** Directive Definitions */ +export const DIRECTIVE_DEFINITION = 'DirectiveDefinition'; +export type DIRECTIVE_DEFINITION = typeof DIRECTIVE_DEFINITION; + +/** Type System Extensions */ +export const SCHEMA_EXTENSION = 'SchemaExtension'; +export type SCHEMA_EXTENSION = typeof SCHEMA_EXTENSION; + +/** Type Extensions */ +export const SCALAR_TYPE_EXTENSION = 'ScalarTypeExtension'; +export type SCALAR_TYPE_EXTENSION = typeof SCALAR_TYPE_EXTENSION; +export const OBJECT_TYPE_EXTENSION = 'ObjectTypeExtension'; +export type OBJECT_TYPE_EXTENSION = typeof OBJECT_TYPE_EXTENSION; +export const INTERFACE_TYPE_EXTENSION = 'InterfaceTypeExtension'; +export type INTERFACE_TYPE_EXTENSION = typeof INTERFACE_TYPE_EXTENSION; +export const UNION_TYPE_EXTENSION = 'UnionTypeExtension'; +export type UNION_TYPE_EXTENSION = typeof UNION_TYPE_EXTENSION; +export const ENUM_TYPE_EXTENSION = 'EnumTypeExtension'; +export type ENUM_TYPE_EXTENSION = typeof ENUM_TYPE_EXTENSION; +export const INPUT_OBJECT_TYPE_EXTENSION = 'InputObjectTypeExtension'; +export type INPUT_OBJECT_TYPE_EXTENSION = typeof INPUT_OBJECT_TYPE_EXTENSION;