diff --git a/packages/import/src/index.ts b/packages/import/src/index.ts index 892c5e55ccc..bcf814c3dd4 100644 --- a/packages/import/src/index.ts +++ b/packages/import/src/index.ts @@ -31,6 +31,8 @@ import { SchemaDefinitionNode, OperationTypeDefinitionNode, DocumentNode, + ScalarTypeDefinitionNode, + ScalarTypeExtensionNode, } from 'graphql'; import { readFileSync, realpathSync } from 'fs-extra'; import { dirname, join, isAbsolute } from 'path'; @@ -138,6 +140,12 @@ function visitFile( case Kind.DIRECTIVE_DEFINITION: visitDirectiveDefinitionNode(definition, dependencySet, dependenciesByDefinitionName); break; + case Kind.SCALAR_TYPE_DEFINITION: + visitScalarDefinitionNode(definition, dependencySet); + break; + case Kind.SCHEMA_DEFINITION: + visitSchemaDefinitionNode(definition, dependencySet); + break; case Kind.OBJECT_TYPE_EXTENSION: visitObjectTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName); break; @@ -153,8 +161,8 @@ function visitFile( case Kind.INPUT_OBJECT_TYPE_EXTENSION: visitInputObjectTypeExtensionNode(definition, dependencySet, dependenciesByDefinitionName); break; - case Kind.SCHEMA_DEFINITION: - visitSchemaDefinitionNode(definition, dependencySet); + case Kind.SCALAR_TYPE_EXTENSION: + visitScalarExtensionNode(definition, dependencySet); break; } if ('fields' in definition) { @@ -365,11 +373,11 @@ function visitObjectTypeDefinitionNode( ) { const typeName = node.name.value; dependencySet.add(typeName); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); - node.fields.forEach(fieldDefinitionNode => + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.fields?.forEach(fieldDefinitionNode => visitFieldDefinitionNode(fieldDefinitionNode, dependencySet, dependenciesByDefinitionName) ); - node.interfaces.forEach(namedTypeNode => { + node.interfaces?.forEach(namedTypeNode => { visitNamedTypeNode(namedTypeNode, dependencySet); const interfaceName = namedTypeNode.name.value; // interface should be dependent to the type as well @@ -392,10 +400,10 @@ function visitFieldDefinitionNode( dependencySet: Set, dependenciesByDefinitionName: Map> ) { - node.arguments.forEach(inputValueDefinitionNode => + node.arguments?.forEach(inputValueDefinitionNode => visitInputValueDefinitionNode(inputValueDefinitionNode, dependencySet, dependenciesByDefinitionName) ); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); visitTypeNode(node.type, dependencySet, dependenciesByDefinitionName); } @@ -445,7 +453,7 @@ function visitInputValueDefinitionNode( dependencySet: Set, dependenciesByDefinitionName: Map> ) { - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); visitTypeNode(node.type, dependencySet, dependenciesByDefinitionName); } @@ -456,8 +464,8 @@ function visitInterfaceTypeDefinitionNode( ) { const typeName = node.name.value; dependencySet.add(typeName); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); - node.fields.forEach(fieldDefinitionNode => + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.fields?.forEach(fieldDefinitionNode => visitFieldDefinitionNode(fieldDefinitionNode, dependencySet, dependenciesByDefinitionName) ); (node as any).interfaces?.forEach((namedTypeNode: NamedTypeNode) => { @@ -473,13 +481,13 @@ function visitInterfaceTypeDefinitionNode( function visitUnionTypeDefinitionNode(node: UnionTypeDefinitionNode, dependencySet: Set) { dependencySet.add(node.name.value); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); node.types.forEach(namedTypeNode => visitNamedTypeNode(namedTypeNode, dependencySet)); } function visitEnumTypeDefinitionNode(node: EnumTypeDefinitionNode, dependencySet: Set) { dependencySet.add(node.name.value); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); } function visitInputObjectTypeDefinitionNode( @@ -488,8 +496,8 @@ function visitInputObjectTypeDefinitionNode( dependenciesByDefinitionName: Map> ) { dependencySet.add(node.name.value); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); - node.fields.forEach(inputValueDefinitionNode => + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.fields?.forEach(inputValueDefinitionNode => visitInputValueDefinitionNode(inputValueDefinitionNode, dependencySet, dependenciesByDefinitionName) ); } @@ -500,7 +508,7 @@ function visitDirectiveDefinitionNode( dependenciesByDefinitionName: Map> ) { dependencySet.add(node.name.value); - node.arguments.forEach(inputValueDefinitionNode => + node.arguments?.forEach(inputValueDefinitionNode => visitInputValueDefinitionNode(inputValueDefinitionNode, dependencySet, dependenciesByDefinitionName) ); } @@ -512,11 +520,11 @@ function visitObjectTypeExtensionNode( ) { const typeName = node.name.value; dependencySet.add(typeName); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); - node.fields.forEach(fieldDefinitionNode => + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.fields?.forEach(fieldDefinitionNode => visitFieldDefinitionNode(fieldDefinitionNode, dependencySet, dependenciesByDefinitionName) ); - node.interfaces.forEach(namedTypeNode => { + node.interfaces?.forEach(namedTypeNode => { visitNamedTypeNode(namedTypeNode, dependencySet); const interfaceName = namedTypeNode.name.value; // interface should be dependent to the type as well @@ -534,8 +542,8 @@ function visitInterfaceTypeExtensionNode( ) { const typeName = node.name.value; dependencySet.add(typeName); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); - node.fields.forEach(fieldDefinitionNode => + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.fields?.forEach(fieldDefinitionNode => visitFieldDefinitionNode(fieldDefinitionNode, dependencySet, dependenciesByDefinitionName) ); (node as any).interfaces?.forEach((namedTypeNode: NamedTypeNode) => { @@ -551,13 +559,13 @@ function visitInterfaceTypeExtensionNode( function visitUnionTypeExtensionNode(node: UnionTypeExtensionNode, dependencySet: Set) { dependencySet.add(node.name.value); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); node.types.forEach(namedTypeNode => visitNamedTypeNode(namedTypeNode, dependencySet)); } function visitEnumTypeExtensionNode(node: EnumTypeExtensionNode, dependencySet: Set) { dependencySet.add(node.name.value); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); } function visitInputObjectTypeExtensionNode( @@ -566,20 +574,30 @@ function visitInputObjectTypeExtensionNode( dependenciesByDefinitionName: Map> ) { dependencySet.add(node.name.value); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); - node.fields.forEach(inputValueDefinitionNode => + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.fields?.forEach(inputValueDefinitionNode => visitInputValueDefinitionNode(inputValueDefinitionNode, dependencySet, dependenciesByDefinitionName) ); } function visitSchemaDefinitionNode(node: SchemaDefinitionNode, dependencySet: Set) { dependencySet.add('schema'); - node.directives.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); node.operationTypes.forEach(operationTypeDefinitionNode => visitOperationTypeDefinitionNode(operationTypeDefinitionNode, dependencySet) ); } +function visitScalarDefinitionNode(node: ScalarTypeDefinitionNode, dependencySet: Set) { + dependencySet.add(node.name.value); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); +} + +function visitScalarExtensionNode(node: ScalarTypeExtensionNode, dependencySet: Set) { + dependencySet.add(node.name.value); + node.directives?.forEach(directiveNode => visitDirectiveNode(directiveNode, dependencySet)); +} + function visitOperationTypeDefinitionNode(node: OperationTypeDefinitionNode, dependencySet: Set) { visitNamedTypeNode(node.type, dependencySet); } diff --git a/packages/import/tests/schema/fixtures/mix-n-match/a.graphql b/packages/import/tests/schema/fixtures/mix-n-match/a.graphql index 9cec6fbf524..a296d31f608 100644 --- a/packages/import/tests/schema/fixtures/mix-n-match/a.graphql +++ b/packages/import/tests/schema/fixtures/mix-n-match/a.graphql @@ -4,4 +4,5 @@ type A { first: String second: Float b: B + date: Date } diff --git a/packages/import/tests/schema/fixtures/mix-n-match/b.graphql b/packages/import/tests/schema/fixtures/mix-n-match/b.graphql index d1072a528eb..d167a24e90f 100644 --- a/packages/import/tests/schema/fixtures/mix-n-match/b.graphql +++ b/packages/import/tests/schema/fixtures/mix-n-match/b.graphql @@ -1,4 +1,5 @@ # import C1, C2 from '../import-all/c.graphql' +scalar Date type B { hello: String! c1: C1 diff --git a/packages/import/tests/schema/import-schema.spec.ts b/packages/import/tests/schema/import-schema.spec.ts index 4ed3ac5aaef..bbddb4141d0 100644 --- a/packages/import/tests/schema/import-schema.spec.ts +++ b/packages/import/tests/schema/import-schema.spec.ts @@ -6,7 +6,7 @@ import { Kind, print } from 'graphql'; const importSchema = (schema: string, schemas?: Record) => { const document = processImport(schema, __dirname, schemas); - return print(mergeTypeDefs(document.definitions.map(definition => ({ kind: Kind.DOCUMENT, definitions: [definition]})), { + return print(mergeTypeDefs(document.definitions.map(definition => ({ kind: Kind.DOCUMENT, definitions: [definition] })), { sort: true, useSchemaDefinition: false, })) @@ -290,10 +290,13 @@ describe('importSchema', () => { test(`importSchema: import all mix 'n match`, () => { const expectedSDL = /* GraphQL */`\ + scalar Date + type A { first: String second: Float b: B + date: Date } type C1 { diff --git a/packages/node-require/package.json b/packages/node-require/package.json new file mode 100644 index 00000000000..55e288a40fc --- /dev/null +++ b/packages/node-require/package.json @@ -0,0 +1,29 @@ +{ + "name": "@graphql-tools/node-require", + "version": "6.0.5", + "description": "A set of utils for faster development of GraphQL tools", + "repository": "git@github.com:ardatan/graphql-tools.git", + "license": "MIT", + "sideEffects": false, + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "typings": "dist/index.d.ts", + "typescript": { + "definition": "dist/index.d.ts" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0" + }, + "buildOptions": { + "input": "./src/index.ts" + }, + "dependencies": { + "@graphql-tools/load": "6.0.5", + "@graphql-tools/graphql-file-loader": "6.0.5", + "tslib": "~2.0.0" + }, + "publishConfig": { + "access": "public", + "directory": "dist" + } +} diff --git a/packages/node-require/src/declarations.d.ts b/packages/node-require/src/declarations.d.ts new file mode 100644 index 00000000000..5e21ef929d0 --- /dev/null +++ b/packages/node-require/src/declarations.d.ts @@ -0,0 +1,28 @@ +/* eslint-disable import/no-duplicates */ +declare module '*.graphql' { + import { DocumentNode } from 'graphql'; + + const value: DocumentNode; + export = value; +} + +declare module '*.gql' { + import { DocumentNode } from 'graphql'; + + const value: DocumentNode; + export = value; +} + +declare module '*.gqls' { + import { DocumentNode } from 'graphql'; + + const value: DocumentNode; + export = value; +} + +declare module '*.graphqls' { + import { DocumentNode } from 'graphql'; + + const value: DocumentNode; + export = value; +} diff --git a/packages/node-require/src/index.ts b/packages/node-require/src/index.ts new file mode 100644 index 00000000000..3b7ee84a928 --- /dev/null +++ b/packages/node-require/src/index.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/triple-slash-reference */ +/* eslint-disable spaced-comment */ +/* eslint-disable node/no-deprecated-api */ + +/// + +import { loadTypedefsSync } from '@graphql-tools/load'; +import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'; +import { concatAST } from 'graphql'; + +const VALID_EXTENSIONS = ['graphql', 'graphqls', 'gql', 'gqls']; + +function handleModule(m: NodeModule, filename: string) { + console.log(m, filename); + const sources = loadTypedefsSync(filename, { + loaders: [new GraphQLFileLoader()], + }); + + const documents = sources.map(source => source.document); + const mergedDoc = concatAST(documents); + m.exports = mergedDoc; +} + +export function registerGraphQLExtensions(require: NodeRequire) { + VALID_EXTENSIONS.forEach(ext => { + require.extensions[`.${ext}`] = handleModule; + }); +} + +registerGraphQLExtensions(require); diff --git a/packages/node-require/test/fixtures/test.graphql b/packages/node-require/test/fixtures/test.graphql new file mode 100644 index 00000000000..6a59a3af225 --- /dev/null +++ b/packages/node-require/test/fixtures/test.graphql @@ -0,0 +1,3 @@ +type Query { + foo: String +} diff --git a/packages/node-require/test/node-require.spec.ts b/packages/node-require/test/node-require.spec.ts new file mode 100644 index 00000000000..8fc5b9c6f6d --- /dev/null +++ b/packages/node-require/test/node-require.spec.ts @@ -0,0 +1,13 @@ +import '../src'; +import { print } from 'graphql'; +import { readFileSync } from 'fs'; + +describe('GraphQL Node Import', () => { + it.skip('should import correct definitions', () => { + const filePath = './fixtures/test.graphql'; + const typeDefs = require(filePath); + expect(print(typeDefs).replace(/\s\s+/g, ' ')).toBe( + readFileSync(require.resolve(filePath), 'utf8').replace(/\s\s+/g, ' ') + ); + }); +}); diff --git a/packages/webpack-loader/package.json b/packages/webpack-loader/package.json new file mode 100644 index 00000000000..3b263c61e4a --- /dev/null +++ b/packages/webpack-loader/package.json @@ -0,0 +1,29 @@ +{ + "name": "@graphql-tools/webpack-loader", + "version": "6.0.5", + "description": "A set of utils for faster development of GraphQL tools", + "repository": "git@github.com:ardatan/graphql-tools.git", + "license": "MIT", + "sideEffects": false, + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "typings": "dist/index.d.ts", + "typescript": { + "definition": "dist/index.d.ts" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0" + }, + "buildOptions": { + "input": "./src/index.ts" + }, + "dependencies": { + "@graphql-tools/load": "6.0.5", + "@graphql-tools/graphql-file-loader": "6.0.5", + "tslib": "~2.0.0" + }, + "publishConfig": { + "access": "public", + "directory": "dist" + } +} diff --git a/packages/webpack-loader/src/index.ts b/packages/webpack-loader/src/index.ts new file mode 100644 index 00000000000..d5ce628001a --- /dev/null +++ b/packages/webpack-loader/src/index.ts @@ -0,0 +1,17 @@ +import { loadTypedefs } from '@graphql-tools/load'; +import { GraphQLFileLoader } from 'packages/graphql-tools/src'; +import { concatAST } from 'graphql'; + +export default function (this: any, path: string) { + const callback = this.async(); + + this.cacheable(); + + loadTypedefs(path, { + loaders: [new GraphQLFileLoader()], + }).then(sources => { + const documents = sources.map(source => source.document); + const mergedDoc = concatAST(documents); + return callback(null, `module.exports = ${JSON.stringify(mergedDoc)}`); + }); +}