Skip to content

Commit

Permalink
Improve errors diagnostics, narrowing to related words only (#39)
Browse files Browse the repository at this point in the history
* improve errors diagnostics, narrowing to related words only

* improve error diagnostics related to schemas

* upgrade to 1.4.2
  • Loading branch information
Chnapy committed Sep 12, 2022
1 parent 0d57c8b commit cc394b5
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 14 deletions.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "ts-gql-plugin",
"version": "1.4.1",
"version": "1.4.2",
"packageManager": "yarn@3.2.1",
"license": "MIT",
"main": "./dist/index.js",
Expand Down
4 changes: 3 additions & 1 deletion src/cached/cached-literal-parser.ts
Expand Up @@ -45,7 +45,9 @@ export const createCachedLiteralParser = ({
projectName,
});
if (!project) {
throw new Error(`Project not defined for name "${projectName}"`);
throw new Error(
`Project not defined for name "${projectName}", or there is an issue on schema file`
);
}

return { ...project, projectName };
Expand Down
49 changes: 38 additions & 11 deletions src/create-error-catcher.ts
@@ -1,6 +1,8 @@
import { GraphQLError } from 'graphql';
import ts from 'typescript';
import { Logger } from './utils/logger';
import { getCurrentWord } from './utils/get-current-word';
import { isVSCodeEnv } from './utils/is-vscode-env';
import { Logger } from './utils/logger';

export type ErrorCatcher = (
err: unknown,
Expand All @@ -9,6 +11,8 @@ export type ErrorCatcher = (
length?: number
) => null;

const unknownFileName = '';

export const createErrorCatcher = (
pluginsDiagnostics: Map<string, ts.Diagnostic[]>,
logger: Logger
Expand All @@ -25,12 +29,6 @@ export const createErrorCatcher = (
return null;
}

if (!sourceFile && !vsCodeEnv) {
logger.error(err);

throw new Error('Internal error - check previous logs.');
}

if (err instanceof AggregateError) {
err.errors.forEach((gqlErr) =>
errorCatcher(gqlErr, sourceFile, start, length)
Expand All @@ -42,20 +40,49 @@ export const createErrorCatcher = (
logger.error(err);
}

if (sourceFile) {
const gqlDiagnostics = pluginsDiagnostics.get(sourceFile.fileName) ?? [];
const addNewDiagnosticError = (file: ts.SourceFile | undefined) => {
const fileName = file?.fileName ?? unknownFileName;
const gqlDiagnostics = pluginsDiagnostics.get(fileName) ?? [];

pluginsDiagnostics.set(sourceFile.fileName, [
pluginsDiagnostics.set(fileName, [
...gqlDiagnostics,
{
category: ts.DiagnosticCategory.Error,
code: 0,
file: sourceFile,
file,
start,
length,
messageText: err.message,
},
]);
};

if (err instanceof GraphQLError) {
const errorLocation = err.nodes?.[0]?.loc;
const position = err.positions?.[0];

const text = sourceFile?.text ?? err.source?.body;

if (errorLocation) {
start += errorLocation.start;
length = errorLocation.end - errorLocation.start;
} else if (position && text) {
start += position;
length = getCurrentWord(text, start).length;
}
}

if (sourceFile) {
addNewDiagnosticError(sourceFile);
} else if (err instanceof GraphQLError) {
const source = err.source;

const fileName = source?.name ?? unknownFileName;
const file = source && ts.createSourceFile(fileName, source.body, 99);

addNewDiagnosticError(file);
} else {
addNewDiagnosticError(undefined);
}

return null;
Expand Down
22 changes: 21 additions & 1 deletion src/generators/generate-type-from-literal.ts
@@ -1,6 +1,6 @@
import { codegen } from '@graphql-codegen/core';
import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations';
import { DocumentNode, parse } from 'graphql';
import { DocumentNode, GraphQLError, parse } from 'graphql';
import { DocumentInfos } from './generate-bottom-content';

type CodegenPlugin = typeof plugins[number];
Expand All @@ -27,6 +27,8 @@ export const generateTypeFromLiteral = async (
...codegenConfig,
};

const codegenErrors: GraphQLError[] = [];

const staticTypes = await codegen({
schema,
documents: [
Expand All @@ -41,6 +43,24 @@ export const generateTypeFromLiteral = async (
[i + 1]: {},
})),
pluginMap,
profiler: {
collect: () => [],
run: async (fn) => {
const value = await fn();

if (Array.isArray(value)) {
codegenErrors.push(...value.flatMap((val) => val.errors ?? []));
}

return value;
},
},
}).catch(async (error) => {
if (codegenErrors.length === 0) {
throw error;
}

throw new AggregateError(codegenErrors, 'Codegen errors');
});

const typeRegex = /\s=\s(.*?);\n$/gms;
Expand Down
11 changes: 11 additions & 0 deletions src/utils/get-current-word.ts
@@ -0,0 +1,11 @@
const spaceRelatedChars = new Set([' ', '\n', '\t']);

export const getCurrentWord = (text: string, start: number): string => {
const currentChar = text[start];

if (spaceRelatedChars.has(currentChar)) {
return '';
}

return currentChar + getCurrentWord(text, start + 1);
};

1 comment on commit cc394b5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"with ts-gql-plugin" vs "without ts-gql-plugin" Benchmark

Benchmark suite Current: cc394b5 Previous: 0d57c8b Ratio
performance impact %: "with ts-gql-plugin" vs "without ts-gql-plugin" 23.02 % (±1.23%) 24.29 % (±2.19%) 1.06

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.