@graphql-inspector/cli
Version:
Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.
171 lines (170 loc) • 5.87 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFileLoader = createFileLoader;
exports.createConfigLoader = createConfigLoader;
exports.printSchemaFromEndpoint = printSchemaFromEndpoint;
exports.loadSources = loadSources;
const tslib_1 = require("tslib");
const dataloader_1 = tslib_1.__importDefault(require("dataloader"));
const graphql_1 = require("graphql");
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
const fetch_1 = require("@whatwg-node/fetch");
const utils_js_1 = require("./utils.js");
function createGetFilesQuery(variableMap) {
const variables = Object.keys(variableMap)
.map(name => `$${name}: String!`)
.join(', ');
const files = Object.keys(variableMap)
.map(name => {
return `
${name}: object(expression: $${name}) {
... on Blob {
text
}
}
`;
})
.join('\n');
return /* GraphQL */ `
query GetFile($repo: String!, $owner: String!, ${variables}) {
repository(name: $repo, owner: $owner) {
${files}
}
}
`.replace(/\s+/g, ' ');
}
function createFileLoader(config) {
const loader = new dataloader_1.default(async (inputs) => {
const variablesMap = (0, utils_js_1.objectFromEntries)(inputs.map(input => [input.alias, `${input.ref}:${input.path}`]));
const { context, repo, owner } = config;
const result = await context.octokit.graphql(createGetFilesQuery(variablesMap), {
repo,
owner,
...variablesMap,
});
return Promise.all(inputs.map(async (input) => {
const alias = input.alias;
try {
if (!result) {
throw new Error(`No result :(`);
}
if (result.data) {
return result.data.repository[alias].text;
}
return result.repository[alias].text;
}
catch (error) {
const failure = new Error(`Failed to load '${input.path}' (ref: ${input.ref})`);
if (input.throwNotFound === false) {
if (input.onError) {
input.onError(failure);
}
else {
console.error(failure);
}
return null;
}
throw failure;
}
}));
}, {
batch: true,
maxBatchSize: 5,
cacheKeyFn(obj) {
return `${obj.ref} - ${obj.path}`;
},
});
return input => loader.load(input);
}
function createConfigLoader(config, loadFile) {
const loader = new dataloader_1.default(ids => {
const errors = [];
const onError = (error) => {
errors.push(error);
};
return Promise.all(ids.map(async (id) => {
const [yamlConfig, ymlConfig, pkgFile] = await Promise.all([
loadFile({
...config,
alias: 'yaml',
path: `.github/${id}.yaml`,
throwNotFound: false,
onError,
}),
loadFile({
...config,
alias: 'yml',
path: `.github/${id}.yml`,
throwNotFound: false,
onError,
}),
loadFile({
...config,
alias: 'pkg',
path: 'package.json',
throwNotFound: false,
onError,
}),
]);
if (yamlConfig || ymlConfig) {
return js_yaml_1.default.load((yamlConfig || ymlConfig));
}
if (pkgFile) {
try {
const pkg = JSON.parse(pkgFile);
if (pkg[id]) {
return pkg[id];
}
}
catch (error) {
errors.push(error);
}
}
console.error([`Failed to load config:`, ...errors].join('\n'));
return null;
}));
}, {
batch: false,
});
return () => loader.load('graphql-inspector');
}
async function printSchemaFromEndpoint(endpoint) {
const config = (0, utils_js_1.parseEndpoint)(endpoint);
const response = await (0, fetch_1.fetch)(config.url, {
method: config.method,
headers: config.headers,
body: JSON.stringify({
query: (0, graphql_1.getIntrospectionQuery)().replace(/\s+/g, ' ').trim(),
}),
});
const { data } = await response.json();
const introspection = data;
return (0, graphql_1.printSchema)((0, graphql_1.buildClientSchema)(introspection, {
assumeValid: true,
}));
}
async function loadSources({ config, oldPointer, newPointer, loadFile, }) {
// Here, config.endpoint is defined only if target's branch matches branch of environment
// otherwise it's empty
const useEndpoint = !(0, utils_js_1.isNil)(config.endpoint);
const [oldFile, newFile] = await Promise.all([
useEndpoint
? printSchemaFromEndpoint(config.endpoint)
: loadFile({
...oldPointer,
alias: 'oldSource',
}),
loadFile({
...newPointer,
alias: 'newSource',
}),
]);
return {
old: new graphql_1.Source(oldFile, useEndpoint
? typeof config.endpoint === 'string'
? config.endpoint
: config.endpoint?.url
: `${oldPointer.ref}:${oldPointer.path}`),
new: new graphql_1.Source(newFile, `${newPointer.ref}:${newPointer.path}`),
};
}
;