Comparing version 0.0.0-main-6a722399 to 0.0.0-main-6ca96c43
{ | ||
"name": "grats", | ||
"version": "0.0.4", | ||
"version": "0.0.9", | ||
"main": "dist/src/index.js", | ||
@@ -15,11 +15,12 @@ "bin": "dist/src/cli.js", | ||
"build": "tsc --build", | ||
"lint": "eslint src/**/*.ts" | ||
"format": "prettier . --write", | ||
"lint": "eslint src/**/*.ts && prettier . --check" | ||
}, | ||
"dependencies": { | ||
"@graphql-tools/utils": "^9.2.1", | ||
"commander": "^10.0.0", | ||
"graphql": "^16.6.0", | ||
"typescript": "^4.9.5" | ||
"typescript": "^5.0.2" | ||
}, | ||
"devDependencies": { | ||
"@graphql-tools/utils": "^9.2.1", | ||
"@types/node": "^18.14.6", | ||
@@ -32,2 +33,3 @@ "@typescript-eslint/eslint-plugin": "^5.55.0", | ||
"path-browserify": "^1.0.1", | ||
"prettier": "^2.8.7", | ||
"process": "^0.11.10", | ||
@@ -39,3 +41,3 @@ "ts-node": "^10.9.1" | ||
}, | ||
"packageManager": "pnpm@8.1.1", | ||
"packageManager": "pnpm@8.12.0", | ||
"engines": { | ||
@@ -42,0 +44,0 @@ "node": ">=16 <=21", |
@@ -39,3 +39,3 @@ #!/usr/bin/env node | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.formatLoc = void 0; | ||
@@ -45,3 +45,2 @@ var graphql_1 = require("graphql"); | ||
var lib_1 = require("./lib"); | ||
var utils_1 = require("@graphql-tools/utils"); | ||
var commander_1 = require("commander"); | ||
@@ -52,2 +51,4 @@ var fs_1 = require("fs"); | ||
var Locate_1 = require("./Locate"); | ||
var printSchema_1 = require("./printSchema"); | ||
var ts = require("typescript"); | ||
var program = new commander_1.Command(); | ||
@@ -58,9 +59,8 @@ program | ||
.version(package_json_1.version) | ||
.option("-o, --output <SCHEMA_FILE>", "Where to write the schema file. Defaults to stdout") | ||
.option("--tsconfig <TSCONFIG>", "Path to tsconfig.json. Defaults to auto-detecting based on the current working directory") | ||
.action(function (_a) { | ||
var output = _a.output, tsconfig = _a.tsconfig; | ||
var tsconfig = _a.tsconfig; | ||
return __awaiter(void 0, void 0, void 0, function () { | ||
return __generator(this, function (_b) { | ||
build(output, tsconfig); | ||
build(tsconfig); | ||
return [2 /*return*/]; | ||
@@ -76,3 +76,4 @@ }); | ||
var tsconfig = _a.tsconfig; | ||
var schema = buildSchema(tsconfig); | ||
var config = getTsConfig(tsconfig).config; | ||
var schema = buildSchema(config); | ||
var loc = (0, Locate_1.locate)(schema, entity); | ||
@@ -86,26 +87,31 @@ if (loc.kind === "ERROR") { | ||
program.parse(); | ||
function build(output, tsconfig) { | ||
var schema = buildSchema(tsconfig); | ||
function build(tsconfig) { | ||
var _a = getTsConfig(tsconfig), config = _a.config, configPath = _a.configPath; | ||
var schema = buildSchema(config); | ||
var sortedSchema = (0, graphql_1.lexicographicSortSchema)(schema); | ||
var schemaStr = (0, utils_1.printSchemaWithDirectives)(sortedSchema, { | ||
assumeValid: true | ||
}); | ||
if (output) { | ||
var absOutput = (0, path_1.resolve)(process.cwd(), output); | ||
(0, fs_1.writeFileSync)(absOutput, schemaStr); | ||
console.error("Grats: Wrote schema to `".concat(absOutput, "`.")); | ||
var gratsOptions = config.raw.grats; | ||
var dest = (0, path_1.resolve)((0, path_1.dirname)(configPath), gratsOptions.tsSchema); | ||
var code = (0, printSchema_1.printExecutableSchema)(sortedSchema, gratsOptions, dest); | ||
(0, fs_1.writeFileSync)(dest, code); | ||
console.error("Grats: Wrote TypeScript schema to `".concat(dest, "`.")); | ||
var schemaStr = (0, printSchema_1.printGratsSDL)(sortedSchema, gratsOptions); | ||
var absOutput = (0, path_1.resolve)((0, path_1.dirname)(configPath), gratsOptions.graphqlSchema); | ||
(0, fs_1.writeFileSync)(absOutput, schemaStr); | ||
console.error("Grats: Wrote schema to `".concat(absOutput, "`.")); | ||
} | ||
// Locate and read the tsconfig.json file | ||
function getTsConfig(tsconfig) { | ||
var configPath = tsconfig || ts.findConfigFile(process.cwd(), ts.sys.fileExists); | ||
if (configPath == null) { | ||
throw new Error("Grats: Could not find tsconfig.json"); | ||
} | ||
else { | ||
console.log(schemaStr); | ||
var optionsResult = (0, _1.getParsedTsConfig)(configPath); | ||
if (optionsResult.kind === "ERROR") { | ||
console.error(optionsResult.err.formatDiagnosticsWithColorAndContext()); | ||
process.exit(1); | ||
} | ||
return { configPath: configPath, config: optionsResult.value }; | ||
} | ||
function buildSchema(tsconfig) { | ||
if (tsconfig && !(0, fs_1.existsSync)(tsconfig)) { | ||
console.error("Grats: Could not find tsconfig.json at `".concat(tsconfig, "`.")); | ||
process.exit(1); | ||
} | ||
var parsed = (0, _1.getParsedTsConfig)(tsconfig); | ||
// FIXME: Validate config! | ||
// https://github.com/tsconfig/bases | ||
var schemaResult = (0, lib_1.buildSchemaResult)(parsed); | ||
function buildSchema(options) { | ||
var schemaResult = (0, lib_1.buildSchemaResult)(options); | ||
if (schemaResult.kind === "ERROR") { | ||
@@ -112,0 +118,0 @@ console.error(schemaResult.err.formatDiagnosticsWithColorAndContext()); |
@@ -34,4 +34,4 @@ /** | ||
export declare function inputFieldUntyped(): string; | ||
export declare function typeTagOnUnamedClass(): string; | ||
export declare function typeTagOnAliasOfNonObject(): string; | ||
export declare function typeTagOnUnnamedClass(): string; | ||
export declare function typeTagOnAliasOfNonObjectOrUnknown(): string; | ||
export declare function typeNameNotDeclaration(): string; | ||
@@ -88,1 +88,7 @@ export declare function typeNameMissingInitializer(): string; | ||
export declare function multipleContextTypes(): string; | ||
export declare function graphQLNameHasLeadingNewlines(name: string, tagName: string): string; | ||
export declare function graphQLTagNameHasWhitespace(tagName: string): string; | ||
export declare function subscriptionFieldNotAsyncIterable(): string; | ||
export declare function nonSubscriptionFieldAsyncIterable(): string; | ||
export declare function operationTypeNotUnknown(): string; | ||
export declare function expectedNullableArgumentToBeOptional(): string; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.defaultArgPropertyMissingName = exports.defaultArgElementIsNotAssignment = exports.defaultValueIsNotLiteral = exports.ambiguousNumberType = exports.expectedOneNonNullishType = exports.propertyFieldMissingType = exports.cannotResolveSymbolForDescription = exports.promiseMissingTypeArg = exports.methodMissingType = exports.gqlEntityMissingName = exports.enumVariantMissingInitializer = exports.enumVariantNotStringLiteral = exports.enumTagOnInvalidNode = exports.argNotTyped = exports.argNameNotLiteral = exports.argIsNotProperty = exports.argumentParamIsNotObject = exports.argumentParamIsMissingType = exports.typeNameDoesNotMatchExpected = exports.typeNameTypeNotStringLiteral = exports.typeNameMissingTypeAnnotation = exports.typeNameInitializerWrong = exports.typeNameInitializeNotString = exports.typeNameMissingInitializer = exports.typeNameNotDeclaration = exports.typeTagOnAliasOfNonObject = exports.typeTagOnUnamedClass = exports.inputFieldUntyped = exports.inputTypeFieldNotProperty = exports.inputTypeNotLiteral = exports.functionFieldNotNamedExport = exports.functionFieldDefaultExport = exports.functionFieldNotNamed = exports.functionFieldParentTypeNotValid = exports.functionFieldParentTypeMissing = exports.functionFieldNotTopLevel = exports.invalidReturnTypeForFunctionField = exports.invalidParentArgForFunctionField = exports.expectedUnionTypeReference = exports.expectedUnionTypeNode = exports.invalidUnionTagUsage = exports.invalidInputTagUsage = exports.invalidEnumTagUsage = exports.invalidInterfaceTagUsage = exports.invalidScalarTagUsage = exports.invalidTypeTagUsage = exports.invalidGratsTag = exports.wrongCasingForGratsTag = exports.killsParentOnExceptionOnWrongNode = exports.fieldTagOnWrongNode = void 0; | ||
exports.multipleContextTypes = exports.unexpectedParamSpreadForContextParam = exports.expectedTypeAnnotationOnContextToHaveDeclaration = exports.expectedTypeAnnotationOnContextToBeResolvable = exports.expectedTypeAnnotationOfReferenceOnContext = exports.expectedTypeAnnotationOnContext = exports.unresolvedTypeReference = exports.invalidTypePassedToFieldFunction = exports.parameterPropertyMissingType = exports.parameterPropertyNotPublic = exports.parameterWithoutModifiers = exports.duplicateInterfaceTag = exports.duplicateTag = exports.implementsTagOnTypeAlias = exports.implementsTagOnInterface = exports.implementsTagOnClass = exports.implementsTagMissingValue = exports.mergedInterfaces = exports.nonNullTypeCannotBeOptional = exports.killsParentOnExceptionOnNullable = exports.killsParentOnExceptionWithWrongConfig = exports.expectedIdentifier = exports.pluralTypeMissingParameter = exports.unknownGraphQLType = exports.unsupportedTypeLiteral = exports.defaultArgPropertyMissingInitializer = void 0; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defaultArgPropertyMissingName = exports.defaultArgElementIsNotAssignment = exports.defaultValueIsNotLiteral = exports.ambiguousNumberType = exports.expectedOneNonNullishType = exports.propertyFieldMissingType = exports.cannotResolveSymbolForDescription = exports.promiseMissingTypeArg = exports.methodMissingType = exports.gqlEntityMissingName = exports.enumVariantMissingInitializer = exports.enumVariantNotStringLiteral = exports.enumTagOnInvalidNode = exports.argNotTyped = exports.argNameNotLiteral = exports.argIsNotProperty = exports.argumentParamIsNotObject = exports.argumentParamIsMissingType = exports.typeNameDoesNotMatchExpected = exports.typeNameTypeNotStringLiteral = exports.typeNameMissingTypeAnnotation = exports.typeNameInitializerWrong = exports.typeNameInitializeNotString = exports.typeNameMissingInitializer = exports.typeNameNotDeclaration = exports.typeTagOnAliasOfNonObjectOrUnknown = exports.typeTagOnUnnamedClass = exports.inputFieldUntyped = exports.inputTypeFieldNotProperty = exports.inputTypeNotLiteral = exports.functionFieldNotNamedExport = exports.functionFieldDefaultExport = exports.functionFieldNotNamed = exports.functionFieldParentTypeNotValid = exports.functionFieldParentTypeMissing = exports.functionFieldNotTopLevel = exports.invalidReturnTypeForFunctionField = exports.invalidParentArgForFunctionField = exports.expectedUnionTypeReference = exports.expectedUnionTypeNode = exports.invalidUnionTagUsage = exports.invalidInputTagUsage = exports.invalidEnumTagUsage = exports.invalidInterfaceTagUsage = exports.invalidScalarTagUsage = exports.invalidTypeTagUsage = exports.invalidGratsTag = exports.wrongCasingForGratsTag = exports.killsParentOnExceptionOnWrongNode = exports.fieldTagOnWrongNode = void 0; | ||
exports.expectedNullableArgumentToBeOptional = exports.operationTypeNotUnknown = exports.nonSubscriptionFieldAsyncIterable = exports.subscriptionFieldNotAsyncIterable = exports.graphQLTagNameHasWhitespace = exports.graphQLNameHasLeadingNewlines = exports.multipleContextTypes = exports.unexpectedParamSpreadForContextParam = exports.expectedTypeAnnotationOnContextToHaveDeclaration = exports.expectedTypeAnnotationOnContextToBeResolvable = exports.expectedTypeAnnotationOfReferenceOnContext = exports.expectedTypeAnnotationOnContext = exports.unresolvedTypeReference = exports.invalidTypePassedToFieldFunction = exports.parameterPropertyMissingType = exports.parameterPropertyNotPublic = exports.parameterWithoutModifiers = exports.duplicateInterfaceTag = exports.duplicateTag = exports.implementsTagOnTypeAlias = exports.implementsTagOnInterface = exports.implementsTagOnClass = exports.implementsTagMissingValue = exports.mergedInterfaces = exports.nonNullTypeCannotBeOptional = exports.killsParentOnExceptionOnNullable = exports.killsParentOnExceptionWithWrongConfig = exports.expectedIdentifier = exports.pluralTypeMissingParameter = exports.unknownGraphQLType = exports.unsupportedTypeLiteral = exports.defaultArgPropertyMissingInitializer = void 0; | ||
var Extractor_1 = require("./Extractor"); | ||
// TODO: Move these to short URLS that are easier to keep from breaking. | ||
var DOC_URLS = { | ||
mergedInterfaces: "https://grats.capt.dev/docs/dockblock-tags/interfaces/#merged-interfaces", | ||
parameterProperties: "https://grats.capt.dev/docs/dockblock-tags/fields#class-based-fields", | ||
typeImplementsInterface: "TODO" | ||
mergedInterfaces: "https://grats.capt.dev/docs/docblock-tags/interfaces/#merged-interfaces", | ||
parameterProperties: "https://grats.capt.dev/docs/docblock-tags/fields#class-based-fields", | ||
}; | ||
@@ -115,10 +114,10 @@ /** | ||
exports.inputFieldUntyped = inputFieldUntyped; | ||
function typeTagOnUnamedClass() { | ||
function typeTagOnUnnamedClass() { | ||
return "Unexpected `@".concat(Extractor_1.TYPE_TAG, "` annotation on unnamed class declaration."); | ||
} | ||
exports.typeTagOnUnamedClass = typeTagOnUnamedClass; | ||
function typeTagOnAliasOfNonObject() { | ||
return "Expected `@".concat(Extractor_1.TYPE_TAG, "` type to be a type literal. For example: `type Foo = { bar: string }`"); | ||
exports.typeTagOnUnnamedClass = typeTagOnUnnamedClass; | ||
function typeTagOnAliasOfNonObjectOrUnknown() { | ||
return "Expected `@".concat(Extractor_1.TYPE_TAG, "` type to be an object type literal (`{ }`) or `unknown`. For example: `type Foo = { bar: string }` or `type Query = unknown`."); | ||
} | ||
exports.typeTagOnAliasOfNonObject = typeTagOnAliasOfNonObject; | ||
exports.typeTagOnAliasOfNonObjectOrUnknown = typeTagOnAliasOfNonObjectOrUnknown; | ||
function typeNameNotDeclaration() { | ||
@@ -249,7 +248,7 @@ return "Expected `__typename` to be a property declaration."; | ||
function killsParentOnExceptionOnNullable() { | ||
return "Unexpected `@".concat(Extractor_1.KILLS_PARENT_ON_EXCEPTION_TAG, "` tag. `@").concat(Extractor_1.KILLS_PARENT_ON_EXCEPTION_TAG, "` is unnessesary on fields that are already nullable."); | ||
return "Unexpected `@".concat(Extractor_1.KILLS_PARENT_ON_EXCEPTION_TAG, "` tag. `@").concat(Extractor_1.KILLS_PARENT_ON_EXCEPTION_TAG, "` is unnecessary on fields that are already nullable."); | ||
} | ||
exports.killsParentOnExceptionOnNullable = killsParentOnExceptionOnNullable; | ||
function nonNullTypeCannotBeOptional() { | ||
return "Unexpected optional argument that does not also accept `null`. Optional arguments in GraphQL may get passed an explict `null` value. This means optional arguments must be typed to also accept `null`."; | ||
return "Unexpected optional argument that does not also accept `null`. Optional arguments in GraphQL may get passed an explicit `null` value. This means optional arguments must be typed to also accept `null`."; | ||
} | ||
@@ -280,3 +279,3 @@ exports.nonNullTypeCannotBeOptional = nonNullTypeCannotBeOptional; | ||
function implementsTagOnTypeAlias() { | ||
return "`@".concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, "` has been deprecated. Types which implement GraphQL interfaces should be defined using TypeScript class or interface declarations. Learn more: ").concat(DOC_URLS.typeImplementsInterface, "."); | ||
return "`@".concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, "` has been deprecated. Types which implement GraphQL interfaces should be defined using TypeScript class or interface declarations."); | ||
} | ||
@@ -344,1 +343,25 @@ exports.implementsTagOnTypeAlias = implementsTagOnTypeAlias; | ||
exports.multipleContextTypes = multipleContextTypes; | ||
function graphQLNameHasLeadingNewlines(name, tagName) { | ||
return "Expected the GraphQL name `".concat(name, "` to be on the same line as it's `@").concat(tagName, "` tag."); | ||
} | ||
exports.graphQLNameHasLeadingNewlines = graphQLNameHasLeadingNewlines; | ||
function graphQLTagNameHasWhitespace(tagName) { | ||
return "Expected text following a `@".concat(tagName, "` tag to be a GraphQL name. If you intended this text to be a description, place it at the top of the docblock before any `@tags`."); | ||
} | ||
exports.graphQLTagNameHasWhitespace = graphQLTagNameHasWhitespace; | ||
function subscriptionFieldNotAsyncIterable() { | ||
return "Expected fields on `Subscription` to return an AsyncIterable."; | ||
} | ||
exports.subscriptionFieldNotAsyncIterable = subscriptionFieldNotAsyncIterable; | ||
function nonSubscriptionFieldAsyncIterable() { | ||
return "Unexpected AsyncIterable. Only fields on `Subscription` should return an AsyncIterable."; | ||
} | ||
exports.nonSubscriptionFieldAsyncIterable = nonSubscriptionFieldAsyncIterable; | ||
function operationTypeNotUnknown() { | ||
return "Operation types `Query`, `Mutation`, and `Subscription` must be defined as type aliases of `unknown`. E.g. `type Query = unknown`."; | ||
} | ||
exports.operationTypeNotUnknown = operationTypeNotUnknown; | ||
function expectedNullableArgumentToBeOptional() { | ||
return "Expected nullable argument to be optional. graphql-js may not define properties where an undefined argument is passed. To guard against this add a `?` to the end of the argument name to make it optional."; | ||
} | ||
exports.expectedNullableArgumentToBeOptional = expectedNullableArgumentToBeOptional; |
@@ -65,2 +65,3 @@ import { FieldDefinitionNode, InputValueDefinitionNode, NamedTypeNode, NameNode, TypeNode, StringValueNode, ConstValueNode, ConstDirectiveNode, EnumValueDefinitionNode, ConstObjectFieldNode, ConstObjectValueNode, ConstListValueNode } from "graphql"; | ||
typeClassDeclaration(node: ts.ClassDeclaration, tag: ts.JSDocTag): null | undefined; | ||
validateOperationTypes(node: ts.Node, name: string): void; | ||
typeInterfaceDeclaration(node: ts.InterfaceDeclaration, tag: ts.JSDocTag): null | undefined; | ||
@@ -95,5 +96,8 @@ typeTypeAliasDeclaration(node: ts.TypeAliasDeclaration, tag: ts.JSDocTag): null | undefined; | ||
methodDeclaration(node: ts.MethodDeclaration | ts.MethodSignature): FieldDefinitionNode | null; | ||
collectMethodType(node: ts.TypeNode): TypeNode | null; | ||
collectReturnType(node: ts.TypeNode): { | ||
type: TypeNode; | ||
isStream: boolean; | ||
} | null; | ||
collectPropertyType(node: ts.TypeNode): TypeNode | null; | ||
maybeUnwrapePromise(node: ts.TypeNode): ts.TypeNode | null; | ||
maybeUnwrapPromise(node: ts.TypeNode): ts.TypeNode | null; | ||
collectDescription(node: ts.Node): StringValueNode | null; | ||
@@ -108,5 +112,5 @@ collectDeprecated(node: ts.Node): ConstDirectiveNode | null; | ||
handleErrorBubbling(parentNode: ts.Node, type: TypeNode): TypeNode; | ||
exportDirective(nameNode: ts.Node, filename: string, functionName: string): ConstDirectiveNode; | ||
exportDirective(nameNode: ts.Node, jsModulePath: string, tsModulePath: string, functionName: string, argCount: number): ConstDirectiveNode; | ||
fieldNameDirective(nameNode: ts.Node, name: string): ConstDirectiveNode; | ||
} | ||
export {}; |
@@ -29,3 +29,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Extractor = exports.ALL_TAGS = exports.KILLS_PARENT_ON_EXCEPTION_TAG = exports.IMPLEMENTS_TAG_DEPRECATED = exports.INPUT_TAG = exports.UNION_TAG = exports.ENUM_TAG = exports.INTERFACE_TAG = exports.SCALAR_TAG = exports.FIELD_TAG = exports.TYPE_TAG = exports.ISSUE_URL = exports.LIBRARY_NAME = exports.LIBRARY_IMPORT_NAME = void 0; | ||
@@ -63,2 +63,3 @@ var graphql_1 = require("graphql"); | ||
var DEPRECATED_TAG = "deprecated"; | ||
var OPERATION_TYPES = new Set(["Query", "Mutation", "Subscription"]); | ||
/** | ||
@@ -149,3 +150,3 @@ * Extracts GraphQL definitions from TypeScript source code. | ||
try { | ||
if (ALL_TAGS_1_1 && !ALL_TAGS_1_1.done && (_a = ALL_TAGS_1["return"])) _a.call(ALL_TAGS_1); | ||
if (ALL_TAGS_1_1 && !ALL_TAGS_1_1.done && (_a = ALL_TAGS_1.return)) _a.call(ALL_TAGS_1); | ||
} | ||
@@ -233,3 +234,3 @@ finally { if (e_1) throw e_1.error; } | ||
length: length, | ||
relatedInformation: relatedInformation | ||
relatedInformation: relatedInformation, | ||
}); | ||
@@ -252,3 +253,3 @@ return null; | ||
length: node.getWidth(), | ||
messageText: message | ||
messageText: message, | ||
}; | ||
@@ -286,3 +287,3 @@ }; | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -311,5 +312,6 @@ finally { if (e_2) throw e_2.error; } | ||
} | ||
var type = this.collectMethodType(node.type); | ||
if (type == null) | ||
var returnType = this.collectReturnType(node.type); | ||
if (returnType == null) | ||
return null; | ||
var type = returnType.type, isStream = returnType.isStream; | ||
var args = null; | ||
@@ -329,8 +331,8 @@ var argsParam = node.parameters[1]; | ||
// TODO: Does this work in the browser? | ||
var filename = this.ctx.getDestFilePath(node.parent); | ||
var _a = this.ctx.getDestFilePath(node.parent), jsModulePath = _a.jsModulePath, tsModulePath = _a.tsModulePath; | ||
var directives = [ | ||
this.exportDirective(funcName, filename, funcName.text), | ||
this.exportDirective(funcName, jsModulePath, tsModulePath, funcName.text, node.parameters.length), | ||
]; | ||
if (funcName.text !== name.value) { | ||
directives.push(this.fieldNameDirective(funcName, funcName.text)); | ||
if (isStream) { | ||
directives.push(this.gql.constDirective(node.type, this.gql.name(node.type, serverDirectives_1.ASYNC_ITERABLE_TYPE_DIRECTIVE), null)); | ||
} | ||
@@ -415,3 +417,3 @@ var deprecated = this.collectDeprecated(node); | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -439,3 +441,3 @@ finally { if (e_3) throw e_3.error; } | ||
if (node.name == null) { | ||
return this.report(node, E.typeTagOnUnamedClass()); | ||
return this.report(node, E.typeTagOnUnnamedClass()); | ||
} | ||
@@ -445,2 +447,3 @@ var name = this.entityName(node, tag); | ||
return null; | ||
this.validateOperationTypes(node.name, name.value); | ||
var description = this.collectDescription(node.name); | ||
@@ -453,2 +456,9 @@ var fields = this.collectFields(node); | ||
}; | ||
Extractor.prototype.validateOperationTypes = function (node, name) { | ||
// TODO: If we start supporting defining operation types using | ||
// non-standard names, we will need to update this logic. | ||
if (OPERATION_TYPES.has(name)) { | ||
this.report(node, E.operationTypeNotUnknown()); | ||
} | ||
}; | ||
Extractor.prototype.typeInterfaceDeclaration = function (node, tag) { | ||
@@ -458,2 +468,3 @@ var name = this.entityName(node, tag); | ||
return null; | ||
this.validateOperationTypes(node.name, name.value); | ||
var description = this.collectDescription(node.name); | ||
@@ -470,11 +481,20 @@ var fields = this.collectFields(node); | ||
return null; | ||
if (!ts.isTypeLiteralNode(node.type)) { | ||
this.reportUnhandled(node.type, "type", E.typeTagOnAliasOfNonObject()); | ||
return; | ||
var fields = []; | ||
var interfaces = null; | ||
if (ts.isTypeLiteralNode(node.type)) { | ||
this.validateOperationTypes(node.type, name.value); | ||
fields = this.collectFields(node.type); | ||
interfaces = this.collectInterfaces(node); | ||
this.checkForTypenameProperty(node.type, name.value); | ||
} | ||
else if (node.type.kind === ts.SyntaxKind.UnknownKeyword) { | ||
// This is fine, we just don't know what it is. This should be the expected | ||
// case for operation types such as `Query`, `Mutation`, and `Subscription` | ||
// where there is not strong convention around. | ||
} | ||
else { | ||
return this.report(node.type, E.typeTagOnAliasOfNonObjectOrUnknown()); | ||
} | ||
var description = this.collectDescription(node.name); | ||
var fields = this.collectFields(node.type); | ||
var interfaces = this.collectInterfaces(node); | ||
this.ctx.recordTypeName(node.name, name, "TYPE"); | ||
this.checkForTypenameProperty(node.type, name.value); | ||
this.definitions.push(this.gql.objectTypeDefinition(node, name, fields, interfaces, description)); | ||
@@ -658,3 +678,3 @@ }; | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -759,3 +779,3 @@ finally { if (e_4) throw e_4.error; } | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -782,3 +802,3 @@ finally { if (e_5) throw e_5.error; } | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -799,3 +819,3 @@ finally { if (e_6) throw e_6.error; } | ||
else if (this.isNullish(node)) { | ||
return this.gql["null"](node); | ||
return this.gql.null(node); | ||
} | ||
@@ -835,3 +855,3 @@ else if (node.kind === ts.SyntaxKind.TrueKeyword) { | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -864,3 +884,3 @@ finally { if (e_7) throw e_7.error; } | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -908,9 +928,17 @@ finally { if (e_8) throw e_8.error; } | ||
return null; | ||
if (type.kind !== graphql_1.Kind.NON_NULL_TYPE && !node.questionToken) { | ||
// If a field is passed an argument value, and that argument is not defined in the request, | ||
// `graphql-js` will not define the argument property. Therefore we must ensure the argument | ||
// is not just nullable, but optional. | ||
return this.report(node.name, E.expectedNullableArgumentToBeOptional()); | ||
} | ||
if (node.questionToken) { | ||
/* | ||
// TODO: Don't allow args that are optional but don't accept null | ||
if (type.kind === Kind.NON_NULL_TYPE) { | ||
return this.report(node.questionToken, E.nonNullTypeCannotBeOptional()); | ||
// Question mark means we can handle the argument being undefined in the | ||
// object literal, but if we are going to type the GraphQL arg as | ||
// optional, the code must also be able to handle an explicit null. | ||
// | ||
// TODO: This will catch { a?: string } but not { a?: string | undefined }. | ||
if (type.kind === graphql_1.Kind.NON_NULL_TYPE) { | ||
return this.report(node.questionToken, E.nonNullTypeCannotBeOptional()); | ||
} | ||
*/ | ||
type = this.gql.nullableType(type); | ||
@@ -1005,3 +1033,3 @@ } | ||
try { | ||
if (_d && !_d.done && (_a = _c["return"])) _a.call(_c); | ||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c); | ||
} | ||
@@ -1031,3 +1059,3 @@ finally { if (e_9) throw e_9.error; } | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -1043,3 +1071,24 @@ finally { if (e_10) throw e_10.error; } | ||
// FIXME: Use the _value_'s location not the tag's | ||
return this.gql.name(tag, commentName); | ||
var locNode = tag; | ||
// Test for leading newlines using the raw text | ||
var hasLeadingNewlines = /\n/.test(tag.getText().trimEnd()); | ||
var hasInternalWhitespace = /\s/.test(commentName); | ||
var validationMessage = graphQLNameValidationMessage(commentName); | ||
if (hasLeadingNewlines && validationMessage == null) { | ||
// TODO: Offer quick fix. | ||
return this.report(locNode, E.graphQLNameHasLeadingNewlines(commentName, tag.tagName.text)); | ||
} | ||
if (hasLeadingNewlines || hasInternalWhitespace) { | ||
return this.report(locNode, E.graphQLTagNameHasWhitespace(tag.tagName.text)); | ||
} | ||
// No whitespace, but still invalid. We will assume they meant this to | ||
// be a GraphQL name but didn't provide a valid identifier. | ||
// | ||
// NOTE: We can't let GraphQL validation handle this, because it throws rather | ||
// than returning a validation message. Presumably because it expects token | ||
// validation to be done during lexing/parsing. | ||
if (validationMessage !== null) { | ||
return this.report(locNode, validationMessage); | ||
} | ||
return this.gql.name(locNode, commentName); | ||
} | ||
@@ -1085,3 +1134,3 @@ } | ||
declaration: declaration, | ||
firstReference: node.type.typeName | ||
firstReference: node.type.typeName, | ||
}; | ||
@@ -1105,3 +1154,6 @@ } | ||
} | ||
var type = this.collectMethodType(node.type); | ||
var returnType = this.collectReturnType(node.type); | ||
if (returnType == null) | ||
return null; | ||
var type = returnType.type, isStream = returnType.isStream; | ||
// We already reported an error | ||
@@ -1127,2 +1179,5 @@ if (type == null) | ||
} | ||
if (isStream) { | ||
directives.push(this.gql.constDirective(node.type, this.gql.name(node.type, serverDirectives_1.ASYNC_ITERABLE_TYPE_DIRECTIVE), null)); | ||
} | ||
var deprecated = this.collectDeprecated(node); | ||
@@ -1134,11 +1189,29 @@ if (deprecated != null) { | ||
}; | ||
Extractor.prototype.collectMethodType = function (node) { | ||
var inner = this.maybeUnwrapePromise(node); | ||
Extractor.prototype.collectReturnType = function (node) { | ||
if (ts.isTypeReferenceNode(node)) { | ||
var identifier = this.expectIdentifier(node.typeName); | ||
if (identifier == null) | ||
return null; | ||
if (identifier.text == "AsyncIterable") { | ||
if (node.typeArguments == null || node.typeArguments.length === 0) { | ||
// TODO: Better error? | ||
return this.report(node, E.promiseMissingTypeArg()); | ||
} | ||
var t_1 = this.collectType(node.typeArguments[0]); | ||
if (t_1 == null) | ||
return null; | ||
return { type: t_1, isStream: true }; | ||
} | ||
} | ||
var inner = this.maybeUnwrapPromise(node); | ||
if (inner == null) | ||
return null; | ||
return this.collectType(inner); | ||
var t = this.collectType(inner); | ||
if (t == null) | ||
return null; | ||
return { type: t, isStream: false }; | ||
}; | ||
Extractor.prototype.collectPropertyType = function (node) { | ||
// TODO: Handle function types here. | ||
var inner = this.maybeUnwrapePromise(node); | ||
var inner = this.maybeUnwrapPromise(node); | ||
if (inner == null) | ||
@@ -1148,3 +1221,3 @@ return null; | ||
}; | ||
Extractor.prototype.maybeUnwrapePromise = function (node) { | ||
Extractor.prototype.maybeUnwrapPromise = function (node) { | ||
if (ts.isTypeReferenceNode(node)) { | ||
@@ -1155,3 +1228,3 @@ var identifier = this.expectIdentifier(node.typeName); | ||
if (identifier.text === "Promise") { | ||
if (node.typeArguments == null) { | ||
if (node.typeArguments == null || node.typeArguments.length === 0) { | ||
return this.report(node, E.promiseMissingTypeArg()); | ||
@@ -1172,3 +1245,3 @@ } | ||
if (description) { | ||
return this.gql.string(node, description, true); | ||
return this.gql.string(node, description.trim(), true); | ||
} | ||
@@ -1344,3 +1417,3 @@ return null; | ||
// It is a GraphQL best practice to model all fields as nullable. This allows | ||
// the server to handle field level exections by simply returning null for | ||
// the server to handle field level executions by simply returning null for | ||
// that field. | ||
@@ -1366,6 +1439,8 @@ // https://graphql.org/learn/best-practices/#nullability | ||
/* Grats directives */ | ||
Extractor.prototype.exportDirective = function (nameNode, filename, functionName) { | ||
Extractor.prototype.exportDirective = function (nameNode, jsModulePath, tsModulePath, functionName, argCount) { | ||
return this.gql.constDirective(nameNode, this.gql.name(nameNode, serverDirectives_1.EXPORTED_DIRECTIVE), [ | ||
this.gql.constArgument(nameNode, this.gql.name(nameNode, serverDirectives_1.EXPORTED_FILENAME_ARG), this.gql.string(nameNode, filename)), | ||
this.gql.constArgument(nameNode, this.gql.name(nameNode, serverDirectives_1.JS_MODULE_PATH_ARG), this.gql.string(nameNode, jsModulePath)), | ||
this.gql.constArgument(nameNode, this.gql.name(nameNode, serverDirectives_1.TS_MODULE_PATH_ARG), this.gql.string(nameNode, tsModulePath)), | ||
this.gql.constArgument(nameNode, this.gql.name(nameNode, serverDirectives_1.EXPORTED_FUNCTION_NAME_ARG), this.gql.string(nameNode, functionName)), | ||
this.gql.constArgument(nameNode, this.gql.name(nameNode, serverDirectives_1.ARG_COUNT), this.gql.int(nameNode, String(argCount))), | ||
]); | ||
@@ -1381,1 +1456,10 @@ }; | ||
exports.Extractor = Extractor; | ||
function graphQLNameValidationMessage(name) { | ||
try { | ||
(0, graphql_1.assertName)(name); | ||
return null; | ||
} | ||
catch (e) { | ||
return e.message; | ||
} | ||
} |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GraphQLConstructor = void 0; | ||
@@ -16,3 +16,3 @@ var graphql_1 = require("graphql"); | ||
name: name, | ||
types: types | ||
types: types, | ||
}; | ||
@@ -28,3 +28,3 @@ }; | ||
fields: fields, | ||
interfaces: interfaces !== null && interfaces !== void 0 ? interfaces : undefined | ||
interfaces: interfaces !== null && interfaces !== void 0 ? interfaces : undefined, | ||
}; | ||
@@ -40,3 +40,3 @@ }; | ||
fields: fields, | ||
interfaces: interfaces !== null && interfaces !== void 0 ? interfaces : undefined | ||
interfaces: interfaces !== null && interfaces !== void 0 ? interfaces : undefined, | ||
}; | ||
@@ -50,3 +50,3 @@ }; | ||
name: name, | ||
values: values | ||
values: values, | ||
}; | ||
@@ -60,3 +60,3 @@ }; | ||
onType: onType, | ||
field: field | ||
field: field, | ||
}; | ||
@@ -73,3 +73,3 @@ }; | ||
arguments: args !== null && args !== void 0 ? args : undefined, | ||
directives: this._optionalList(directives) | ||
directives: this._optionalList(directives), | ||
}; | ||
@@ -88,3 +88,3 @@ }; | ||
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : undefined, | ||
directives: this._optionalList(directives) | ||
directives: this._optionalList(directives), | ||
}; | ||
@@ -98,3 +98,3 @@ }; | ||
name: name, | ||
directives: directives | ||
directives: directives, | ||
}; | ||
@@ -108,3 +108,3 @@ }; | ||
name: name, | ||
directives: undefined | ||
directives: undefined, | ||
}; | ||
@@ -119,3 +119,3 @@ }; | ||
fields: fields !== null && fields !== void 0 ? fields : undefined, | ||
directives: this._optionalList(directives) | ||
directives: this._optionalList(directives), | ||
}; | ||
@@ -131,3 +131,3 @@ }; | ||
loc: this._loc(node), | ||
name: this.name(node, value) | ||
name: this.name(node, value), | ||
}; | ||
@@ -166,3 +166,3 @@ }; | ||
name: name, | ||
arguments: this._optionalList(args) | ||
arguments: this._optionalList(args), | ||
}; | ||
@@ -179,3 +179,3 @@ }; | ||
}; | ||
GraphQLConstructor.prototype["null"] = function (node) { | ||
GraphQLConstructor.prototype.null = function (node) { | ||
return { kind: graphql_1.Kind.NULL, loc: this._loc(node) }; | ||
@@ -182,0 +182,0 @@ }; |
import * as ts from "typescript"; | ||
export declare function getRelativeOutputPath(options: ts.ParsedCommandLine, sourceFile: ts.SourceFile): string; | ||
export declare function getRelativeOutputPath(options: ts.ParsedCommandLine, sourceFile: ts.SourceFile): { | ||
jsModulePath: string; | ||
tsModulePath: string; | ||
}; | ||
export declare function resolveRelativePath(relativePath: string): string; |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.resolveRelativePath = exports.getRelativeOutputPath = void 0; | ||
@@ -13,3 +13,3 @@ var path_1 = require("path"); | ||
// step and the runtime can agree on. This path is that thing. | ||
var gratsRoot = __dirname; | ||
var gratsRoot = (0, path_1.join)(__dirname, "../.."); | ||
function getRelativeOutputPath(options, sourceFile) { | ||
@@ -25,3 +25,5 @@ var fileNames = ts.getOutputFileNames(options, sourceFile.fileName, true); | ||
} | ||
return (0, path_1.relative)(gratsRoot, fileNames[0]); | ||
var jsModulePath = (0, path_1.relative)(gratsRoot, fileNames[0]); | ||
var tsModulePath = (0, path_1.relative)(gratsRoot, sourceFile.fileName); | ||
return { jsModulePath: jsModulePath, tsModulePath: tsModulePath }; | ||
} | ||
@@ -28,0 +30,0 @@ exports.getRelativeOutputPath = getRelativeOutputPath; |
@@ -1,10 +0,6 @@ | ||
import { GraphQLSchema } from "graphql"; | ||
import * as ts from "typescript"; | ||
import { ParsedCommandLineGrats } from "./lib"; | ||
import { ReportableDiagnostics, Result } from "./utils/DiagnosticError"; | ||
export * from "./Types"; | ||
export * from "./lib"; | ||
type RuntimeOptions = { | ||
emitSchemaFile?: string; | ||
}; | ||
export declare function extractGratsSchemaAtRuntime(runtimeOptions: RuntimeOptions): GraphQLSchema; | ||
export declare function buildSchemaFromSDL(sdl: string): GraphQLSchema; | ||
export declare function getParsedTsConfig(configPath?: string): ts.ParsedCommandLine; | ||
export { codegen } from "./codegen"; | ||
export declare function getParsedTsConfig(configFile: string): Result<ParsedCommandLineGrats, ReportableDiagnostics>; |
@@ -16,39 +16,13 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
exports.getParsedTsConfig = exports.buildSchemaFromSDL = exports.extractGratsSchemaAtRuntime = void 0; | ||
var graphql_1 = require("graphql"); | ||
var utils_1 = require("@graphql-tools/utils"); | ||
var fs = require("fs"); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getParsedTsConfig = exports.codegen = void 0; | ||
var ts = require("typescript"); | ||
var lib_1 = require("./lib"); | ||
var DiagnosticError_1 = require("./utils/DiagnosticError"); | ||
__exportStar(require("./Types"), exports); | ||
__exportStar(require("./lib"), exports); | ||
// Build an executable schema from a set of files. Note that if extraction | ||
// fails, this function will exit the process and print a helpful error | ||
// message. | ||
function extractGratsSchemaAtRuntime(runtimeOptions) { | ||
var parsedTsConfig = getParsedTsConfig(); | ||
var schemaResult = (0, lib_1.buildSchemaResult)(parsedTsConfig); | ||
if (schemaResult.kind === "ERROR") { | ||
console.error(schemaResult.err.formatDiagnosticsWithColorAndContext()); | ||
process.exit(1); | ||
} | ||
var runtimeSchema = schemaResult.value; | ||
if (runtimeOptions.emitSchemaFile) { | ||
runtimeSchema = (0, graphql_1.lexicographicSortSchema)(runtimeSchema); | ||
var sdl = (0, utils_1.printSchemaWithDirectives)(runtimeSchema, { assumeValid: true }); | ||
var filePath = runtimeOptions.emitSchemaFile; | ||
fs.writeFileSync(filePath, sdl); | ||
} | ||
return runtimeSchema; | ||
} | ||
exports.extractGratsSchemaAtRuntime = extractGratsSchemaAtRuntime; | ||
function buildSchemaFromSDL(sdl) { | ||
var schema = (0, graphql_1.buildSchema)(sdl); | ||
return (0, lib_1.applyServerDirectives)(schema); | ||
} | ||
exports.buildSchemaFromSDL = buildSchemaFromSDL; | ||
var codegen_1 = require("./codegen"); | ||
Object.defineProperty(exports, "codegen", { enumerable: true, get: function () { return codegen_1.codegen; } }); | ||
// #FIXME: Report diagnostics instead of throwing! | ||
function getParsedTsConfig(configPath) { | ||
var configFile = configPath || ts.findConfigFile(process.cwd(), ts.sys.fileExists); | ||
function getParsedTsConfig(configFile) { | ||
if (!configFile) { | ||
@@ -60,7 +34,10 @@ throw new Error("Grats: Could not find tsconfig.json"); | ||
var parsed = ts.getParsedCommandLineOfConfigFile(configFile, undefined, configFileHost); | ||
if (!parsed || parsed.errors.length > 0) { | ||
throw new Error("Grats: Could not parse tsconfig.json"); | ||
if (!parsed) { | ||
throw new Error("Grats: Could not locate tsconfig.json"); | ||
} | ||
return parsed; | ||
if (parsed.errors.length > 0) { | ||
return (0, DiagnosticError_1.err)(DiagnosticError_1.ReportableDiagnostics.fromDiagnostics(parsed.errors)); | ||
} | ||
return (0, DiagnosticError_1.ok)((0, lib_1.validateGratsOptions)(parsed)); | ||
} | ||
exports.getParsedTsConfig = getParsedTsConfig; |
@@ -13,3 +13,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.computeInterfaceMap = void 0; | ||
@@ -47,3 +47,3 @@ var DiagnosticError_1 = require("./utils/DiagnosticError"); | ||
kind: "INTERFACE", | ||
name: doc.name.value | ||
name: doc.name.value, | ||
}); | ||
@@ -55,3 +55,3 @@ } | ||
try { | ||
if (_g && !_g.done && (_b = _f["return"])) _b.call(_f); | ||
if (_g && !_g.done && (_b = _f.return)) _b.call(_f); | ||
} | ||
@@ -77,3 +77,3 @@ finally { if (e_2) throw e_2.error; } | ||
try { | ||
if (_j && !_j.done && (_c = _h["return"])) _c.call(_h); | ||
if (_j && !_j.done && (_c = _h.return)) _c.call(_h); | ||
} | ||
@@ -89,3 +89,3 @@ finally { if (e_3) throw e_3.error; } | ||
try { | ||
if (docs_1_1 && !docs_1_1.done && (_a = docs_1["return"])) _a.call(docs_1); | ||
if (docs_1_1 && !docs_1_1.done && (_a = docs_1.return)) _a.call(docs_1); | ||
} | ||
@@ -92,0 +92,0 @@ finally { if (e_1) throw e_1.error; } |
import { GraphQLSchema } from "graphql"; | ||
import { Result, ReportableDiagnostics } from "./utils/DiagnosticError"; | ||
import * as ts from "typescript"; | ||
export { applyServerDirectives } from "./serverDirectives"; | ||
export type ConfigOptions = { | ||
nullableByDefault?: boolean; | ||
reportTypeScriptTypeErrors?: boolean; | ||
}; | ||
export declare function buildSchemaResult(options: ts.ParsedCommandLine): Result<GraphQLSchema, ReportableDiagnostics>; | ||
export declare function buildSchemaResultWithHost(options: ts.ParsedCommandLine, compilerHost: ts.CompilerHost): Result<GraphQLSchema, ReportableDiagnostics>; | ||
import { ParsedCommandLineGrats } from "./gratsConfig"; | ||
export * from "./gratsConfig"; | ||
export declare function buildSchemaResult(options: ParsedCommandLineGrats): Result<GraphQLSchema, ReportableDiagnostics>; | ||
export declare function buildSchemaResultWithHost(options: ParsedCommandLineGrats, compilerHost: ts.CompilerHost): Result<GraphQLSchema, ReportableDiagnostics>; |
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
@@ -24,2 +13,5 @@ if (k2 === undefined) k2 = k; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
@@ -36,4 +28,4 @@ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
}; | ||
exports.__esModule = true; | ||
exports.buildSchemaResultWithHost = exports.buildSchemaResult = exports.applyServerDirectives = void 0; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.buildSchemaResultWithHost = exports.buildSchemaResult = void 0; | ||
var graphql_1 = require("graphql"); | ||
@@ -46,4 +38,4 @@ var DiagnosticError_1 = require("./utils/DiagnosticError"); | ||
var serverDirectives_1 = require("./serverDirectives"); | ||
var serverDirectives_2 = require("./serverDirectives"); | ||
__createBinding(exports, serverDirectives_2, "applyServerDirectives"); | ||
var helpers_1 = require("./utils/helpers"); | ||
__exportStar(require("./gratsConfig"), exports); | ||
// Construct a schema, using GraphQL schema language | ||
@@ -60,30 +52,10 @@ // Exported for tests that want to intercept diagnostic errors. | ||
function buildSchemaResultWithHost(options, compilerHost) { | ||
var gratsOptions = parseGratsOptions(options); | ||
var schemaResult = extractSchema(options, gratsOptions, compilerHost); | ||
var schemaResult = extractSchema(options, compilerHost); | ||
if (schemaResult.kind === "ERROR") { | ||
return (0, DiagnosticError_1.err)(new DiagnosticError_1.ReportableDiagnostics(compilerHost, schemaResult.err)); | ||
} | ||
return (0, DiagnosticError_1.ok)((0, serverDirectives_1.applyServerDirectives)(schemaResult.value)); | ||
return (0, DiagnosticError_1.ok)(schemaResult.value); | ||
} | ||
exports.buildSchemaResultWithHost = buildSchemaResultWithHost; | ||
// TODO: Make this return diagnostics | ||
function parseGratsOptions(options) { | ||
var _a, _b; | ||
var gratsOptions = __assign({}, ((_b = (_a = options.raw) === null || _a === void 0 ? void 0 : _a.grats) !== null && _b !== void 0 ? _b : {})); | ||
if (gratsOptions.nullableByDefault === undefined) { | ||
gratsOptions.nullableByDefault = true; | ||
} | ||
else if (typeof gratsOptions.nullableByDefault !== "boolean") { | ||
throw new Error("Grats: The Grats config option `nullableByDefault` must be a boolean if provided."); | ||
} | ||
if (gratsOptions.reportTypeScriptTypeErrors === undefined) { | ||
gratsOptions.reportTypeScriptTypeErrors = false; | ||
} | ||
else if (typeof gratsOptions.reportTypeScriptTypeErrors !== "boolean") { | ||
throw new Error("Grats: The Grats config option `reportTypeScriptTypeErrors` must be a boolean if provided"); | ||
} | ||
// FIXME: Check for unknown options | ||
return gratsOptions; | ||
} | ||
function extractSchema(options, gratsOptions, host) { | ||
function extractSchema(options, host) { | ||
var e_1, _a, e_2, _b; | ||
@@ -94,2 +66,3 @@ var program = ts.createProgram(options.fileNames, options.options, host); | ||
var definitions = Array.from(serverDirectives_1.DIRECTIVES_AST.definitions); | ||
var errors = []; | ||
try { | ||
@@ -102,7 +75,8 @@ for (var _c = __values(program.getSourceFiles()), _d = _c.next(); !_d.done; _d = _c.next()) { | ||
} | ||
if (gratsOptions.reportTypeScriptTypeErrors) { | ||
if (options.raw.grats.reportTypeScriptTypeErrors) { | ||
// If the user asked for us to report TypeScript errors, then we'll report them. | ||
var typeErrors = ts.getPreEmitDiagnostics(program, sourceFile); | ||
if (typeErrors.length > 0) { | ||
return (0, DiagnosticError_1.err)(typeErrors); | ||
(0, helpers_1.extend)(errors, typeErrors); | ||
continue; | ||
} | ||
@@ -117,9 +91,12 @@ } | ||
// the first one. | ||
return (0, DiagnosticError_1.err)([syntaxErrors[0]]); | ||
errors.push(syntaxErrors[0]); | ||
continue; | ||
} | ||
} | ||
var extractor = new Extractor_1.Extractor(sourceFile, ctx, gratsOptions); | ||
var extractor = new Extractor_1.Extractor(sourceFile, ctx, options.raw.grats); | ||
var extractedResult = extractor.extract(); | ||
if (extractedResult.kind === "ERROR") | ||
return extractedResult; | ||
if (extractedResult.kind === "ERROR") { | ||
(0, helpers_1.extend)(errors, extractedResult.err); | ||
continue; | ||
} | ||
try { | ||
@@ -134,3 +111,3 @@ for (var _e = (e_2 = void 0, __values(extractedResult.value)), _f = _e.next(); !_f.done; _f = _e.next()) { | ||
try { | ||
if (_f && !_f.done && (_b = _e["return"])) _b.call(_e); | ||
if (_f && !_f.done && (_b = _e.return)) _b.call(_e); | ||
} | ||
@@ -144,6 +121,9 @@ finally { if (e_2) throw e_2.error; } | ||
try { | ||
if (_d && !_d.done && (_a = _c["return"])) _a.call(_c); | ||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
if (errors.length > 0) { | ||
return (0, DiagnosticError_1.err)(errors); | ||
} | ||
// If you define a field on an interface using the functional style, we need to add | ||
@@ -158,3 +138,3 @@ // that field to each concrete type as well. This must be done after all types are created, | ||
kind: graphql_1.Kind.DOCUMENT, | ||
definitions: definitionsResult.value | ||
definitions: definitionsResult.value, | ||
}); | ||
@@ -164,2 +144,6 @@ if (docResult.kind === "ERROR") | ||
var doc = docResult.value; | ||
var subscriptionsValidationResult = ctx.validateAsyncIterableFields(doc); | ||
if (subscriptionsValidationResult.kind === "ERROR") { | ||
return subscriptionsValidationResult; | ||
} | ||
// TODO: Currently this does not detect definitions that shadow builtins | ||
@@ -213,3 +197,3 @@ // (`String`, `Int`, etc). However, if we pass a second param (extending an | ||
try { | ||
if (typeImplementors_1_1 && !typeImplementors_1_1.done && (_b = typeImplementors_1["return"])) _b.call(typeImplementors_1); | ||
if (typeImplementors_1_1 && !typeImplementors_1_1.done && (_b = typeImplementors_1.return)) _b.call(typeImplementors_1); | ||
} | ||
@@ -223,3 +207,3 @@ finally { if (e_4) throw e_4.error; } | ||
try { | ||
if (abstractTypes_1_1 && !abstractTypes_1_1.done && (_a = abstractTypes_1["return"])) _a.call(abstractTypes_1); | ||
if (abstractTypes_1_1 && !abstractTypes_1_1.done && (_a = abstractTypes_1.return)) _a.call(abstractTypes_1); | ||
} | ||
@@ -226,0 +210,0 @@ finally { if (e_3) throw e_3.error; } |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.locate = void 0; | ||
@@ -4,0 +4,0 @@ var graphql_1 = require("graphql"); |
@@ -1,8 +0,10 @@ | ||
import { DocumentNode, GraphQLSchema } from "graphql"; | ||
import { DocumentNode } from "graphql"; | ||
export declare const METHOD_NAME_DIRECTIVE = "methodName"; | ||
export declare const METHOD_NAME_ARG = "name"; | ||
export declare const EXPORTED_DIRECTIVE = "exported"; | ||
export declare const EXPORTED_FILENAME_ARG = "filename"; | ||
export declare const JS_MODULE_PATH_ARG = "jsModulePath"; | ||
export declare const TS_MODULE_PATH_ARG = "tsModulePath"; | ||
export declare const ARG_COUNT = "argCount"; | ||
export declare const EXPORTED_FUNCTION_NAME_ARG = "functionName"; | ||
export declare const ASYNC_ITERABLE_TYPE_DIRECTIVE = "asyncIterable"; | ||
export declare const DIRECTIVES_AST: DocumentNode; | ||
export declare function applyServerDirectives(schema: GraphQLSchema): GraphQLSchema; |
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (g && (g = 0, op[0] && (_ = 0)), _) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
exports.__esModule = true; | ||
exports.applyServerDirectives = exports.DIRECTIVES_AST = exports.EXPORTED_FUNCTION_NAME_ARG = exports.EXPORTED_FILENAME_ARG = exports.EXPORTED_DIRECTIVE = exports.METHOD_NAME_ARG = exports.METHOD_NAME_DIRECTIVE = void 0; | ||
var utils_1 = require("@graphql-tools/utils"); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.DIRECTIVES_AST = exports.ASYNC_ITERABLE_TYPE_DIRECTIVE = exports.EXPORTED_FUNCTION_NAME_ARG = exports.ARG_COUNT = exports.TS_MODULE_PATH_ARG = exports.JS_MODULE_PATH_ARG = exports.EXPORTED_DIRECTIVE = exports.METHOD_NAME_ARG = exports.METHOD_NAME_DIRECTIVE = void 0; | ||
var graphql_1 = require("graphql"); | ||
var gratsRoot_1 = require("./gratsRoot"); | ||
// TODO: Rename to be generic since it can apply to properties as well as methods. | ||
@@ -58,82 +9,7 @@ exports.METHOD_NAME_DIRECTIVE = "methodName"; | ||
exports.EXPORTED_DIRECTIVE = "exported"; | ||
exports.EXPORTED_FILENAME_ARG = "filename"; | ||
exports.JS_MODULE_PATH_ARG = "jsModulePath"; | ||
exports.TS_MODULE_PATH_ARG = "tsModulePath"; | ||
exports.ARG_COUNT = "argCount"; | ||
exports.EXPORTED_FUNCTION_NAME_ARG = "functionName"; | ||
exports.DIRECTIVES_AST = (0, graphql_1.parse)("\n directive @".concat(exports.METHOD_NAME_DIRECTIVE, "(").concat(exports.METHOD_NAME_ARG, ": String!) on FIELD_DEFINITION\n directive @").concat(exports.EXPORTED_DIRECTIVE, "(\n ").concat(exports.EXPORTED_FILENAME_ARG, ": String!,\n ").concat(exports.EXPORTED_FUNCTION_NAME_ARG, ": String!\n ) on FIELD_DEFINITION\n")); | ||
function applyServerDirectives(schema) { | ||
var _a; | ||
// TODO: Do we really need all of mapSchema here or can we create our own | ||
// thing that's simpler. | ||
return (0, utils_1.mapSchema)(schema, (_a = {}, | ||
_a[utils_1.MapperKind.OBJECT_FIELD] = function (fieldConfig) { | ||
var _a, _b; | ||
var newFieldConfig = fieldConfig; | ||
var methodNameDirective = (_a = (0, utils_1.getDirective)(schema, fieldConfig, exports.METHOD_NAME_DIRECTIVE)) === null || _a === void 0 ? void 0 : _a[0]; | ||
if (methodNameDirective != null) { | ||
newFieldConfig = applyMethodNameDirective(newFieldConfig, methodNameDirective); | ||
} | ||
var exportedDirective = (_b = (0, utils_1.getDirective)(schema, fieldConfig, exports.EXPORTED_DIRECTIVE)) === null || _b === void 0 ? void 0 : _b[0]; | ||
if (exportedDirective != null) { | ||
newFieldConfig = applyExportDirective(newFieldConfig, exportedDirective); | ||
} | ||
return newFieldConfig; | ||
}, | ||
_a)); | ||
} | ||
exports.applyServerDirectives = applyServerDirectives; | ||
/** | ||
* Field renaming directive: | ||
* | ||
* By default, when resolving a field, the server will take the schema field | ||
* name, and look for a resolver/property by that name on the parent object. | ||
* Since we support exposing a method/property under a different name, we need | ||
* to modify that field's resolver to look for the implementation name rather | ||
* than the schema name. | ||
*/ | ||
function applyMethodNameDirective(fieldConfig, methodNameDirective) { | ||
var _a = fieldConfig.resolve, resolve = _a === void 0 ? graphql_1.defaultFieldResolver : _a; | ||
return __assign(__assign({}, fieldConfig), { resolve: function (source, args, context, info) { | ||
var newInfo = __assign(__assign({}, info), { fieldName: methodNameDirective[exports.METHOD_NAME_ARG] }); | ||
return resolve(source, args, context, newInfo); | ||
} }); | ||
} | ||
/** | ||
* Export directive: | ||
* | ||
* By default, when resolving a field, the server will look for a resolver | ||
* function on the parent object. This directive allows you to specify a | ||
* module and function name to import and use as the resolver. | ||
*/ | ||
function applyExportDirective(fieldConfig, methodNameDirective) { | ||
// TODO: Does this work in the browser? | ||
var filename = (0, gratsRoot_1.resolveRelativePath)(methodNameDirective[exports.EXPORTED_FILENAME_ARG]); | ||
var functionName = methodNameDirective[exports.EXPORTED_FUNCTION_NAME_ARG]; | ||
return __assign(__assign({}, fieldConfig), { resolve: function (source, args, context, info) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var mod, e_1, resolve; | ||
return __generator(this, function (_a) { | ||
var _b; | ||
switch (_a.label) { | ||
case 0: | ||
mod = {}; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, (_b = filename, Promise.resolve().then(function () { return require(_b); }))]; | ||
case 2: | ||
mod = _a.sent(); | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
e_1 = _a.sent(); | ||
console.error("Grats Error: Failed to import module `".concat(filename, "`. You may need to rerun Grats.")); | ||
throw e_1; | ||
case 4: | ||
resolve = mod[functionName]; | ||
if (typeof resolve !== "function") { | ||
throw new Error("Grats Error: Expected `".concat(filename, "` to have a named export `").concat(functionName, "` that is a function, but it was `").concat(typeof resolve, "`. You may need to rerun Grats.")); | ||
} | ||
return [2 /*return*/, resolve(source, args, context, info)]; | ||
} | ||
}); | ||
}); | ||
} }); | ||
} | ||
exports.ASYNC_ITERABLE_TYPE_DIRECTIVE = "asyncIterable"; | ||
exports.DIRECTIVES_AST = (0, graphql_1.parse)("\n directive @".concat(exports.ASYNC_ITERABLE_TYPE_DIRECTIVE, " on FIELD_DEFINITION\n directive @").concat(exports.METHOD_NAME_DIRECTIVE, "(").concat(exports.METHOD_NAME_ARG, ": String!) on FIELD_DEFINITION\n directive @").concat(exports.EXPORTED_DIRECTIVE, "(\n ").concat(exports.JS_MODULE_PATH_ARG, ": String!,\n ").concat(exports.TS_MODULE_PATH_ARG, ": String!,\n ").concat(exports.EXPORTED_FUNCTION_NAME_ARG, ": String!\n ").concat(exports.ARG_COUNT, ": Int!\n ) on FIELD_DEFINITION\n")); |
@@ -60,7 +60,6 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var path = require("path"); | ||
var TestRunner_1 = require("./TestRunner"); | ||
var lib_1 = require("../lib"); | ||
var utils_1 = require("@graphql-tools/utils"); | ||
var ts = require("typescript"); | ||
@@ -71,2 +70,7 @@ var graphql_1 = require("graphql"); | ||
var DiagnosticError_1 = require("../utils/DiagnosticError"); | ||
var fs_1 = require("fs"); | ||
var codegen_1 = require("../codegen"); | ||
var utils_1 = require("@graphql-tools/utils"); | ||
var jest_diff_1 = require("jest-diff"); | ||
var printSchema_1 = require("../printSchema"); | ||
var program = new commander_1.Command(); | ||
@@ -81,3 +85,3 @@ program | ||
return __awaiter(void 0, void 0, void 0, function () { | ||
var filterRegex, failures, testDirs_1, testDirs_1_1, _b, fixturesDir_1, transformer, runner, e_1_1; | ||
var filterRegex, failures, testDirs_1, testDirs_1_1, _b, fixturesDir_1, transformer, testFilePattern, ignoreFilePattern, runner, e_1_1; | ||
var e_1, _c; | ||
@@ -96,4 +100,4 @@ return __generator(this, function (_d) { | ||
if (!!testDirs_1_1.done) return [3 /*break*/, 5]; | ||
_b = testDirs_1_1.value, fixturesDir_1 = _b.fixturesDir, transformer = _b.transformer; | ||
runner = new TestRunner_1["default"](fixturesDir_1, !!write, filterRegex, transformer); | ||
_b = testDirs_1_1.value, fixturesDir_1 = _b.fixturesDir, transformer = _b.transformer, testFilePattern = _b.testFilePattern, ignoreFilePattern = _b.ignoreFilePattern; | ||
runner = new TestRunner_1.default(fixturesDir_1, !!write, filterRegex, testFilePattern, ignoreFilePattern, transformer); | ||
return [4 /*yield*/, runner.run()]; | ||
@@ -113,3 +117,3 @@ case 3: | ||
try { | ||
if (testDirs_1_1 && !testDirs_1_1.done && (_c = testDirs_1["return"])) _c.call(testDirs_1); | ||
if (testDirs_1_1 && !testDirs_1_1.done && (_c = testDirs_1.return)) _c.call(testDirs_1); | ||
} | ||
@@ -127,11 +131,16 @@ finally { if (e_1) throw e_1.error; } | ||
}); | ||
var gratsDir = path.join(__dirname, "../.."); | ||
var fixturesDir = path.join(__dirname, "fixtures"); | ||
var integrationFixturesDir = path.join(__dirname, "integrationFixtures"); | ||
var codegenFixturesDir = path.join(__dirname, "codegenFixtures"); | ||
var testDirs = [ | ||
{ | ||
fixturesDir: fixturesDir, | ||
testFilePattern: /\.ts$/, | ||
ignoreFilePattern: null, | ||
transformer: function (code, fileName) { | ||
var firstLine = code.split("\n")[0]; | ||
var options = { | ||
nullableByDefault: true | ||
nullableByDefault: true, | ||
schemaHeader: null, | ||
}; | ||
@@ -144,10 +153,10 @@ if (firstLine.startsWith("// {")) { | ||
var files = ["".concat(fixturesDir, "/").concat(fileName), "src/Types.ts"]; | ||
var parsedOptions = { | ||
var parsedOptions = (0, lib_1.validateGratsOptions)({ | ||
options: {}, | ||
raw: { | ||
grats: options | ||
grats: options, | ||
}, | ||
errors: [], | ||
fileNames: files | ||
}; | ||
fileNames: files, | ||
}); | ||
// https://stackoverflow.com/a/66604532/1263117 | ||
@@ -161,2 +170,4 @@ var compilerHost = ts.createCompilerHost(parsedOptions.options, | ||
} | ||
// We run codegen here just ensure that it doesn't throw. | ||
(0, codegen_1.codegen)(schemaResult.value, "".concat(fixturesDir, "/").concat(fileName)); | ||
var LOCATION_REGEX = /^\/\/ Locate: (.*)/; | ||
@@ -175,37 +186,35 @@ var locationMatch = code.match(LOCATION_REGEX); | ||
return (0, utils_1.printSchemaWithDirectives)(schemaResult.value, { | ||
assumeValid: true | ||
assumeValid: true, | ||
}); | ||
} | ||
} | ||
}, | ||
}, | ||
{ | ||
fixturesDir: integrationFixturesDir, | ||
testFilePattern: /index.ts$/, | ||
ignoreFilePattern: /schema.ts$/, | ||
transformer: function (code, fileName) { return __awaiter(void 0, void 0, void 0, function () { | ||
var filePath, server, options, files, parsedOptions, schemaResult, schema, data; | ||
var filePath, schemaPath, options, files, parsedOptions, schemaResult, tsSchema, server, schemaModule, schemaDiff, data; | ||
return __generator(this, function (_a) { | ||
var _b; | ||
switch (_a.label) { | ||
case 0: | ||
filePath = "".concat(integrationFixturesDir, "/").concat(fileName); | ||
return [4 /*yield*/, (_b = filePath, Promise.resolve().then(function () { return require(_b); }))]; | ||
case 1: | ||
server = _a.sent(); | ||
if (server.query == null || typeof server.query !== "string") { | ||
throw new Error("Expected `".concat(filePath, "` to export a query text as `query`")); | ||
} | ||
if (server.Query == null || typeof server.Query !== "function") { | ||
throw new Error("Expected `".concat(filePath, "` to export a Query type as `Query`")); | ||
} | ||
schemaPath = path.join(path.dirname(filePath), "schema.ts"); | ||
options = { | ||
nullableByDefault: true | ||
nullableByDefault: true, | ||
}; | ||
files = [filePath, "src/Types.ts"]; | ||
parsedOptions = { | ||
options: {}, | ||
parsedOptions = (0, lib_1.validateGratsOptions)({ | ||
options: { | ||
// Required to enable ts-node to locate function exports | ||
rootDir: gratsDir, | ||
outDir: "dist", | ||
configFilePath: "tsconfig.json", | ||
}, | ||
raw: { | ||
grats: options | ||
grats: options, | ||
}, | ||
errors: [], | ||
fileNames: files | ||
}; | ||
fileNames: files, | ||
}); | ||
schemaResult = (0, lib_1.buildSchemaResult)(parsedOptions); | ||
@@ -215,9 +224,25 @@ if (schemaResult.kind === "ERROR") { | ||
} | ||
schema = schemaResult.value; | ||
tsSchema = (0, codegen_1.codegen)(schemaResult.value, schemaPath); | ||
(0, fs_1.writeFileSync)(schemaPath, tsSchema); | ||
return [4 /*yield*/, Promise.resolve("".concat(filePath)).then(function (s) { return require(s); })]; | ||
case 1: | ||
server = _a.sent(); | ||
if (server.query == null || typeof server.query !== "string") { | ||
throw new Error("Expected `".concat(filePath, "` to export a query text as `query`")); | ||
} | ||
return [4 /*yield*/, Promise.resolve("".concat(schemaPath)).then(function (s) { return require(s); })]; | ||
case 2: | ||
schemaModule = _a.sent(); | ||
schemaDiff = compareSchemas(schemaModule.schema, schemaResult.value); | ||
if (schemaDiff) { | ||
console.log(schemaDiff); | ||
// TODO: Make this an actual test failure, not an error | ||
throw new Error("The codegen schema does not match the SDL schema."); | ||
} | ||
return [4 /*yield*/, (0, graphql_1.graphql)({ | ||
schema: schema, | ||
schema: schemaModule.schema, | ||
source: server.query, | ||
rootValue: new server.Query() | ||
variableValues: server.variables, | ||
})]; | ||
case 2: | ||
case 3: | ||
data = _a.sent(); | ||
@@ -227,5 +252,28 @@ return [2 /*return*/, JSON.stringify(data, null, 2)]; | ||
}); | ||
}); } | ||
}); }, | ||
}, | ||
{ | ||
fixturesDir: codegenFixturesDir, | ||
testFilePattern: /\.graphql$/, | ||
ignoreFilePattern: null, | ||
transformer: function (code, fileName) { return __awaiter(void 0, void 0, void 0, function () { | ||
var filePath, sdl, schema; | ||
return __generator(this, function (_a) { | ||
filePath = "".concat(codegenFixturesDir, "/").concat(fileName); | ||
sdl = (0, fs_1.readFileSync)(filePath, "utf8"); | ||
schema = (0, graphql_1.buildSchema)(sdl); | ||
return [2 /*return*/, (0, codegen_1.codegen)(schema, filePath)]; | ||
}); | ||
}); }, | ||
}, | ||
]; | ||
// Returns null if the schemas are equal, otherwise returns a string diff. | ||
function compareSchemas(actual, expected) { | ||
var actualSDL = (0, printSchema_1.printSDLWithoutDirectives)(actual); | ||
var expectedSDL = (0, printSchema_1.printSDLWithoutDirectives)(expected); | ||
if (actualSDL === expectedSDL) { | ||
return null; | ||
} | ||
return (0, jest_diff_1.diff)(expectedSDL, actualSDL); | ||
} | ||
program.parse(); |
@@ -15,3 +15,3 @@ type Transformer = (code: string, filename: string) => Promise<string> | string; | ||
_transformer: Transformer; | ||
constructor(fixturesDir: string, write: boolean, filter: string | null, transformer: Transformer); | ||
constructor(fixturesDir: string, write: boolean, filter: string | null, testFilePattern: RegExp, ignoreFilePattern: RegExp | null, transformer: Transformer); | ||
run(): Promise<boolean>; | ||
@@ -18,0 +18,0 @@ _testFixture(fixture: string): Promise<void>; |
@@ -49,3 +49,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var fs = require("fs"); | ||
@@ -60,3 +60,3 @@ var path = require("path"); | ||
var TestRunner = /** @class */ (function () { | ||
function TestRunner(fixturesDir, write, filter, transformer) { | ||
function TestRunner(fixturesDir, write, filter, testFilePattern, ignoreFilePattern, transformer) { | ||
var e_1, _a; | ||
@@ -74,3 +74,3 @@ this._testFixtures = []; | ||
var fileName = _c.value; | ||
if (fileName.endsWith(".ts")) { | ||
if (testFilePattern.test(fileName)) { | ||
this._testFixtures.push(fileName); | ||
@@ -82,3 +82,3 @@ var filePath = path.join(fixturesDir, fileName); | ||
} | ||
else { | ||
else if (!ignoreFilePattern || !ignoreFilePattern.test(fileName)) { | ||
this._otherFiles.add(fileName); | ||
@@ -91,3 +91,3 @@ } | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -125,3 +125,3 @@ finally { if (e_1) throw e_1.error; } | ||
try { | ||
if (_b && !_b.done && (_g = _a["return"])) _g.call(_a); | ||
if (_b && !_b.done && (_g = _a.return)) _g.call(_a); | ||
} | ||
@@ -151,3 +151,3 @@ finally { if (e_2) throw e_2.error; } | ||
try { | ||
if (_d && !_d.done && (_h = _c["return"])) _h.call(_c); | ||
if (_d && !_d.done && (_h = _c.return)) _h.call(_c); | ||
} | ||
@@ -168,3 +168,3 @@ finally { if (e_3) throw e_3.error; } | ||
try { | ||
if (_f && !_f.done && (_j = _e["return"])) _j.call(_e); | ||
if (_f && !_f.done && (_j = _e.return)) _j.call(_e); | ||
} | ||
@@ -191,3 +191,3 @@ finally { if (e_4) throw e_4.error; } | ||
if (this._otherFiles.has(expectedFileName)) { | ||
this._otherFiles["delete"](expectedFileName); | ||
this._otherFiles.delete(expectedFileName); | ||
} | ||
@@ -247,3 +247,3 @@ else { | ||
}()); | ||
exports["default"] = TestRunner; | ||
exports.default = TestRunner; | ||
function readdirSyncRecursive(dir) { | ||
@@ -266,3 +266,3 @@ var e_6, _a, e_7, _b; | ||
try { | ||
if (_f && !_f.done && (_b = _e["return"])) _b.call(_e); | ||
if (_f && !_f.done && (_b = _e.return)) _b.call(_e); | ||
} | ||
@@ -280,3 +280,3 @@ finally { if (e_7) throw e_7.error; } | ||
try { | ||
if (_d && !_d.done && (_a = _c["return"])) _a.call(_c); | ||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c); | ||
} | ||
@@ -283,0 +283,0 @@ finally { if (e_6) throw e_6.error; } |
@@ -1,2 +0,2 @@ | ||
import { DefinitionNode, DocumentNode, FieldDefinitionNode, Location, NameNode } from "graphql"; | ||
import { DefinitionNode, DocumentNode, FieldDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, Location, NameNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode } from "graphql"; | ||
import * as ts from "typescript"; | ||
@@ -52,2 +52,4 @@ import { DiagnosticResult, DiagnosticsResult } from "./utils/DiagnosticError"; | ||
resolveTypes(doc: DocumentNode): DiagnosticsResult<DocumentNode>; | ||
validateAsyncIterableFields(doc: DocumentNode): DiagnosticsResult<void>; | ||
validateField(t: ObjectTypeDefinitionNode | ObjectTypeExtensionNode | InterfaceTypeDefinitionNode | InterfaceTypeExtensionNode): ts.Diagnostic | void; | ||
handleAbstractDefinitions(docs: GratsDefinitionNode[]): DiagnosticsResult<DefinitionNode[]>; | ||
@@ -58,5 +60,7 @@ addAbstractFieldDefinition(doc: AbstractFieldDefinitionNode, interfaceGraph: InterfaceMap): DiagnosticsResult<DefinitionNode[]>; | ||
relatedInformation(loc: Location, message: string): ts.DiagnosticRelatedInformation; | ||
validateInterfaceImplementorsHaveTypenameField(): DiagnosticResult<null>; | ||
getDestFilePath(sourceFile: ts.SourceFile): string; | ||
getDestFilePath(sourceFile: ts.SourceFile): { | ||
jsModulePath: string; | ||
tsModulePath: string; | ||
}; | ||
} | ||
export {}; |
@@ -24,3 +24,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TypeContext = exports.UNRESOLVED_REFERENCE_NAME = void 0; | ||
@@ -123,4 +123,65 @@ var graphql_1 = require("graphql"); | ||
}; | ||
// Ensure that all fields on `Subscription` return an AsyncIterable, and that no other | ||
// fields do. | ||
TypeContext.prototype.validateAsyncIterableFields = function (doc) { | ||
var _a; | ||
var _this = this; | ||
var errors = []; | ||
var visitNode = function (t) { | ||
var validateFieldsResult = _this.validateField(t); | ||
if (validateFieldsResult != null) { | ||
errors.push(validateFieldsResult); | ||
} | ||
}; | ||
(0, graphql_1.visit)(doc, (_a = {}, | ||
_a[graphql_1.Kind.INTERFACE_TYPE_DEFINITION] = visitNode, | ||
_a[graphql_1.Kind.INTERFACE_TYPE_EXTENSION] = visitNode, | ||
_a[graphql_1.Kind.OBJECT_TYPE_DEFINITION] = visitNode, | ||
_a[graphql_1.Kind.OBJECT_TYPE_EXTENSION] = visitNode, | ||
_a)); | ||
if (errors.length > 0) { | ||
return (0, DiagnosticError_1.err)(errors); | ||
} | ||
return (0, DiagnosticError_1.ok)(undefined); | ||
}; | ||
TypeContext.prototype.validateField = function (t) { | ||
var e_1, _a; | ||
var _b; | ||
if (t.fields == null) | ||
return; | ||
// Note: We assume the default name is used here. When custom operation types are supported | ||
// we'll need to update this. | ||
var isSubscription = t.name.value === "Subscription" && | ||
(t.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION || | ||
t.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION); | ||
try { | ||
for (var _c = __values(t.fields), _d = _c.next(); !_d.done; _d = _c.next()) { | ||
var field = _d.value; | ||
var asyncDirective = (_b = field.directives) === null || _b === void 0 ? void 0 : _b.find(function (directive) { return directive.name.value === serverDirectives_1.ASYNC_ITERABLE_TYPE_DIRECTIVE; }); | ||
if (isSubscription && asyncDirective == null) { | ||
if (field.type.loc == null) { | ||
throw new Error("Expected field type to have a location."); | ||
} | ||
return this.err(field.type.loc, E.subscriptionFieldNotAsyncIterable()); | ||
} | ||
if (!isSubscription && asyncDirective != null) { | ||
if (asyncDirective.loc == null) { | ||
throw new Error("Expected asyncDirective to have a location."); | ||
} | ||
return this.err(asyncDirective.loc, // Directive location is the AsyncIterable type. | ||
E.nonSubscriptionFieldAsyncIterable()); | ||
} | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}; | ||
// TODO: Is this still used? | ||
TypeContext.prototype.handleAbstractDefinitions = function (docs) { | ||
var e_1, _a; | ||
var e_2, _a; | ||
var newDocs = []; | ||
@@ -150,8 +211,8 @@ var errors = []; | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (docs_1_1 && !docs_1_1.done && (_a = docs_1["return"])) _a.call(docs_1); | ||
if (docs_1_1 && !docs_1_1.done && (_a = docs_1.return)) _a.call(docs_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
@@ -166,3 +227,3 @@ if (errors.length > 0) { | ||
TypeContext.prototype.addAbstractFieldDefinition = function (doc, interfaceGraph) { | ||
var e_2, _a; | ||
var e_3, _a; | ||
var _b; | ||
@@ -191,3 +252,3 @@ var newDocs = []; | ||
fields: [doc.field], | ||
loc: doc.loc | ||
loc: doc.loc, | ||
}); | ||
@@ -206,3 +267,3 @@ break; | ||
name: doc.onType, | ||
fields: [__assign(__assign({}, doc.field), { directives: directives })] | ||
fields: [__assign(__assign({}, doc.field), { directives: directives })], | ||
}); | ||
@@ -215,3 +276,3 @@ try { | ||
value: implementor.name, | ||
loc: doc.loc | ||
loc: doc.loc, // Bit of a lie, but I don't see a better option. | ||
}; | ||
@@ -224,3 +285,3 @@ switch (implementor.kind) { | ||
fields: [doc.field], | ||
loc: doc.loc | ||
loc: doc.loc, | ||
}); | ||
@@ -233,3 +294,3 @@ break; | ||
fields: [__assign(__assign({}, doc.field), { directives: directives })], | ||
loc: doc.loc | ||
loc: doc.loc, | ||
}); | ||
@@ -240,8 +301,8 @@ break; | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
catch (e_3_1) { e_3 = { error: e_3_1 }; } | ||
finally { | ||
try { | ||
if (_d && !_d.done && (_a = _c["return"])) _a.call(_c); | ||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
finally { if (e_3) throw e_3.error; } | ||
} | ||
@@ -295,3 +356,3 @@ break; | ||
file: ts.createSourceFile(loc.source.name, loc.source.body, ts.ScriptTarget.Latest), | ||
relatedInformation: relatedInformation | ||
relatedInformation: relatedInformation, | ||
}; | ||
@@ -306,8 +367,5 @@ }; | ||
start: loc.start, | ||
length: loc.end - loc.start | ||
length: loc.end - loc.start, | ||
}; | ||
}; | ||
TypeContext.prototype.validateInterfaceImplementorsHaveTypenameField = function () { | ||
return (0, DiagnosticError_1.ok)(null); | ||
}; | ||
TypeContext.prototype.getDestFilePath = function (sourceFile) { | ||
@@ -314,0 +372,0 @@ return (0, gratsRoot_1.getRelativeOutputPath)(this._options, sourceFile); |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -17,5 +17,6 @@ import { GraphQLError, Location, Source } from "graphql"; | ||
export declare class ReportableDiagnostics { | ||
_host: ts.CompilerHost; | ||
_host: ts.FormatDiagnosticsHost; | ||
_diagnostics: ts.Diagnostic[]; | ||
constructor(host: ts.CompilerHost, diagnostics: ts.Diagnostic[]); | ||
constructor(host: ts.FormatDiagnosticsHost, diagnostics: ts.Diagnostic[]); | ||
static fromDiagnostics(diagnostics: ts.Diagnostic[]): ReportableDiagnostics; | ||
formatDiagnosticsWithColorAndContext(): string; | ||
@@ -22,0 +23,0 @@ formatDiagnosticsWithContext(): string; |
@@ -29,3 +29,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.graphqlSourceToSourceFile = exports.diagnosticAtGraphQLLocation = exports.graphQlErrorToDiagnostic = exports.FAKE_ERROR_CODE = exports.ReportableDiagnostics = exports.err = exports.ok = void 0; | ||
@@ -46,2 +46,12 @@ var ts = require("typescript"); | ||
} | ||
// If you don't have a host, for example if you error while parsing the | ||
// tsconfig, you can use this method and one will be created for you. | ||
ReportableDiagnostics.fromDiagnostics = function (diagnostics) { | ||
var formatHost = { | ||
getCanonicalFileName: function (path) { return path; }, | ||
getCurrentDirectory: ts.sys.getCurrentDirectory, | ||
getNewLine: function () { return ts.sys.newLine; }, | ||
}; | ||
return new ReportableDiagnostics(formatHost, diagnostics); | ||
}; | ||
ReportableDiagnostics.prototype.formatDiagnosticsWithColorAndContext = function () { | ||
@@ -101,3 +111,3 @@ var formatted = ts.formatDiagnosticsWithColorAndContext(this._diagnostics, this._host); | ||
start: relatedNode.loc.start, | ||
length: relatedNode.loc.end - relatedNode.loc.start | ||
length: relatedNode.loc.end - relatedNode.loc.start, | ||
}); | ||
@@ -109,3 +119,3 @@ } | ||
try { | ||
if (rest_1_1 && !rest_1_1.done && (_a = rest_1["return"])) _a.call(rest_1); | ||
if (rest_1_1 && !rest_1_1.done && (_a = rest_1.return)) _a.call(rest_1); | ||
} | ||
@@ -128,3 +138,3 @@ finally { if (e_1) throw e_1.error; } | ||
length: length, | ||
relatedInformation: relatedInformation | ||
relatedInformation: relatedInformation, | ||
}; | ||
@@ -140,3 +150,3 @@ } | ||
start: loc.start, | ||
length: loc.end - loc.start | ||
length: loc.end - loc.start, | ||
}; | ||
@@ -143,0 +153,0 @@ } |
@@ -7,2 +7,2 @@ export declare class DefaultMap<K, V> { | ||
} | ||
export declare function extend<T>(a: T[], b: T[]): void; | ||
export declare function extend<T>(a: T[], b: readonly T[]): void; |
@@ -13,3 +13,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.extend = exports.DefaultMap = void 0; | ||
@@ -43,3 +43,3 @@ var DefaultMap = /** @class */ (function () { | ||
try { | ||
if (b_1_1 && !b_1_1.done && (_a = b_1["return"])) _a.call(b_1); | ||
if (b_1_1 && !b_1_1.done && (_a = b_1.return)) _a.call(b_1); | ||
} | ||
@@ -46,0 +46,0 @@ finally { if (e_1) throw e_1.error; } |
@@ -13,3 +13,3 @@ "use strict"; | ||
}; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.traverseJSDocTags = void 0; | ||
@@ -42,3 +42,3 @@ var ts = require("typescript"); | ||
try { | ||
if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
@@ -45,0 +45,0 @@ finally { if (e_1) throw e_1.error; } |
{ | ||
"name": "grats", | ||
"version": "0.0.0-main-6a722399", | ||
"version": "0.0.0-main-6ca96c43", | ||
"main": "dist/src/index.js", | ||
@@ -12,8 +12,8 @@ "bin": "dist/src/cli.js", | ||
"dependencies": { | ||
"@graphql-tools/utils": "^9.2.1", | ||
"commander": "^10.0.0", | ||
"graphql": "^16.6.0", | ||
"typescript": "^4.9.5" | ||
"typescript": "^5.0.2" | ||
}, | ||
"devDependencies": { | ||
"@graphql-tools/utils": "^9.2.1", | ||
"@types/node": "^18.14.6", | ||
@@ -26,2 +26,3 @@ "@typescript-eslint/eslint-plugin": "^5.55.0", | ||
"path-browserify": "^1.0.1", | ||
"prettier": "^2.8.7", | ||
"process": "^0.11.10", | ||
@@ -33,3 +34,3 @@ "ts-node": "^10.9.1" | ||
}, | ||
"packageManager": "pnpm@8.1.1", | ||
"packageManager": "pnpm@8.12.0", | ||
"engines": { | ||
@@ -43,4 +44,5 @@ "node": ">=16 <=21", | ||
"build": "tsc --build", | ||
"lint": "eslint src/**/*.ts" | ||
"format": "prettier . --write", | ||
"lint": "eslint src/**/*.ts && prettier . --check" | ||
} | ||
} |
@@ -1,5 +0,1 @@ | ||
# -=[ ALPHA SOFTWARE ]=- | ||
**Grats is still experimental. Feel free to try it out and give feedback, but they api is still in flux** | ||
# Grats: Implementation-First GraphQL for TypeScript | ||
@@ -9,2 +5,4 @@ | ||
_Beta Software: Grats is largely stable and being used in production in multiple places. If you encounter any issues, dont hesitate to let us know._ | ||
**What if building a GraphQL server were as simple as just writing functions?** | ||
@@ -18,7 +16,33 @@ | ||
By making your TypeScript implementation the source of truth, you never have to | ||
worry about valuating that your implementation matches your schema. Your | ||
worry about validating that your implementation matches your schema. Your | ||
implementation _is_ your schema! | ||
## Read the docs: https://grats.capt.dev/ | ||
## Example | ||
Here's what it looks like to define a User type with a greeting field using Grats: | ||
```ts | ||
/** @gqlType */ | ||
class User { | ||
/** @gqlField */ | ||
name: string; | ||
/** @gqlField */ | ||
greet(args: { greeting: string }): string { | ||
return `${args.greeting}, ${this.name}`; | ||
} | ||
} | ||
``` | ||
After running `npx grats`, you'll find a `schema.ts` module that exports an executable schema, and a `schema.graphql` file contins your GraphQL schema definition: | ||
```graphql | ||
type User { | ||
name: String | ||
greet(greeting: String!): String | ||
} | ||
``` | ||
That's just the begining! To learn more, **Read the docs: https://grats.capt.dev/** | ||
## Contributing | ||
@@ -25,0 +49,0 @@ |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
262302
3
87
5592
60
11
+ Addedtypescript@5.7.3(transitive)
- Removed@graphql-tools/utils@^9.2.1
- Removed@graphql-tools/utils@9.2.1(transitive)
- Removed@graphql-typed-document-node/core@3.2.0(transitive)
- Removedtslib@2.8.1(transitive)
- Removedtypescript@4.9.5(transitive)
Updatedtypescript@^5.0.2