@conduit-client/onestore-graphql-parser 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,27 @@
1
1
  import { DocumentNode } from 'graphql/language';
2
+ import { type Result } from '@conduit-client/utils';
3
+ import type { GraphQLResponse } from './types';
2
4
  /**
3
- * Validates a GraphQL config and rejects operations not in the accepted list
4
- * @param config The GraphQL config containing query and operationName
5
- * @param options Options containing acceptedOperations array
6
- * @throws Error if the executable operation is not in acceptedOperations
5
+ * Resolves and validates a GraphQL query AST, handling parsing errors centrally.
6
+ * This function should be used in all GraphQL bindings to ensure consistent error handling.
7
+ *
8
+ * @param query The AST reference to resolve
9
+ * @param operationName Optional operation name for validation
10
+ * @param acceptedOperations Array of accepted operation types (default: ['query'])
11
+ * @returns Object with either:
12
+ * - `error`: GraphQLResponse with errors if parsing/validation failed
13
+ * - `document`: DocumentNode if successful
7
14
  */
8
- export declare function validateGraphQLOperations(config: {
9
- query: DocumentNode;
10
- operationName?: string;
11
- }, options: {
12
- acceptedOperations: ('query' | 'mutation' | 'subscription')[];
13
- }): void;
14
- export declare function resolveAst(ast: any): DocumentNode | undefined;
15
- export declare function wrapConfigAndVerify(config: any, options?: {
15
+ export type ResolveAndValidateOptions = {
16
16
  acceptedOperations?: ('query' | 'mutation' | 'subscription')[];
17
- }): any;
17
+ };
18
+ export type UnverifiedGraphQLConfig = {
19
+ query?: unknown;
20
+ operationName?: string;
21
+ variables?: Record<string, unknown>;
22
+ };
23
+ export type ValidGraphQLConfig<TConfig extends UnverifiedGraphQLConfig = UnverifiedGraphQLConfig> = Omit<TConfig, 'query'> & {
24
+ query: DocumentNode;
25
+ };
26
+ export type ResolveAndValidateConfigResult<TConfig extends UnverifiedGraphQLConfig> = Result<ValidGraphQLConfig<TConfig>, GraphQLResponse> | undefined;
27
+ export declare function resolveAndValidateGraphQLConfig<TConfig extends UnverifiedGraphQLConfig>(config: TConfig, options?: ResolveAndValidateOptions): ResolveAndValidateConfigResult<TConfig>;
@@ -4,25 +4,33 @@
4
4
  * @module gql
5
5
  */
6
6
  import type { DefinitionNode, DocumentNode } from 'graphql/language';
7
- export type AstResolver = (astReference: any) => DocumentNode | undefined;
7
+ import type { GraphQLResponse } from './types';
8
+ export type AstResolution = {
9
+ type: 'document';
10
+ document: DocumentNode;
11
+ } | {
12
+ type: 'error';
13
+ error: GraphQLResponse;
14
+ };
15
+ export type AstResolver = (astReference: unknown) => AstResolution | undefined;
8
16
  /**
9
17
  * we should look into optimizing this before it turns into a memory hog
10
18
  * weakmaps, or limiting the size of the cache, or something
11
19
  */
12
- export declare const docMap: Map<string, DocumentNode>;
20
+ export declare const docMap: Map<string, AstResolution>;
13
21
  /**
14
22
  * Opaque reference map to return keys to userland
15
23
  * As a user shouldn't have access to the Document
16
24
  */
17
- export declare const referenceMap: WeakMap<Object, DocumentNode>;
25
+ export declare const referenceMap: WeakMap<Object, AstResolution>;
18
26
  /**
19
27
  * Returns document node if cached or else update the cache and return the document node
20
28
  * @param inputString - operation string
21
- * @returns DocumentNode
29
+ * @returns DocumentNode or GraphQLResponse with errors if parsing fails
22
30
  */
23
- export declare function parseDocument(inputString: string): DocumentNode | null;
24
- export declare function updateReferenceMapWithKnownKey(doc: DocumentNode, key: object): void;
25
- export declare function updateReferenceMapAndGetKey(doc: DocumentNode): object;
31
+ export declare function parseDocument(inputString: string): AstResolution | null;
32
+ export declare function updateReferenceMapWithKnownKey(doc: AstResolution, key: object): void;
33
+ export declare function updateReferenceMapAndGetKey(doc: AstResolution): object;
26
34
  /**
27
35
  * Insert string and fragment substitutions with the actual nodes
28
36
  * @param inputString
@@ -2,6 +2,8 @@ export type { GraphQLObjectType, GraphQLInterfaceType, GraphQLDirective, GraphQL
2
2
  export type { ASTNode, ObjectValueNode, ListTypeNode, BooleanValueNode, EnumTypeDefinitionNode, FieldDefinitionNode, FloatValueNode, InterfaceTypeDefinitionNode, IntValueNode, NamedTypeNode, ObjectTypeDefinitionNode, StringValueNode, TypeNode, UnionTypeDefinitionNode, DocumentNode, OperationDefinitionNode, FieldNode, ArgumentNode, ValueNode, SelectionNode, SelectionSetNode, FragmentDefinitionNode, DirectiveNode, ObjectFieldNode, ScalarTypeDefinitionNode, InputObjectTypeDefinitionNode, InlineFragmentNode, FragmentSpreadNode, VariableDefinitionNode, ListValueNode, VariableNode, NullValueNode, } from 'graphql/language';
3
3
  export { Kind } from 'graphql/language';
4
4
  export { gql, astResolver } from './gql';
5
- export type { AstResolver } from './gql';
5
+ export type { AstResolver, AstResolution } from './gql';
6
6
  export { parse, print, visit } from 'graphql/language';
7
- export { validateGraphQLOperations, resolveAst, wrapConfigAndVerify } from './bindings-utils';
7
+ export type { ResolveAndValidateOptions, UnverifiedGraphQLConfig, ValidGraphQLConfig, } from './bindings-utils';
8
+ export { resolveAndValidateGraphQLConfig } from './bindings-utils';
9
+ export type { GraphQLResponse, GraphQLData } from './types';
@@ -0,0 +1,15 @@
1
+ export interface GraphQLErrorShape {
2
+ message: string;
3
+ locations?: ReadonlyArray<{
4
+ line: number;
5
+ column: number;
6
+ }>;
7
+ path?: ReadonlyArray<string | number>;
8
+ extensions?: Record<string, any>;
9
+ }
10
+ export interface GraphQLResponse<TData = Record<string, any>> {
11
+ data?: TData | null;
12
+ errors?: ReadonlyArray<GraphQLErrorShape>;
13
+ extensions?: Record<string, any>;
14
+ }
15
+ export type GraphQLData = Record<string, any>;
package/dist/v1/index.js CHANGED
@@ -3066,20 +3066,37 @@ function operationKeyBuilder(inputString) {
3066
3066
  return stripIgnoredCharacters(inputString);
3067
3067
  }
3068
3068
  function parseDocument(inputString) {
3069
+ var _a;
3069
3070
  const operationKey = operationKeyBuilder(inputString);
3070
3071
  const cachedDoc = docMap.get(operationKey);
3071
3072
  if (cachedDoc !== void 0) {
3072
3073
  return cachedDoc;
3073
3074
  }
3074
- const parsedDoc = parse(inputString, { noLocation: true });
3075
- if (!parsedDoc || parsedDoc.kind !== "Document") {
3076
- if (process.env.NODE_ENV !== "production") {
3077
- throw new Error("Invalid graphql doc");
3075
+ try {
3076
+ const parsedDoc = parse(inputString, { noLocation: true });
3077
+ const resolvedDoc = { type: "document", document: parsedDoc };
3078
+ docMap.set(operationKey, resolvedDoc);
3079
+ return resolvedDoc;
3080
+ } catch (e) {
3081
+ if (e instanceof GraphQLError) {
3082
+ const errorDoc = {
3083
+ errors: [
3084
+ {
3085
+ message: e.message || "Failed to parse GraphQL document",
3086
+ locations: (_a = e.locations) == null ? void 0 : _a.map((loc) => ({
3087
+ line: loc.line,
3088
+ column: loc.column
3089
+ })),
3090
+ extensions: e.extensions
3091
+ }
3092
+ ]
3093
+ };
3094
+ const resolvedError = { type: "error", error: errorDoc };
3095
+ docMap.set(operationKey, resolvedError);
3096
+ return resolvedError;
3078
3097
  }
3079
- return null;
3098
+ throw e;
3080
3099
  }
3081
- docMap.set(operationKey, parsedDoc);
3082
- return parsedDoc;
3083
3100
  }
3084
3101
  function insertFragments(doc, fragments) {
3085
3102
  fragments.forEach((fragment) => {
@@ -3105,15 +3122,17 @@ function processSubstitutions(inputString, substitutions) {
3105
3122
  if (typeof substitution === "string" || typeof substitution === "number") {
3106
3123
  outputString += substitution;
3107
3124
  } else if (typeof substitution === "object") {
3108
- const doc = referenceMap.get(substitution);
3109
- if (doc === void 0) {
3125
+ const resolved = referenceMap.get(substitution);
3126
+ if (resolved === void 0) {
3110
3127
  if (process.env.NODE_ENV !== "production") {
3111
3128
  throw new Error("Invalid substitution fragment");
3112
3129
  }
3113
3130
  return null;
3114
3131
  }
3115
- for (const def of doc.definitions) {
3116
- fragments.push(def);
3132
+ if (resolved.type === "document") {
3133
+ for (const def of resolved.document.definitions) {
3134
+ fragments.push(def);
3135
+ }
3117
3136
  }
3118
3137
  } else {
3119
3138
  if (process.env.NODE_ENV !== "production") {
@@ -3128,6 +3147,9 @@ function processSubstitutions(inputString, substitutions) {
3128
3147
  };
3129
3148
  }
3130
3149
  const astResolver = function(astReference) {
3150
+ if (typeof astReference !== "object" || astReference === null) {
3151
+ return void 0;
3152
+ }
3131
3153
  return referenceMap.get(astReference);
3132
3154
  };
3133
3155
  function gql(literals, ...subs) {
@@ -3160,11 +3182,47 @@ function gql(literals, ...subs) {
3160
3182
  if (document === null) {
3161
3183
  return null;
3162
3184
  }
3163
- if (inputSubstitutionFragments.length === 0) {
3185
+ if (document.type === "error") {
3164
3186
  return updateReferenceMapAndGetKey(document);
3165
3187
  }
3166
- return updateReferenceMapAndGetKey(insertFragments(document, inputSubstitutionFragments));
3188
+ const docNode = document.document;
3189
+ if (inputSubstitutionFragments.length === 0) {
3190
+ return updateReferenceMapAndGetKey({ type: "document", document: docNode });
3191
+ }
3192
+ return updateReferenceMapAndGetKey({
3193
+ type: "document",
3194
+ document: insertFragments(docNode, inputSubstitutionFragments)
3195
+ });
3196
+ }
3197
+ /*!
3198
+ * Copyright (c) 2022, Salesforce, Inc.,
3199
+ * All rights reserved.
3200
+ * For full license text, see the LICENSE.txt file
3201
+ */
3202
+ class Ok {
3203
+ constructor(value) {
3204
+ this.value = value;
3205
+ }
3206
+ isOk() {
3207
+ return true;
3208
+ }
3209
+ isErr() {
3210
+ return !this.isOk();
3211
+ }
3212
+ }
3213
+ class Err {
3214
+ constructor(error) {
3215
+ this.error = error;
3216
+ }
3217
+ isOk() {
3218
+ return false;
3219
+ }
3220
+ isErr() {
3221
+ return !this.isOk();
3222
+ }
3167
3223
  }
3224
+ const ok = (value) => new Ok(value);
3225
+ const err = (err2) => new Err(err2);
3168
3226
  function findExecutableOperation(document, operationName) {
3169
3227
  const operations = document.definitions.filter(
3170
3228
  (def) => def.kind === Kind.OPERATION_DEFINITION
@@ -3197,25 +3255,40 @@ function validateGraphQLOperations(config, options) {
3197
3255
  }
3198
3256
  function resolveAst(ast) {
3199
3257
  if (ast === null || ast === void 0) {
3200
- return;
3258
+ return void 0;
3201
3259
  }
3202
- const result = astResolver(ast);
3203
- if (result === void 0) {
3204
- throw new Error("Could not resolve AST. Did you parse the query with gql?");
3260
+ return astResolver(ast);
3261
+ }
3262
+ function resolveAndValidateGraphQLConfig(config, options) {
3263
+ const query = config.query;
3264
+ if (query === null || query === void 0) {
3265
+ return void 0;
3205
3266
  }
3206
- return result;
3267
+ const result = resolveAndValidateGraphQLDocument(query, config.operationName, options);
3268
+ if (result.isErr()) {
3269
+ return err(result.error);
3270
+ }
3271
+ return ok({
3272
+ ...config,
3273
+ query: result.value
3274
+ });
3207
3275
  }
3208
- function wrapConfigAndVerify(config, options) {
3209
- if (config == null ? void 0 : config.query) {
3210
- config = { ...config, query: resolveAst(config.query) };
3211
- if (config.query === void 0) {
3212
- throw new Error("Internal error in GraphQL adapter occurred: Unable to resolve query");
3213
- }
3214
- validateGraphQLOperations(config, {
3215
- acceptedOperations: (options == null ? void 0 : options.acceptedOperations) ?? ["query"]
3216
- });
3276
+ function resolveAndValidateGraphQLDocument(query, operationName, options) {
3277
+ const resolved = resolveAst(query);
3278
+ if (resolved === void 0) {
3279
+ throw new Error("Could not resolve AST. Did you parse the query with gql?");
3280
+ }
3281
+ if (resolved.type === "error") {
3282
+ return err(resolved.error);
3217
3283
  }
3218
- return config;
3284
+ const document = resolved.document;
3285
+ validateGraphQLOperations(
3286
+ { query: document, operationName },
3287
+ {
3288
+ acceptedOperations: (options == null ? void 0 : options.acceptedOperations) ?? ["query"]
3289
+ }
3290
+ );
3291
+ return ok(document);
3219
3292
  }
3220
3293
  export {
3221
3294
  Kind,
@@ -3223,9 +3296,7 @@ export {
3223
3296
  gql,
3224
3297
  parse,
3225
3298
  print,
3226
- resolveAst,
3227
- validateGraphQLOperations,
3228
- visit,
3229
- wrapConfigAndVerify
3299
+ resolveAndValidateGraphQLConfig,
3300
+ visit
3230
3301
  };
3231
3302
  //# sourceMappingURL=index.js.map