@vanta-inc/eslint-plugin-vanta
Version:
Custom ESLint rules for Vanta
93 lines (92 loc) • 4.14 kB
JavaScript
;
/**
* @fileoverview Lint rule to ensure that all types reachable from fields marked as @public are themselves marked as @public.
*/
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
var eslint_plugin_1 = require("@graphql-eslint/eslint-plugin");
var graphql_1 = require("graphql");
var graphqlutils_1 = require("../utils/graphqlutils");
var PUBLIC_DIRECTIVE = "public";
var RULE_ID = "public-descendants-public";
var rule = {
meta: {
type: "problem",
docs: {
category: "Schema",
// @ts-ignore
description: "Ensures that all types reachable from fields marked as @public are themselves marked as @public.",
url: "https://github.com/VantaInc/eslint-plugin-vanta/blob/main/docs/rules/public-descendants-public.md",
requiresSchema: true,
},
messages: (_a = {},
_a[RULE_ID] = "All types reachable from fields marked as @public must be also marked as @public",
_a),
},
create: function (context) {
var schema = eslint_plugin_1.requireGraphQLSchemaFromContext(RULE_ID, context);
var hasPublicDirective = function (directives) {
return Boolean(directives === null || directives === void 0 ? void 0 : directives.find(function (x) { return x.name.value === PUBLIC_DIRECTIVE; }));
};
var fieldPointsToPublicTypeOrScalar = function (node) {
var _a;
var typeName = graphqlutils_1.extractNamedType(node.type).name.value;
var type = schema.getType(typeName);
if (!type) {
return true; // type not found; assume OK
}
// need to check a whitelist since the version of graphql we're using
// seems to not work with the instanceOf checks. Hoping we can get rid of
// this in the future.
var builtinScalars = ["Int", "Float", "String", "Boolean", "ID"];
var customScalarsAndEnums = [
"DateTime",
"reportStandard",
"testOutcome",
];
var typeIsScalar = type instanceof graphql_1.GraphQLScalarType ||
type instanceof graphql_1.GraphQLEnumType ||
builtinScalars.includes(typeName) ||
customScalarsAndEnums.includes(typeName);
return hasPublicDirective((_a = type.astNode) === null || _a === void 0 ? void 0 : _a.directives) || typeIsScalar;
};
return {
FieldDefinition: function (node) {
if (!hasPublicDirective(node.directives)) {
return;
}
if (!fieldPointsToPublicTypeOrScalar(node.rawNode())) {
context.report({
node: node,
message: "Types accessible by @" + PUBLIC_DIRECTIVE + " fields must be marked @" + PUBLIC_DIRECTIVE + ".",
});
}
},
ObjectTypeDefinition: function (node) {
var _a;
if (!hasPublicDirective(node.directives)) {
return;
}
(_a = node.rawNode().fields) === null || _a === void 0 ? void 0 : _a.forEach(function (field) {
if (!fieldPointsToPublicTypeOrScalar(field)) {
context.report({
node: node,
message: "Types accessible from @" + PUBLIC_DIRECTIVE + " types must themselves be marked @" + PUBLIC_DIRECTIVE + ". Unmarked field: " + field.name.value,
});
}
});
},
ObjectTypeExtension: function (node) {
if (!hasPublicDirective(node.directives)) {
return;
}
context.report({
node: node,
message: "@" + PUBLIC_DIRECTIVE + " directive not supported on type extensions",
});
},
};
},
};
module.exports = rule;
exports.default = rule;