@graphql-eslint/eslint-plugin
Version:
GraphQL plugin for ESLint
283 lines (282 loc) • 7.91 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var match_document_filename_exports = {};
__export(match_document_filename_exports, {
rule: () => rule
});
module.exports = __toCommonJS(match_document_filename_exports);
var import_path = require("path");
var import_graphql = require("graphql");
var import_utils = require("../utils.js");
const MATCH_EXTENSION = "MATCH_EXTENSION";
const MATCH_STYLE = "MATCH_STYLE";
const CASE_STYLES = [
"camelCase",
"PascalCase",
"snake_case",
"UPPER_CASE",
"kebab-case",
"matchDocumentStyle"
];
const schemaOption = {
oneOf: [{ $ref: "#/definitions/asString" }, { $ref: "#/definitions/asObject" }]
};
const schema = {
definitions: {
asString: {
enum: CASE_STYLES,
description: `One of: ${CASE_STYLES.map((t) => `\`${t}\``).join(", ")}`
},
asObject: {
type: "object",
additionalProperties: false,
minProperties: 1,
properties: {
style: { enum: CASE_STYLES },
suffix: { type: "string" },
prefix: { type: "string" }
}
}
},
type: "array",
minItems: 1,
maxItems: 1,
items: {
type: "object",
additionalProperties: false,
minProperties: 1,
properties: {
fileExtension: { enum: [".gql", ".graphql"] },
query: schemaOption,
mutation: schemaOption,
subscription: schemaOption,
fragment: schemaOption
}
}
};
const rule = {
meta: {
type: "suggestion",
docs: {
category: "Operations",
description: "This rule allows you to enforce that the file name should match the operation name.",
url: "https://the-guild.dev/graphql/eslint/rules/match-document-filename",
examples: [
{
title: "Correct",
usage: [{ fileExtension: ".gql" }],
code: (
/* GraphQL */
`
# user.gql
type User {
id: ID!
}
`
)
},
{
title: "Correct",
usage: [{ query: "snake_case" }],
code: (
/* GraphQL */
`
# user_by_id.gql
query UserById {
userById(id: 5) {
id
name
fullName
}
}
`
)
},
{
title: "Correct",
usage: [{ fragment: { style: "kebab-case", suffix: ".fragment" } }],
code: (
/* GraphQL */
`
# user-fields.fragment.gql
fragment user_fields on User {
id
email
}
`
)
},
{
title: "Correct",
usage: [{ mutation: { style: "PascalCase", suffix: "Mutation" } }],
code: (
/* GraphQL */
`
# DeleteUserMutation.gql
mutation DELETE_USER {
deleteUser(id: 5)
}
`
)
},
{
title: "Incorrect",
usage: [{ fileExtension: ".graphql" }],
code: (
/* GraphQL */
`
# post.gql
type Post {
id: ID!
}
`
)
},
{
title: "Incorrect",
usage: [{ query: "PascalCase" }],
code: (
/* GraphQL */
`
# user-by-id.gql
query UserById {
userById(id: 5) {
id
name
fullName
}
}
`
)
},
{
title: "Correct",
usage: [{ fragment: { style: "kebab-case", prefix: "mutation." } }],
code: (
/* GraphQL */
`
# mutation.add-alert.graphql
mutation addAlert {
foo
}
`
)
},
{
title: "Correct",
usage: [{ fragment: { prefix: "query." } }],
code: (
/* GraphQL */
`
# query.me.graphql
query me {
foo
}
`
)
}
],
configOptions: [
{
query: "kebab-case",
mutation: "kebab-case",
subscription: "kebab-case",
fragment: "kebab-case"
}
]
},
messages: {
[MATCH_EXTENSION]: `File extension "{{ fileExtension }}" don't match extension "{{ expectedFileExtension }}"`,
[MATCH_STYLE]: 'Unexpected filename "{{ filename }}". Rename it to "{{ expectedFilename }}"'
},
schema
},
create(context) {
const options = context.options[0] || {
fileExtension: null
};
const filePath = context.getFilename();
const isVirtualFile = import_utils.VIRTUAL_DOCUMENT_REGEX.test(filePath);
if (isVirtualFile) {
return {};
}
const fileExtension = (0, import_path.extname)(filePath);
const filename = (0, import_path.basename)(filePath, fileExtension);
return {
Document(documentNode) {
var _a;
if (options.fileExtension && options.fileExtension !== fileExtension) {
context.report({
loc: import_utils.REPORT_ON_FIRST_CHARACTER,
messageId: MATCH_EXTENSION,
data: {
fileExtension,
expectedFileExtension: options.fileExtension
}
});
}
const firstOperation = documentNode.definitions.find(
(n) => n.kind === import_graphql.Kind.OPERATION_DEFINITION
);
const firstFragment = documentNode.definitions.find(
(n) => n.kind === import_graphql.Kind.FRAGMENT_DEFINITION
);
const node = firstOperation || firstFragment;
if (!node) {
return;
}
const docName = (_a = node.name) == null ? void 0 : _a.value;
if (!docName) {
return;
}
const docType = "operation" in node ? node.operation : "fragment";
let option = options[docType];
if (!option) {
return;
}
if (typeof option === "string") {
option = { style: option };
}
const expectedExtension = options.fileExtension || fileExtension;
let expectedFilename = option.prefix || "";
if (option.style) {
expectedFilename += option.style === "matchDocumentStyle" ? docName : (0, import_utils.convertCase)(option.style, docName);
} else {
expectedFilename += filename;
}
expectedFilename += (option.suffix || "") + expectedExtension;
const filenameWithExtension = filename + expectedExtension;
if (expectedFilename !== filenameWithExtension) {
context.report({
loc: import_utils.REPORT_ON_FIRST_CHARACTER,
messageId: MATCH_STYLE,
data: {
expectedFilename,
filename: filenameWithExtension
}
});
}
}
};
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
rule
});