Open ludovic-pourrat opened 3 years ago
Hello @ludovic-pourrat,
There are some instructions on how to do this in the README
: https://github.com/cjoudrey/graphql-schema-linter#customizing-rules
You can also look at this library's rule set to better understand the syntax.
Let me know if you have other questions.
Cheers!
Got here with exactly the same question, just in case for anyone looking for a custom rule example
Suppose we have following schema:
type Country {
id: ID!
name: String!
}
type City {
id: ID!
name: String!
countryId: ID!
}
Technically schema is valid, but it has code smell
We going to prevent such cases by disallowing fields like whateverId: ID
rules/identifiers-are-connected.js
const { ValidationError } = require('graphql-schema-linter/lib/validation_error')
const camelCaseTest = RegExp('^.+Id$');
function IdentifiersAreConnected(context) {
return {
FieldDefinition(node, key, parent, path, ancestors) {
const fieldName = node.name.value;
let type = node.type;
while (type.type) {
type = type.type;
}
if (camelCaseTest.test(fieldName) && type.name.value === 'ID') {
const parentName = ancestors[ancestors.length - 1].name.value;
context.reportError(
new ValidationError(
'identifiers-are-connected', // <- Naming: Be careful with this one
`The field \`${parentName}.${fieldName}\` is not connected.`,
[node]
)
);
}
},
};
}
module.exports = {IdentifiersAreConnected} // <- Naming: Be careful with this one
Notes:
And now it is time to run our rule chek:
graphql-schema-linter schema.graphql --custom-rule-paths rules/*.js --rules identifiers-are-connected
And if everything correct you will get desired:
9:3 The field `City.countryId` is not connected. identifiers-are-connected
Notes:
graphql-schema-linter.config.js
module.exports = {
// https://github.com/cjoudrey/graphql-schema-linter#built-in-rules
rules: [
// 'arguments-have-descriptions',
'defined-types-are-used',
'deprecations-have-a-reason',
'descriptions-are-capitalized',
'enum-values-all-caps',
// 'enum-values-have-descriptions',
// 'enum-values-sorted-alphabetically',
'fields-are-camel-cased',
// 'fields-have-descriptions',
// 'input-object-fields-sorted-alphabetically',
'input-object-values-are-camel-cased',
// 'input-object-values-have-descriptions',
// 'interface-fields-sorted-alphabetically',
'relay-connection-types-spec',
'relay-connection-arguments-spec',
// 'type-fields-sorted-alphabetically',
'types-are-capitalized',
// 'types-have-descriptions',
'identifiers-are-connected', // <- here is our custom rule
],
customRulePaths: [
'rules/*.js' // <- add everything at once
],
ignore: {
'defined-types-are-used': [
'DateTimeOffset',
'Seconds',
'Milliseconds',
'Uri',
'Guid',
'Short',
'UShort',
'UInt',
'Long',
'BigInt',
'ULong',
'Byte',
'SByte',
],
'fields-are-camel-cased': [
'Query._entities',
'Query._service',
],
'types-are-capitalized': [
'_Service'
]
},
schemaPaths: [
'schema.graphql'
]
}
Hi,
Is there a way to be able to test our custom rules?
Hi,
Is there a way to be able to test our custom rules?
Hi @isha-talegaonkar,
I would recommend digging into the library's test suite you'll be able to find examples of how the library's rules are tested.
Here are two files that could be useful:
If folks would find this useful, we can always export the test helpers so that other developers can use them when testing their custom rules.
heh, hello few years later, landed here while trying to figure out is there typescript typings and found this issue :)
for anyone interesting of tests, here is how it may look like for example above:
const { IdentifiersAreConnected } = require('./identifiers-are-connected')
const { expectFailsRule, expectPassesRule } = require('../utils/assertions')
describe('IdentifiersAreConnected', () => {
it('catches fields that are not connected', () => {
expectFailsRule(
IdentifiersAreConnected,
`
type Country {
id: ID!
}
type City {
# Invalid
countryId: ID!
# Valid
country: Country
}
interface CityInterface {
# Invalid
countryId: ID!
# Valid
country: Country
}
`,
[{ message: 'The field `City.countryId` is not connected.' }, { message: 'The field `CityInterface.countryId` is not connected.' }],
)
expectPassesRule(
IdentifiersAreConnected,
`
type AddResourceOutputData {
resourceId: ID
}
`,
)
})
})
Hello,
I don't find any guidelines or samples to setup custom rules ?