Skip to content

Commit d71cad2

Browse files
dimaMachinadotansimha
authored andcommitted
upd
upd upd upd upd upd upd package.json fix typecheck upd graphql-eslint fix lint try fix lockfile fixes fixes
1 parent 7fdfdf8 commit d71cad2

19 files changed

+794
-573
lines changed

.eslintrc.cjs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ const guildConfig = require('@theguild/eslint-config/base');
55
const { REACT_RESTRICTED_SYNTAX, RESTRICTED_SYNTAX } = require('@theguild/eslint-config/constants');
66
const path = require('path');
77

8-
const SCHEMA_PATH = './packages/services/api/src/modules/*/module.graphql.ts';
9-
const OPERATIONS_PATHS = [
10-
'./packages/web/app/**/*.ts',
11-
'./packages/web/app/**/*.tsx',
12-
'./packages/web/app/**/*.graphql',
13-
];
14-
158
const rulesToExtends = Object.fromEntries(
169
Object.entries(guildConfig.rules).filter(([key]) =>
1710
[
@@ -70,20 +63,25 @@ module.exports = {
7063
parser: '@graphql-eslint/eslint-plugin',
7164
plugins: ['@graphql-eslint'],
7265
parserOptions: {
73-
schema: SCHEMA_PATH,
74-
operations: OPERATIONS_PATHS,
66+
graphQLConfig: {
67+
schema: './packages/services/api/src/modules/*/module.graphql.ts',
68+
documents: [
69+
'./packages/web/app/**/*.ts',
70+
'./packages/web/app/**/*.tsx',
71+
'./packages/web/app/**/*.graphql',
72+
],
73+
},
7574
},
7675
},
7776
{
7877
// Setup processor for operations/fragments definitions on code-files
79-
files: ['packages/web/app/**/*.tsx', 'packages/web/app/**/*.ts'],
78+
files: ['packages/web/app/**/*.{ts,tsx}'],
8079
processor: '@graphql-eslint/graphql',
8180
},
8281
{
8382
files: ['packages/web/app/**/*.graphql'],
84-
plugins: ['@graphql-eslint'],
8583
rules: {
86-
'@graphql-eslint/require-id-when-available': 'error',
84+
'@graphql-eslint/require-selections': 'error',
8785
'@graphql-eslint/no-deprecated': 'error',
8886
},
8987
},

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@
6565
"@graphql-codegen/typescript-operations": "4.5.1",
6666
"@graphql-codegen/typescript-resolvers": "4.4.4",
6767
"@graphql-codegen/urql-introspection": "3.0.0",
68-
"@graphql-eslint/eslint-plugin": "3.20.1",
68+
"@graphql-eslint/eslint-plugin": "4.4.0",
6969
"@graphql-inspector/cli": "4.0.3",
7070
"@manypkg/get-packages": "2.2.2",
71-
"@next/eslint-plugin-next": "14.2.23",
71+
"@next/eslint-plugin-next": "15.0.4",
7272
"@parcel/watcher": "2.5.0",
7373
"@sentry/cli": "2.40.0",
7474
"@swc/core": "1.10.6",
@@ -121,8 +121,7 @@
121121
122122
"@apollo/[email protected]": "patches/@[email protected]",
123123
"@theguild/[email protected]": "patches/@[email protected]",
124-
125-
"@graphql-eslint/[email protected]": "patches/@[email protected]",
124+
"eslint": "patches/eslint.patch",
126125
127126
128127
"@oclif/[email protected]": "patches/@[email protected]",

packages/services/policy/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
"typecheck": "tsc --noEmit"
1010
},
1111
"devDependencies": {
12-
"@graphql-eslint/eslint-plugin": "3.20.1",
12+
"@graphql-eslint/eslint-plugin": "4.4.0",
1313
"@hive/service-common": "workspace:*",
1414
"@sentry/node": "7.120.2",
1515
"@sentry/tracing": "7.114.0",
1616
"@trpc/server": "10.45.2",
17-
"@types/eslint": "8.56.12",
17+
"@types/eslint": "9.6.1",
1818
"ajv": "8.17.1",
1919
"dotenv": "16.4.7",
20-
"eslint": "8.57.1",
20+
"eslint": "9.23.0",
2121
"fastify": "4.29.0",
2222
"graphql": "16.9.0",
2323
"pino-pretty": "11.3.0",

packages/services/policy/src/api.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ export const schemaPolicyApiRouter = t.router({
6464
availableRules: procedure.query(() => {
6565
return RELEVANT_RULES.map(([name, rule]) => ({
6666
name,
67-
description: rule.meta.docs?.description || '',
68-
recommended: rule.meta.docs?.recommended ?? false,
69-
url: rule.meta.docs?.url,
70-
schema: normalizeAjvSchema(rule.meta.schema) as object | null,
67+
description: rule.meta!.docs!.description || '',
68+
recommended: rule.meta!.docs!.recommended ?? false,
69+
url: rule.meta!.docs!.url,
70+
schema: normalizeAjvSchema(rule.meta!.schema),
7171
}));
7272
}),
7373
validateConfig: procedure.input(CONFIG_CHECK_INPUT_VALIDATION).query(() => {
Lines changed: 96 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Ajv from 'ajv';
2-
import { Linter } from 'eslint';
2+
import { ESLint, Linter } from 'eslint';
33
import { z, ZodType } from 'zod';
4-
import { GraphQLESLintRule, parseForESLint, rules } from '@graphql-eslint/eslint-plugin';
4+
import { GraphQLESLintRule, parser, rules } from '@graphql-eslint/eslint-plugin';
55
import { RELEVANT_RULES } from './rules';
66

77
const ajv = new Ajv({
@@ -12,24 +12,23 @@ const ajv = new Ajv({
1212
allowMatchingProperties: true,
1313
});
1414
const linter = new Linter();
15-
linter.defineParser('@graphql-eslint/eslint-plugin', { parseForESLint });
1615

17-
for (const [ruleId, rule] of Object.entries(rules)) {
18-
linter.defineRule(ruleId, rule as any);
19-
}
20-
21-
const RULE_LEVEL = z.union([z.number().min(0).max(2), z.enum(['off', 'warn', 'error'])]);
16+
const RULE_LEVEL = z.union([
17+
//
18+
z.number().min(0).max(2),
19+
z.enum(['off', 'warn', 'error']),
20+
]);
2221

23-
type RulemapValidationType = {
22+
type RuleMapValidationType = {
2423
[RuleKey in keyof typeof rules]: ZodType;
2524
};
2625

2726
export function normalizeAjvSchema(
28-
schema: GraphQLESLintRule['meta']['schema'],
29-
): GraphQLESLintRule['meta']['schema'] {
27+
schema: NonNullable<GraphQLESLintRule['meta']>['schema'],
28+
): NonNullable<GraphQLESLintRule['meta']>['schema'] {
3029
if (Array.isArray(schema)) {
3130
if (schema.length === 0) {
32-
return null;
31+
return;
3332
}
3433

3534
return {
@@ -40,44 +39,48 @@ export function normalizeAjvSchema(
4039
};
4140
}
4241

43-
return schema || null;
42+
return schema;
4443
}
4544

4645
export function createInputValidationSchema() {
4746
return z
4847
.object(
4948
RELEVANT_RULES.reduce((acc, [name, rule]) => {
50-
const schema = normalizeAjvSchema(rule.meta.schema);
49+
const schema = normalizeAjvSchema(rule.meta!.schema);
5150
const validate = schema ? ajv.compile(schema) : null;
51+
const cfg = z.union([
52+
z.tuple([RULE_LEVEL]),
53+
z.tuple(
54+
validate
55+
? [
56+
RULE_LEVEL,
57+
z.custom(data => {
58+
const asArray = (Array.isArray(data) ? data : [data]).filter(Boolean);
59+
const result = validate(asArray);
60+
61+
if (result) {
62+
return true;
63+
}
64+
65+
throw new Error(
66+
`Failed to validate rule "${name}" configuration: ${ajv.errorsText(
67+
validate.errors,
68+
)}`,
69+
);
70+
}),
71+
]
72+
: [RULE_LEVEL],
73+
),
74+
]);
5275

5376
return {
5477
...acc,
55-
[name]: z.union([
56-
z.tuple([RULE_LEVEL]),
57-
z.tuple(
58-
validate
59-
? [
60-
RULE_LEVEL,
61-
z.custom(data => {
62-
const asArray = (Array.isArray(data) ? data : [data]).filter(Boolean);
63-
const result = validate(asArray);
64-
65-
if (result) {
66-
return true;
67-
}
68-
69-
throw new Error(
70-
`Failed to validate rule "${name}" configuration: ${ajv.errorsText(
71-
validate.errors,
72-
)}`,
73-
);
74-
}),
75-
]
76-
: [RULE_LEVEL],
77-
),
78-
]),
78+
// v3 rules were using just a raw name, and v4 rule is using the plugin name as prefix
79+
// This fix should make sure both will work.
80+
[name]: cfg,
81+
[`@graphql-eslint/${name}`]: cfg,
7982
};
80-
}, {} as RulemapValidationType),
83+
}, {} as RuleMapValidationType),
8184
)
8285
.required()
8386
.partial()
@@ -86,18 +89,68 @@ export function createInputValidationSchema() {
8689

8790
export type PolicyConfigurationObject = z.infer<ReturnType<typeof createInputValidationSchema>>;
8891

92+
type NarrowPrefixKeys<T extends Record<string, any>, Prefix extends string> = {
93+
[K in keyof T as `${Prefix}${string & K}`]: T[K];
94+
};
95+
96+
type NormalizedPolicyConfigurationObject = NarrowPrefixKeys<
97+
PolicyConfigurationObject,
98+
'@graphql-eslint/'
99+
>;
100+
101+
/**
102+
* Transforms v3/v4 policy to v4, ensuring "@graphql-eslint" prefix is used.
103+
104+
* @param inputPolicy v3/v4 policy
105+
* @returns v4
106+
*/
107+
function normalizeInputPolicy(
108+
inputPolicy: PolicyConfigurationObject,
109+
): NormalizedPolicyConfigurationObject {
110+
return Object.keys(inputPolicy).reduce((acc, key) => {
111+
const normalizedKey = (
112+
key.startsWith('@graphql-eslint/') ? key : `@graphql-eslint/${key}`
113+
) as keyof NormalizedPolicyConfigurationObject;
114+
115+
acc[normalizedKey] = inputPolicy[key as keyof PolicyConfigurationObject];
116+
return acc;
117+
}, {} as NormalizedPolicyConfigurationObject);
118+
}
119+
89120
export async function schemaPolicyCheck(input: {
90121
source: string;
91122
schema: string;
92123
policy: PolicyConfigurationObject;
93124
}) {
94-
return linter.verify(
125+
const normalizedPolicy = normalizeInputPolicy(input.policy);
126+
127+
const rulesMap: Record<string, ESLint.Plugin> = {
128+
// "any" here is used because we have weird typing issues with v3 -> v4.
129+
'@graphql-eslint': { rules: rules as any },
130+
};
131+
132+
const linterResult = linter.verify(
95133
input.source,
96134
{
97-
parser: '@graphql-eslint/eslint-plugin',
98-
parserOptions: { schema: input.schema },
99-
rules: input.policy,
135+
files: ['*.graphql'],
136+
plugins: rulesMap,
137+
languageOptions: {
138+
parser,
139+
parserOptions: {
140+
schemaSdl: input.schema,
141+
filePath: 'schema.graphql',
142+
},
143+
},
144+
rules: normalizedPolicy,
100145
},
101146
'schema.graphql',
102147
);
148+
149+
return linterResult.map(r => {
150+
return {
151+
...r,
152+
// v4 returns is a bit different from v3, so we need to handle it differently to keep the responses the same.
153+
ruleId: r.ruleId?.replace('@graphql-eslint/', ''),
154+
};
155+
});
103156
}

packages/services/policy/src/rules.ts

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,49 @@ type RuleName = keyof AllRulesType;
55

66
const SKIPPED_RULES: RuleName[] = [
77
// Skipped because in order to operate, it needs operations.
8-
// Also it does not make sense to run it as part of a schema check.
8+
// Also, it does not make sense to run it as part of a schema check.
99
'no-unused-fields',
1010
];
1111

12-
function isRelevantCategory(category?: CategoryType | CategoryType[]): boolean {
13-
if (!category) {
14-
return false;
12+
function isRelevantCategory(category: CategoryType | CategoryType[]): boolean {
13+
if (Array.isArray(category)) {
14+
return category.some(cat => cat === 'Schema');
1515
}
1616

17-
return Array.isArray(category) ? category.includes('Schema') : category === 'Schema';
17+
return category === 'Schema';
1818
}
1919

2020
// Some rules have configurations for operations (like "alphabetize") and we do not want to expose them.
2121
function patchRulesConfig<T extends RuleName>(
2222
ruleName: T,
2323
ruleDef: AllRulesType[T],
2424
): GraphQLESLintRule {
25+
const { schema } = ruleDef.meta as any;
2526
switch (ruleName) {
2627
case 'alphabetize': {
2728
// Remove operation-specific configurations
28-
delete ruleDef.meta.schema.items.properties.selections;
29-
delete ruleDef.meta.schema.items.properties.variables;
29+
delete schema.items.properties.selections;
30+
delete schema.items.properties.variables;
3031
break;
3132
}
3233
case 'naming-convention': {
3334
// Remove operation-specific configurations
34-
delete ruleDef.meta.schema.items.properties.VariableDefinition;
35-
delete ruleDef.meta.schema.items.properties.OperationDefinition;
35+
delete schema.items.properties.VariableDefinition;
36+
delete schema.items.properties.OperationDefinition;
3637

37-
// Get rid of "definitions" references becuse it's breaking Monaco editor in the frontend
38-
Object.entries(ruleDef.meta.schema.items.properties).forEach(([, propDef]) => {
38+
// Get rid of "definitions" references because it's breaking Monaco editor in the frontend
39+
Object.entries(schema.items.properties).forEach(([, propDef]) => {
3940
if (propDef && typeof propDef === 'object' && 'oneOf' in propDef) {
40-
propDef.oneOf = [
41-
ruleDef.meta.schema.definitions.asObject,
42-
ruleDef.meta.schema.definitions.asString,
43-
];
41+
propDef.oneOf = [schema.definitions.asObject, schema.definitions.asString];
4442
}
4543
});
46-
ruleDef.meta.schema.items.patternProperties = {
44+
schema.items.patternProperties = {
4745
'^(Argument|DirectiveDefinition|EnumTypeDefinition|EnumValueDefinition|FieldDefinition|InputObjectTypeDefinition|InputValueDefinition|InterfaceTypeDefinition|ObjectTypeDefinition|ScalarTypeDefinition|UnionTypeDefinition)(.+)?$':
4846
{
49-
oneOf: [
50-
ruleDef.meta.schema.definitions.asObject,
51-
ruleDef.meta.schema.definitions.asString,
52-
],
47+
oneOf: [schema.definitions.asObject, schema.definitions.asString],
5348
},
5449
};
55-
delete ruleDef.meta.schema.definitions;
50+
delete schema.definitions;
5651

5752
break;
5853
}
@@ -68,8 +63,8 @@ function patchRulesConfig<T extends RuleName>(
6863
export const RELEVANT_RULES = Object.entries(rules)
6964
.filter(
7065
([ruleName, rule]) =>
71-
isRelevantCategory(rule.meta.docs?.category) &&
72-
rule.meta.docs?.graphQLJSRuleName === undefined &&
66+
isRelevantCategory(rule.meta!.docs!.category!) &&
67+
rule.meta!.docs!.graphQLJSRuleName === undefined &&
7368
!SKIPPED_RULES.includes(ruleName as RuleName),
7469
)
7570
.map(

packages/web/app/src/components/organization/billing/Billing.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const BillingView_OrganizationFragment = graphql(`
1717
const BillingView_QueryFragment = graphql(`
1818
fragment BillingView_QueryFragment on Query {
1919
billingPlans {
20+
id
2021
planType
2122
...PlanSummary_PlanFragment
2223
}

packages/web/app/src/components/organization/billing/PlanSummary.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CurrencyFormatter } from './helpers';
66

77
const PriceEstimationTable_PlanFragment = graphql(`
88
fragment PriceEstimationTable_PlanFragment on BillingPlan {
9+
id
910
includedOperationsLimit
1011
pricePerOperationsUnit
1112
basePrice

0 commit comments

Comments
 (0)