Comparing version 0.0.3 to 0.0.4
{ | ||
"name": "grats", | ||
"version": "0.0.2", | ||
"version": "0.0.4", | ||
"main": "dist/src/index.js", | ||
@@ -5,0 +5,0 @@ "bin": "dist/src/cli.js", |
@@ -12,3 +12,2 @@ /** | ||
export declare function fieldTagOnWrongNode(): string; | ||
export declare function implementsTagOnWrongNode(): string; | ||
export declare function killsParentOnExceptionOnWrongNode(): string; | ||
@@ -73,2 +72,5 @@ export declare function wrongCasingForGratsTag(actual: string, expected: string): string; | ||
export declare function implementsTagMissingValue(): string; | ||
export declare function implementsTagOnClass(): string; | ||
export declare function implementsTagOnInterface(): string; | ||
export declare function implementsTagOnTypeAlias(): string; | ||
export declare function duplicateTag(tagName: string): string; | ||
@@ -75,0 +77,0 @@ export declare function duplicateInterfaceTag(): string; |
"use strict"; | ||
exports.__esModule = true; | ||
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.implementsTagOnWrongNode = exports.fieldTagOnWrongNode = void 0; | ||
exports.unresolvedTypeReference = exports.invalidTypePassedToFieldFunction = exports.parameterPropertyMissingType = exports.parameterPropertyNotPublic = exports.parameterWithoutModifiers = exports.duplicateInterfaceTag = exports.duplicateTag = exports.implementsTagMissingValue = exports.mergedInterfaces = exports.nonNullTypeCannotBeOptional = exports.killsParentOnExceptionOnNullable = exports.killsParentOnExceptionWithWrongConfig = exports.expectedIdentifer = exports.pluralTypeMissingParameter = exports.unknownGraphQLType = exports.unsupportedTypeLiteral = exports.defaultArgPropertyMissingInitializer = exports.defaultArgPropertyMissingName = void 0; | ||
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.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.expectedIdentifer = exports.pluralTypeMissingParameter = exports.unknownGraphQLType = exports.unsupportedTypeLiteral = exports.defaultArgPropertyMissingInitializer = void 0; | ||
var Extractor_1 = require("./Extractor"); | ||
@@ -9,3 +9,4 @@ // TODO: Move these to short URLS that are easier to keep from breaking. | ||
mergedInterfaces: "https://grats.capt.dev/docs/dockblock-tags/interfaces/#merged-interfaces", | ||
parameterProperties: "https://grats.capt.dev/docs/dockblock-tags/fields#class-based-fields" | ||
parameterProperties: "https://grats.capt.dev/docs/dockblock-tags/fields#class-based-fields", | ||
typeImplementsInterface: "TODO" | ||
}; | ||
@@ -26,6 +27,2 @@ /** | ||
exports.fieldTagOnWrongNode = fieldTagOnWrongNode; | ||
function implementsTagOnWrongNode() { | ||
return "`@".concat(Extractor_1.IMPLEMENTS_TAG, "` can only be used on Grats type or interface declarations. Did you mean to include the `@").concat(Extractor_1.TYPE_TAG, "` or `@").concat(Extractor_1.INTERFACE_TAG, "` tag in this docblock?"); | ||
} | ||
exports.implementsTagOnWrongNode = implementsTagOnWrongNode; | ||
function killsParentOnExceptionOnWrongNode() { | ||
@@ -271,5 +268,17 @@ return "Unexpected `@".concat(Extractor_1.KILLS_PARENT_ON_EXCEPTION_TAG, "`. `@").concat(Extractor_1.KILLS_PARENT_ON_EXCEPTION_TAG, "` can only be used in field annotation docblocks. Perhaps you are missing a `@").concat(Extractor_1.FIELD_TAG, "` tag?"); | ||
function implementsTagMissingValue() { | ||
return "Expected `@".concat(Extractor_1.IMPLEMENTS_TAG, "` to be followed by one or more interface names."); | ||
return "Expected `@".concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, "` to be followed by one or more interface names."); | ||
} | ||
exports.implementsTagMissingValue = implementsTagMissingValue; | ||
function implementsTagOnClass() { | ||
return "`@".concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, "` has been deprecated. Instead use `class MyType implements MyInterface`."); | ||
} | ||
exports.implementsTagOnClass = implementsTagOnClass; | ||
function implementsTagOnInterface() { | ||
return "`@".concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, "` has been deprecated. Instead use `interface MyType extends MyInterface`."); | ||
} | ||
exports.implementsTagOnInterface = implementsTagOnInterface; | ||
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, "."); | ||
} | ||
exports.implementsTagOnTypeAlias = implementsTagOnTypeAlias; | ||
function duplicateTag(tagName) { | ||
@@ -280,3 +289,3 @@ return "Unexpected duplicate `@".concat(tagName, "` tag. Grats does not accept multiple instances of the same tag."); | ||
function duplicateInterfaceTag() { | ||
return "Unexpected duplicate `@".concat(Extractor_1.IMPLEMENTS_TAG, "` tag. To declare that a type or interface implements multiple interfaces list them as comma separated values: `@").concat(Extractor_1.IMPLEMENTS_TAG, " interfaceA, interfaceB`."); | ||
return "Unexpected duplicate `@".concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, "` tag. To declare that a type or interface implements multiple interfaces list them as comma separated values: `@").concat(Extractor_1.IMPLEMENTS_TAG_DEPRECATED, " interfaceA, interfaceB`."); | ||
} | ||
@@ -286,3 +295,3 @@ exports.duplicateInterfaceTag = duplicateInterfaceTag; | ||
return [ | ||
"Expected `@".concat(Extractor_1.FIELD_TAG, "` constructor paramater to be a parameter property. This requires a modifier such as `public` or `readonly` before the parameter name.\n\n"), | ||
"Expected `@".concat(Extractor_1.FIELD_TAG, "` constructor parameter to be a parameter property. This requires a modifier such as `public` or `readonly` before the parameter name.\n\n"), | ||
"Learn more: ".concat(DOC_URLS.parameterProperties), | ||
@@ -289,0 +298,0 @@ ].join(""); |
@@ -17,3 +17,3 @@ import { FieldDefinitionNode, InputValueDefinitionNode, NamedTypeNode, NameNode, TypeNode, StringValueNode, ConstValueNode, ConstDirectiveNode, EnumValueDefinitionNode, ConstObjectFieldNode, ConstObjectValueNode, ConstListValueNode } from "graphql"; | ||
export declare const INPUT_TAG = "gqlInput"; | ||
export declare const IMPLEMENTS_TAG = "gqlImplements"; | ||
export declare const IMPLEMENTS_TAG_DEPRECATED = "gqlImplements"; | ||
export declare const KILLS_PARENT_ON_EXCEPTION_TAG = "killsParentOnException"; | ||
@@ -74,4 +74,6 @@ export declare const ALL_TAGS: string[]; | ||
collectInterfaces(node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.TypeAliasDeclaration): Array<NamedTypeNode> | null; | ||
collectTagInterfaces(node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.TypeAliasDeclaration): Array<NamedTypeNode> | null; | ||
collectHeritageInterfaces(node: ts.ClassDeclaration): Array<NamedTypeNode> | null; | ||
reportTagInterfaces(node: ts.TypeAliasDeclaration | ts.ClassDeclaration | ts.InterfaceDeclaration): null | undefined; | ||
collectHeritageInterfaces(node: ts.ClassDeclaration | ts.InterfaceDeclaration): Array<NamedTypeNode> | null; | ||
symbolHasGqlTag(node: ts.Node): boolean; | ||
hasGqlTag(node: ts.Node): boolean; | ||
interfaceInterfaceDeclaration(node: ts.InterfaceDeclaration, tag: ts.JSDocTag): null | undefined; | ||
@@ -78,0 +80,0 @@ collectFields(node: ts.ClassDeclaration | ts.InterfaceDeclaration | ts.TypeLiteralNode): Array<FieldDefinitionNode>; |
@@ -30,3 +30,3 @@ "use strict"; | ||
exports.__esModule = true; | ||
exports.Extractor = exports.ALL_TAGS = exports.KILLS_PARENT_ON_EXCEPTION_TAG = exports.IMPLEMENTS_TAG = 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; | ||
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; | ||
var graphql_1 = require("graphql"); | ||
@@ -38,3 +38,2 @@ var DiagnosticError_1 = require("./utils/DiagnosticError"); | ||
var JSDoc_1 = require("./utils/JSDoc"); | ||
var helpers_1 = require("./utils/helpers"); | ||
var GraphQLConstructor_1 = require("./GraphQLConstructor"); | ||
@@ -52,3 +51,3 @@ var serverDirectives_1 = require("./serverDirectives"); | ||
exports.INPUT_TAG = "gqlInput"; | ||
exports.IMPLEMENTS_TAG = "gqlImplements"; | ||
exports.IMPLEMENTS_TAG_DEPRECATED = "gqlImplements"; | ||
exports.KILLS_PARENT_ON_EXCEPTION_TAG = "killsParentOnException"; | ||
@@ -64,3 +63,2 @@ // All the tags that start with gql | ||
exports.INPUT_TAG, | ||
exports.IMPLEMENTS_TAG, | ||
]; | ||
@@ -128,11 +126,2 @@ var DEPRECATED_TAG = "deprecated"; | ||
break; | ||
case exports.IMPLEMENTS_TAG: { | ||
var hasTypeOrInterfaceTag = ts.getJSDocTags(node).some(function (t) { | ||
return (t.tagName.text === exports.TYPE_TAG || t.tagName.text === exports.INTERFACE_TAG); | ||
}); | ||
if (!hasTypeOrInterfaceTag) { | ||
_this.report(tag.tagName, E.implementsTagOnWrongNode()); | ||
} | ||
break; | ||
} | ||
case exports.KILLS_PARENT_ON_EXCEPTION_TAG: { | ||
@@ -545,23 +534,20 @@ var hasFieldTag = ts.getJSDocTags(node).some(function (t) { | ||
Extractor.prototype.collectInterfaces = function (node) { | ||
var heritageInterfaces = ts.isClassDeclaration(node) | ||
this.reportTagInterfaces(node); | ||
return ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) | ||
? this.collectHeritageInterfaces(node) | ||
: null; | ||
return (0, helpers_1.concatMaybeArrays)(heritageInterfaces, this.collectTagInterfaces(node)); | ||
}; | ||
Extractor.prototype.collectTagInterfaces = function (node) { | ||
var _this = this; | ||
var tag = this.findTag(node, exports.IMPLEMENTS_TAG); | ||
Extractor.prototype.reportTagInterfaces = function (node) { | ||
var tag = this.findTag(node, exports.IMPLEMENTS_TAG_DEPRECATED); | ||
if (tag == null) | ||
return null; | ||
var commentName = ts.getTextOfJSDocComment(tag.comment); | ||
if (commentName == null) { | ||
return this.report(tag, E.implementsTagMissingValue()); | ||
if (node.kind === ts.SyntaxKind.ClassDeclaration) { | ||
this.report(tag, E.implementsTagOnClass()); | ||
} | ||
return commentName.split(",").map(function (name) { | ||
// FIXME: Use more targeted location information. | ||
// Will require rewriting everything that expects a node for location | ||
// purposes to transform the node into a location eagerly. Then we can have | ||
// a richer set of tools to construct custom locations. | ||
return _this.gql.namedType(tag, name.trim()); | ||
}); | ||
if (node.kind === ts.SyntaxKind.InterfaceDeclaration) { | ||
this.report(tag, E.implementsTagOnInterface()); | ||
} | ||
if (node.kind === ts.SyntaxKind.TypeAliasDeclaration) { | ||
this.report(tag, E.implementsTagOnTypeAlias()); | ||
} | ||
}; | ||
@@ -572,12 +558,18 @@ Extractor.prototype.collectHeritageInterfaces = function (node) { | ||
return null; | ||
var maybeInterfaces = node.heritageClauses.flatMap(function (clause) { | ||
if (clause.token !== ts.SyntaxKind.ImplementsKeyword) | ||
return []; | ||
return clause.types.map(function (type) { | ||
if (!ts.isIdentifier(type.expression)) { | ||
// TODO: Are there valid cases we want to cover here? | ||
return null; | ||
} | ||
var namedType = _this.gql.namedType(type.expression, TypeContext_1.UNRESOLVED_REFERENCE_NAME); | ||
_this.ctx.markUnresolvedType(type.expression, namedType.name); | ||
var maybeInterfaces = node.heritageClauses | ||
.filter(function (clause) { | ||
if (node.kind === ts.SyntaxKind.ClassDeclaration) { | ||
return clause.token === ts.SyntaxKind.ImplementsKeyword; | ||
} | ||
// Interfaces can only have extends clauses, and those are allowed. | ||
return true; | ||
}) | ||
.flatMap(function (clause) { | ||
return clause.types | ||
.map(function (type) { return type.expression; }) | ||
.filter(function (expression) { return ts.isIdentifier(expression); }) | ||
.filter(function (expression) { return _this.symbolHasGqlTag(expression); }) | ||
.map(function (expression) { | ||
var namedType = _this.gql.namedType(expression, TypeContext_1.UNRESOLVED_REFERENCE_NAME); | ||
_this.ctx.markUnresolvedType(expression, namedType.name); | ||
return namedType; | ||
@@ -592,2 +584,17 @@ }); | ||
}; | ||
Extractor.prototype.symbolHasGqlTag = function (node) { | ||
var _a; | ||
var symbol = this.ctx.checker.getSymbolAtLocation(node); | ||
if (symbol == null) | ||
return false; | ||
var declaration = (_a = symbol.declarations) === null || _a === void 0 ? void 0 : _a[0]; | ||
if (declaration == null) | ||
return false; | ||
return this.hasGqlTag(declaration); | ||
}; | ||
Extractor.prototype.hasGqlTag = function (node) { | ||
return ts.getJSDocTags(node).some(function (tag) { | ||
return exports.ALL_TAGS.includes(tag.tagName.text); | ||
}); | ||
}; | ||
Extractor.prototype.interfaceInterfaceDeclaration = function (node, tag) { | ||
@@ -1260,3 +1267,3 @@ var _this = this; | ||
}); | ||
var message = tagName === exports.IMPLEMENTS_TAG | ||
var message = tagName === exports.IMPLEMENTS_TAG_DEPRECATED | ||
? E.duplicateInterfaceTag() | ||
@@ -1263,0 +1270,0 @@ : E.duplicateTag(tagName); |
@@ -39,5 +39,5 @@ "use strict"; | ||
var implementor = _g.value; | ||
var resolved = typeContext.resolveNamedDefinition(implementor.name); | ||
var resolved = typeContext.resolveNamedType(implementor.name); | ||
if (resolved.kind === "ERROR") { | ||
errors.push(resolved.err); | ||
// We trust that these errors will be reported elsewhere. | ||
continue; | ||
@@ -64,5 +64,5 @@ } | ||
var implementor = _j.value; | ||
var resolved = typeContext.resolveNamedDefinition(implementor.name); | ||
var resolved = typeContext.resolveNamedType(implementor.name); | ||
if (resolved.kind === "ERROR") { | ||
errors.push(resolved.err); | ||
// We trust that these errors will be reported elsewhere. | ||
continue; | ||
@@ -69,0 +69,0 @@ } |
@@ -43,3 +43,2 @@ import { DefinitionNode, DocumentNode, FieldDefinitionNode, Location, NameNode } from "graphql"; | ||
addAbstractFieldDefinition(doc: AbstractFieldDefinitionNode, interfaceGraph: InterfaceMap): DiagnosticsResult<DefinitionNode[]>; | ||
resolveNamedDefinition(unresolved: NameNode): DiagnosticResult<NameNode>; | ||
resolveNamedType(unresolved: NameNode): DiagnosticResult<NameNode>; | ||
@@ -46,0 +45,0 @@ err(loc: Location, message: string, relatedInformation?: ts.DiagnosticRelatedInformation[]): ts.Diagnostic; |
@@ -240,20 +240,2 @@ "use strict"; | ||
}; | ||
TypeContext.prototype.resolveNamedDefinition = function (unresolved) { | ||
var symbol = this._unresolvedTypes.get(unresolved); | ||
if (symbol == null) { | ||
if (unresolved.value === exports.UNRESOLVED_REFERENCE_NAME) { | ||
// This is a logic error on our side. | ||
throw new Error("Unexpected unresolved reference name."); | ||
} | ||
return (0, DiagnosticError_1.ok)(unresolved); | ||
} | ||
var nameDefinition = this._symbolToName.get(symbol); | ||
if (nameDefinition == null) { | ||
if (unresolved.loc == null) { | ||
throw new Error("Expected namedType to have a location."); | ||
} | ||
return (0, DiagnosticError_1.err)(this.err(unresolved.loc, E.unresolvedTypeReference())); | ||
} | ||
return (0, DiagnosticError_1.ok)(__assign(__assign({}, unresolved), { value: nameDefinition.name.value })); | ||
}; | ||
TypeContext.prototype.resolveNamedType = function (unresolved) { | ||
@@ -260,0 +242,0 @@ var symbol = this._unresolvedTypes.get(unresolved); |
@@ -1,2 +0,1 @@ | ||
export declare function concatMaybeArrays<T>(a: T[] | null, b: T[] | null): T[] | null; | ||
export declare class DefaultMap<K, V> { | ||
@@ -3,0 +2,0 @@ private readonly getDefault; |
@@ -14,13 +14,3 @@ "use strict"; | ||
exports.__esModule = true; | ||
exports.extend = exports.DefaultMap = exports.concatMaybeArrays = void 0; | ||
// Returns null if both are null, otherwise returns the concatenated values of | ||
// the non-null arrays. | ||
function concatMaybeArrays(a, b) { | ||
if (a == null) | ||
return b; | ||
if (b == null) | ||
return a; | ||
return a.concat(b); | ||
} | ||
exports.concatMaybeArrays = concatMaybeArrays; | ||
exports.extend = exports.DefaultMap = void 0; | ||
var DefaultMap = /** @class */ (function () { | ||
@@ -27,0 +17,0 @@ function DefaultMap(getDefault) { |
{ | ||
"name": "grats", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"main": "dist/src/index.js", | ||
@@ -5,0 +5,0 @@ "bin": "dist/src/cli.js", |
201088
4179