@gqloom/core 0.8.4 → 0.9.1

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.
package/README.md CHANGED
@@ -18,14 +18,14 @@ import * as v from "valibot"
18
18
 
19
19
  const helloResolver = resolver({
20
20
  hello: query(v.string())
21
- .input({ name: v.nullish(v.string(), "World") })
22
- .resolve(({ name }) => `Hello, ${name}!`),
21
+ .input({ name: v.nullish(v.string(), "World") })
22
+ .resolve(({ name }) => `Hello, ${name}!`),
23
23
  })
24
24
 
25
25
  export const schema = ValibotWeaver.weave(helloResolver)
26
26
  ```
27
27
 
28
- ## Highlights you should not miss
28
+ ## Highlights
29
29
 
30
30
  - 🧑‍💻 **Development Experience**: Fewer boilerplate codes, semantic API design, and extensive ecosystem integration make development enjoyable.
31
31
  - 🔒 **Type Safety**: Automatically infer types from the Schema, enjoy intelligent code completion during development, and detect potential problems during compilation.
@@ -34,6 +34,19 @@ export const schema = ValibotWeaver.weave(helloResolver)
34
34
  - 🔮 **No Magic**: Without decorators, metadata, reflection, or code generation, it can run anywhere with just JavaScript/TypeScript.
35
35
  - 🧩 **Rich Integration**: Use your most familiar validation libraries and ORMs to build your next GraphQL application.
36
36
 
37
+ ## Installation
38
+
39
+ ```bash
40
+ # use npm
41
+ npm install graphql @gqloom/core
42
+
43
+ # use pnpm
44
+ pnpm add graphql @gqloom/core
45
+
46
+ # use yarn
47
+ yarn add graphql @gqloom/core
48
+ ```
49
+
37
50
  ## Getting Started
38
51
 
39
52
  See [Getting Started](https://gqloom.dev/docs/getting-started) to learn how to use GQLoom.
@@ -0,0 +1,220 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/utils/parse-resolving-fields.ts
8
+ import {
9
+ Kind,
10
+ isObjectType
11
+ } from "graphql";
12
+
13
+ // src/utils/constants.ts
14
+ var DERIVED_DEPENDENCIES = "loom.derived-from-dependencies";
15
+
16
+ // src/utils/type.ts
17
+ import { isListType } from "graphql";
18
+ import { isNonNullType } from "graphql";
19
+ function unwrapType(gqlType) {
20
+ if (isNonNullType(gqlType)) {
21
+ return unwrapType(gqlType.ofType);
22
+ }
23
+ if (isListType(gqlType)) {
24
+ return unwrapType(gqlType.ofType);
25
+ }
26
+ return gqlType;
27
+ }
28
+
29
+ // src/utils/parse-resolving-fields.ts
30
+ function getResolvingFields(payload) {
31
+ const requestedFields = parseResolvingFields(payload.info);
32
+ const derivedFields = /* @__PURE__ */ new Set();
33
+ const derivedDependencies = /* @__PURE__ */ new Set();
34
+ const resolvingObject = unwrapType(payload.info.returnType);
35
+ if (isObjectType(resolvingObject)) {
36
+ const objectFields = resolvingObject.getFields();
37
+ for (const requestedFieldName of requestedFields) {
38
+ const field = objectFields[requestedFieldName];
39
+ if (field) {
40
+ const deps = field.extensions?.[DERIVED_DEPENDENCIES];
41
+ if (deps && Array.isArray(deps) && deps.length > 0) {
42
+ derivedFields.add(requestedFieldName);
43
+ for (const d of deps) derivedDependencies.add(d);
44
+ }
45
+ }
46
+ }
47
+ }
48
+ const selectedFields = new Set(requestedFields);
49
+ for (const f of derivedFields) selectedFields.delete(f);
50
+ for (const d of derivedDependencies) selectedFields.add(d);
51
+ return { requestedFields, derivedFields, derivedDependencies, selectedFields };
52
+ }
53
+ function parseResolvingFields(info, maxDepth = 1) {
54
+ return new ResolvingFieldsParser(info, maxDepth).parse();
55
+ }
56
+ var ResolvingFieldsParser = class {
57
+ /** Store unique field paths */
58
+ fields = /* @__PURE__ */ new Set();
59
+ /** Track visited fragments to prevent circular references */
60
+ visitedFragments = /* @__PURE__ */ new Set();
61
+ /** The GraphQL resolve info object */
62
+ info;
63
+ /** Maximum depth of nested fields to parse */
64
+ maxDepth;
65
+ constructor(info, maxDepth) {
66
+ this.info = info;
67
+ this.maxDepth = maxDepth;
68
+ }
69
+ /**
70
+ * Parses the GraphQL resolve info to extract all requested fields.
71
+ * @returns A Set of field paths
72
+ */
73
+ parse() {
74
+ for (const fieldNode of this.info.fieldNodes) {
75
+ this.collectFields(fieldNode.selectionSet);
76
+ }
77
+ return this.fields;
78
+ }
79
+ /**
80
+ * Recursively collects fields from a selection set.
81
+ * Handles fields, inline fragments, and fragment spreads.
82
+ *
83
+ * @param selectionSet - The selection set to process
84
+ * @param parentPath - The path of the parent field (for nested fields)
85
+ * @param currentDepth - Current depth of recursion
86
+ */
87
+ collectFields(selectionSet, parentPath = "", currentDepth = 0) {
88
+ if (!selectionSet?.selections.length || currentDepth >= this.maxDepth)
89
+ return;
90
+ for (const selection of selectionSet.selections) {
91
+ if (!this.shouldIncludeNode(selection)) continue;
92
+ switch (selection.kind) {
93
+ case Kind.FIELD: {
94
+ const fieldName = selection.name.value;
95
+ const fieldPath = parentPath ? `${parentPath}.${fieldName}` : fieldName;
96
+ this.fields.add(fieldPath);
97
+ const hasSelectionSet = selection.selectionSet != null;
98
+ if (hasSelectionSet) {
99
+ this.collectFields(
100
+ selection.selectionSet,
101
+ fieldPath,
102
+ currentDepth + 1
103
+ );
104
+ }
105
+ break;
106
+ }
107
+ case Kind.INLINE_FRAGMENT: {
108
+ if (selection.selectionSet) {
109
+ this.collectFields(selection.selectionSet, parentPath, currentDepth);
110
+ }
111
+ break;
112
+ }
113
+ case Kind.FRAGMENT_SPREAD: {
114
+ const fragmentName = selection.name.value;
115
+ if (this.visitedFragments.has(fragmentName)) continue;
116
+ this.visitedFragments.add(fragmentName);
117
+ const fragment = this.info.fragments[fragmentName];
118
+ if (fragment) {
119
+ this.collectFields(fragment.selectionSet, parentPath, currentDepth);
120
+ }
121
+ break;
122
+ }
123
+ }
124
+ }
125
+ }
126
+ /**
127
+ * Extracts the boolean value from a directive's 'if' argument.
128
+ * Handles both literal boolean values and variables.
129
+ *
130
+ * @param directive - The directive node to extract value from
131
+ * @returns The boolean value of the directive's condition
132
+ */
133
+ getDirectiveValue(directive) {
134
+ const ifArg = directive.arguments?.find(
135
+ (arg) => arg.name.value === "if"
136
+ );
137
+ if (!ifArg) return true;
138
+ const value = ifArg.value;
139
+ if (value.kind === Kind.BOOLEAN) {
140
+ return value.value;
141
+ }
142
+ if (value.kind === Kind.VARIABLE) {
143
+ const variableName = value.name.value;
144
+ const variableValue = this.info.variableValues?.[variableName];
145
+ return variableValue === true;
146
+ }
147
+ return true;
148
+ }
149
+ /**
150
+ * Determines if a selection node should be included based on its directives.
151
+ * Handles both @include and @skip directives.
152
+ *
153
+ * @param node - The selection node to check
154
+ * @returns Whether the node should be included
155
+ */
156
+ shouldIncludeNode(node) {
157
+ if (!node.directives?.length) return true;
158
+ return node.directives.every((directive) => {
159
+ const isIncludeDirective = directive.name.value === "include";
160
+ if (isIncludeDirective) {
161
+ return this.getDirectiveValue(directive);
162
+ }
163
+ if (directive.name.value === "skip") {
164
+ return !this.getDirectiveValue(directive);
165
+ }
166
+ return true;
167
+ });
168
+ }
169
+ };
170
+
171
+ // src/utils/symbols.ts
172
+ var symbols_exports = {};
173
+ __export(symbols_exports, {
174
+ CONTEXT_MAP_KEY: () => CONTEXT_MAP_KEY,
175
+ FIELD_HIDDEN: () => FIELD_HIDDEN,
176
+ GET_GRAPHQL_TYPE: () => GET_GRAPHQL_TYPE,
177
+ IS_RESOLVER: () => IS_RESOLVER,
178
+ RESOLVER_OPTIONS_KEY: () => RESOLVER_OPTIONS_KEY,
179
+ WEAVER_CONFIG: () => WEAVER_CONFIG
180
+ });
181
+ var GET_GRAPHQL_TYPE = Symbol.for("gqloom.get_graphql_type");
182
+ var WEAVER_CONFIG = Symbol.for("gqloom.weaver_config");
183
+ var RESOLVER_OPTIONS_KEY = Symbol.for("gqloom.resolver-options");
184
+ var IS_RESOLVER = Symbol.for("gqloom.is-resolver");
185
+ var CONTEXT_MAP_KEY = Symbol.for("gqloom.context-map");
186
+ var FIELD_HIDDEN = Symbol.for("gqloom.field-hidden");
187
+
188
+ // src/utils/context.ts
189
+ function onlyMemoization() {
190
+ return { memoization: /* @__PURE__ */ new WeakMap(), isMemoization: true };
191
+ }
192
+ function isOnlyMemoryPayload(payload) {
193
+ return payload.isMemoization === true;
194
+ }
195
+ function getMemoizationMap(payload) {
196
+ if (isOnlyMemoryPayload(payload)) return payload.memoization;
197
+ if (typeof payload.context === "undefined") {
198
+ Object.defineProperty(payload, "context", { value: {} });
199
+ }
200
+ return assignContextMap(payload.context);
201
+ }
202
+ function assignContextMap(target) {
203
+ target[CONTEXT_MAP_KEY] ??= /* @__PURE__ */ new WeakMap();
204
+ return target[CONTEXT_MAP_KEY];
205
+ }
206
+
207
+ export {
208
+ DERIVED_DEPENDENCIES,
209
+ getResolvingFields,
210
+ parseResolvingFields,
211
+ GET_GRAPHQL_TYPE,
212
+ WEAVER_CONFIG,
213
+ IS_RESOLVER,
214
+ FIELD_HIDDEN,
215
+ symbols_exports,
216
+ onlyMemoization,
217
+ isOnlyMemoryPayload,
218
+ getMemoizationMap,
219
+ assignContextMap
220
+ };