-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a script that determines wheter a deprecated field is used …
…or not
- Loading branch information
Showing
7 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env node | ||
|
||
var path = require('path'); | ||
require(path.resolve(__dirname, '../lib/cli/check-deprecated.js')).run(process.argv); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export declare function run(argv: string[]): Promise<void>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.run = void 0; | ||
const promises_1 = __importDefault(require("fs/promises")); | ||
const graphql_1 = require("graphql"); | ||
const common_1 = require("./common"); | ||
function isDeprecated(directives) { | ||
for (const directive of directives || []) { | ||
if (directive.name.value === 'deprecated') { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
async function check(schema_file, query_list_file) { | ||
const schema = (0, graphql_1.buildSchema)(await promises_1.default.readFile(schema_file, 'utf-8')); | ||
const query_list = (0, common_1.extractQueryList)(await promises_1.default.readFile(query_list_file, 'utf-8')); | ||
for (const query of query_list) { | ||
if (!query) { | ||
continue; | ||
} | ||
const parsed_query = (0, graphql_1.parse)(query); | ||
const type_info = new graphql_1.TypeInfo(schema); | ||
const visitor = { | ||
enter(node) { | ||
if (node.kind === graphql_1.Kind.FIELD) { | ||
const type = type_info.getParentType(); | ||
const field = type_info.getFieldDef(); | ||
if (type && field) { | ||
const is_field_deprecated = isDeprecated(field.astNode?.directives); | ||
if (is_field_deprecated) { | ||
console.log(`${type.name}.${field.name} is deprecated`); | ||
} | ||
if (node.arguments) { | ||
for (const argument of node.arguments) { | ||
const field_arg = field.args.find((arg) => arg.name === argument.name.value); | ||
if (field_arg) { | ||
const is_arg_deprecated = isDeprecated(field_arg.astNode?.directives); | ||
if (is_arg_deprecated) { | ||
console.log(`${type.name}.${field.name}(${field_arg.name}) is deprecated`); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
}; | ||
(0, graphql_1.visit)(parsed_query, (0, graphql_1.visitWithTypeInfo)(type_info, visitor)); | ||
} | ||
return schema; | ||
} | ||
async function run(argv) { | ||
if (argv.length < 4) { | ||
throw new Error('Usage: check-deprecated <schema file> <query list> [type or field]'); | ||
} | ||
const schema_file = argv[2]; | ||
const query_list_file = argv[3]; | ||
await check(schema_file, query_list_file); | ||
} | ||
exports.run = run; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export declare function extractQueryList(text: string): string[]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.extractQueryList = void 0; | ||
function extractQueryList(text) { | ||
return text | ||
.split('\n') | ||
.map((str) => str | ||
.trim() | ||
.replace(/^query /, '✓query ') | ||
.replace(/^mutation /, '✓mutation ') | ||
.replace(/^fragment /, '✓fragment ')) | ||
.join(' ') | ||
.replace(/✓mutation /g, '\nmutation ') | ||
.replace(/✓query /g, '\nquery ') | ||
.replace(/✓fragment /g, '\nfragment ') | ||
.trim() | ||
.split('\n'); | ||
} | ||
exports.extractQueryList = extractQueryList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import fs from 'fs/promises'; | ||
import { ASTVisitor, buildSchema, ConstDirectiveNode, Kind, parse, TypeInfo, visit, visitWithTypeInfo } from 'graphql'; | ||
import { extractQueryList } from './common'; | ||
|
||
function isDeprecated(directives: readonly ConstDirectiveNode[] | undefined) { | ||
for (const directive of directives || []) { | ||
if (directive.name.value === 'deprecated') { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
async function check(schema_file: string, query_list_file: string) { | ||
const schema = buildSchema(await fs.readFile(schema_file, 'utf-8')); | ||
const query_list = extractQueryList(await fs.readFile(query_list_file, 'utf-8')); | ||
for (const query of query_list) { | ||
if (!query) { | ||
continue; | ||
} | ||
const parsed_query = parse(query); | ||
const type_info = new TypeInfo(schema); | ||
const visitor: ASTVisitor = { | ||
enter(node) { | ||
if (node.kind === Kind.FIELD) { | ||
const type = type_info.getParentType(); | ||
const field = type_info.getFieldDef(); | ||
if (type && field) { | ||
const is_field_deprecated = isDeprecated(field.astNode?.directives); | ||
if (is_field_deprecated) { | ||
console.log(`${type.name}.${field.name} is deprecated`); | ||
} | ||
if (node.arguments) { | ||
for (const argument of node.arguments) { | ||
const field_arg = field.args.find((arg) => arg.name === argument.name.value); | ||
if (field_arg) { | ||
const is_arg_deprecated = isDeprecated(field_arg.astNode?.directives); | ||
if (is_arg_deprecated) { | ||
console.log(`${type.name}.${field.name}(${field_arg.name}) is deprecated`); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
}; | ||
visit(parsed_query, visitWithTypeInfo(type_info, visitor)); | ||
} | ||
return schema; | ||
} | ||
|
||
export async function run(argv: string[]) { | ||
if (argv.length < 4) { | ||
throw new Error('Usage: check-deprecated <schema file> <query list> [type or field]'); | ||
} | ||
const schema_file = argv[2]; | ||
const query_list_file = argv[3]; | ||
|
||
await check(schema_file, query_list_file); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export function extractQueryList(text: string) { | ||
return text | ||
.split('\n') | ||
.map((str) => | ||
str | ||
.trim() | ||
.replace(/^query /, '✓query ') | ||
.replace(/^mutation /, '✓mutation ') | ||
.replace(/^fragment /, '✓fragment '), | ||
) | ||
.join(' ') | ||
.replace(/✓mutation /g, '\nmutation ') | ||
.replace(/✓query /g, '\nquery ') | ||
.replace(/✓fragment /g, '\nfragment ') | ||
.trim() | ||
.split('\n'); | ||
} |