houdini 0.12.0-alpha.0 → 0.12.4
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 +59 -9
- package/build/cmd/generate.js +8 -4
- package/build/cmd/generators/artifacts/selection.js +1 -1
- package/build/cmd/generators/typescript/index.js +4 -1
- package/build/cmd/transforms/composeQueries.d.ts +0 -7
- package/build/cmd/transforms/composeQueries.js +2 -3
- package/build/cmd/transforms/fragmentVariables.d.ts +16 -0
- package/build/cmd/transforms/fragmentVariables.js +61 -44
- package/build/cmd/transforms/list.js +1 -23
- package/build/cmd/transforms/paginate.d.ts +0 -34
- package/build/cmd/transforms/paginate.js +2 -3
- package/build/cmd/validators/typeCheck.js +52 -1
- package/build/cmd.js +855 -803
- package/build/runtime/cache/cache.d.ts +45 -76
- package/build/runtime/cache/cache.js +755 -400
- package/build/runtime/cache/{lists.d.ts → list.d.ts} +17 -28
- package/build/{runtime-cjs/cache/lists.js → runtime/cache/list.js} +71 -152
- package/build/runtime/cache/record.d.ts +40 -0
- package/build/runtime/cache/record.js +342 -0
- package/build/runtime/fragment.js +42 -64
- package/build/runtime/index.d.ts +0 -1
- package/build/runtime/index.js +0 -1
- package/build/runtime/mutation.js +1 -1
- package/build/runtime/network.d.ts +14 -6
- package/build/runtime/network.js +43 -26
- package/build/runtime/pagination.js +1 -3
- package/build/runtime/query.js +3 -5
- package/build/runtime/scalars.js +15 -3
- package/build/runtime/types.d.ts +0 -2
- package/build/runtime-cjs/cache/cache.d.ts +45 -76
- package/build/runtime-cjs/cache/cache.js +755 -400
- package/build/runtime-cjs/cache/{lists.d.ts → list.d.ts} +17 -28
- package/build/{runtime/cache/lists.js → runtime-cjs/cache/list.js} +71 -152
- package/build/runtime-cjs/cache/record.d.ts +40 -0
- package/build/runtime-cjs/cache/record.js +342 -0
- package/build/runtime-cjs/fragment.js +42 -64
- package/build/runtime-cjs/index.d.ts +0 -1
- package/build/runtime-cjs/index.js +0 -1
- package/build/runtime-cjs/mutation.js +1 -1
- package/build/runtime-cjs/network.d.ts +14 -6
- package/build/runtime-cjs/network.js +43 -26
- package/build/runtime-cjs/pagination.js +1 -3
- package/build/runtime-cjs/query.js +3 -5
- package/build/runtime-cjs/scalars.js +15 -3
- package/build/runtime-cjs/types.d.ts +0 -2
- package/build/runtime-esm/cache/cache.d.ts +45 -76
- package/build/runtime-esm/cache/cache.js +512 -310
- package/build/runtime-esm/fragment.js +40 -65
- package/build/runtime-esm/index.d.ts +0 -1
- package/build/runtime-esm/index.js +0 -1
- package/build/runtime-esm/mutation.js +1 -1
- package/build/runtime-esm/network.d.ts +14 -6
- package/build/runtime-esm/network.js +29 -13
- package/build/runtime-esm/pagination.js +1 -3
- package/build/runtime-esm/query.js +3 -5
- package/build/runtime-esm/scalars.js +15 -3
- package/build/runtime-esm/types.d.ts +0 -2
- package/cmd/generate.ts +9 -5
- package/cmd/generators/artifacts/selection.ts +3 -1
- package/cmd/generators/typescript/index.ts +6 -1
- package/cmd/generators/typescript/typescript.test.ts +14 -14
- package/cmd/transforms/composeQueries.ts +3 -3
- package/cmd/transforms/fragmentVariables.test.ts +9 -9
- package/cmd/transforms/fragmentVariables.ts +72 -55
- package/cmd/transforms/list.ts +1 -43
- package/cmd/transforms/lists.test.ts +1 -68
- package/cmd/transforms/paginate.ts +1 -1
- package/cmd/validators/typeCheck.test.ts +18 -2
- package/cmd/validators/typeCheck.ts +57 -1
- package/package.json +3 -3
- package/runtime/cache/cache.ts +670 -420
- package/runtime/cache/{lists.ts → list.ts} +47 -124
- package/runtime/cache/record.ts +255 -0
- package/runtime/cache/tests/{subscriptions.test.ts → cache.test.ts} +266 -203
- package/runtime/cache/tests/gc.test.ts +18 -63
- package/runtime/cache/tests/list.test.ts +153 -193
- package/runtime/cache/tests/{availability.test.ts → policy.test.ts} +8 -9
- package/runtime/cache/tests/scalars.test.ts +5 -5
- package/runtime/fragment.ts +41 -74
- package/runtime/index.ts +0 -1
- package/runtime/mutation.ts +1 -1
- package/runtime/network.ts +63 -26
- package/runtime/pagination.ts +1 -6
- package/runtime/query.ts +6 -5
- package/runtime/scalars.test.ts +130 -0
- package/runtime/scalars.ts +17 -3
- package/runtime/types.ts +0 -2
- package/build/runtime/cache/gc.d.ts +0 -9
- package/build/runtime/cache/gc.js +0 -96
- package/build/runtime/cache/storage.d.ts +0 -86
- package/build/runtime/cache/storage.js +0 -535
- package/build/runtime/cache/stuff.d.ts +0 -6
- package/build/runtime/cache/stuff.js +0 -98
- package/build/runtime/cache/subscription.d.ts +0 -29
- package/build/runtime/cache/subscription.js +0 -384
- package/build/runtime/proxy.d.ts +0 -6
- package/build/runtime/proxy.js +0 -52
- package/build/runtime-cjs/cache/gc.d.ts +0 -9
- package/build/runtime-cjs/cache/gc.js +0 -96
- package/build/runtime-cjs/cache/storage.d.ts +0 -86
- package/build/runtime-cjs/cache/storage.js +0 -535
- package/build/runtime-cjs/cache/stuff.d.ts +0 -6
- package/build/runtime-cjs/cache/stuff.js +0 -98
- package/build/runtime-cjs/cache/subscription.d.ts +0 -29
- package/build/runtime-cjs/cache/subscription.js +0 -384
- package/build/runtime-cjs/proxy.d.ts +0 -6
- package/build/runtime-cjs/proxy.js +0 -52
- package/build/runtime-esm/cache/gc.d.ts +0 -9
- package/build/runtime-esm/cache/gc.js +0 -38
- package/build/runtime-esm/cache/lists.d.ts +0 -46
- package/build/runtime-esm/cache/lists.js +0 -259
- package/build/runtime-esm/cache/storage.d.ts +0 -86
- package/build/runtime-esm/cache/storage.js +0 -370
- package/build/runtime-esm/cache/stuff.d.ts +0 -6
- package/build/runtime-esm/cache/stuff.js +0 -59
- package/build/runtime-esm/cache/subscription.d.ts +0 -29
- package/build/runtime-esm/cache/subscription.js +0 -217
- package/build/runtime-esm/proxy.d.ts +0 -6
- package/build/runtime-esm/proxy.js +0 -25
- package/runtime/cache/gc.ts +0 -53
- package/runtime/cache/storage.ts +0 -489
- package/runtime/cache/stuff.ts +0 -77
- package/runtime/cache/subscription.ts +0 -300
- package/runtime/cache/tests/keys.test.ts +0 -34
- package/runtime/cache/tests/storage.test.ts +0 -383
- package/runtime/proxy.ts +0 -28
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ for the generation of an incredibly lean GraphQL abstraction for your applicatio
|
|
|
42
42
|
1. [Fetching Data](#fetching-data)
|
|
43
43
|
1. [Query variables and page data](#query-variables-and-page-data)
|
|
44
44
|
1. [Loading State](#loading-state)
|
|
45
|
-
1. [
|
|
45
|
+
1. [Hooks](#load-hooks)
|
|
46
46
|
1. [Refetching Data](#refetching-data)
|
|
47
47
|
1. [Cache policy](#cache-policy)
|
|
48
48
|
1. [Data Retention](#data-retention)
|
|
@@ -69,7 +69,7 @@ for the generation of an incredibly lean GraphQL abstraction for your applicatio
|
|
|
69
69
|
1. [Persisted Queries](#persisted-queries)
|
|
70
70
|
1. [Notes, Constraints, and Conventions](#%EF%B8%8Fnotes-constraints-and-conventions)
|
|
71
71
|
|
|
72
|
-
##
|
|
72
|
+
## 🕹 Example
|
|
73
73
|
|
|
74
74
|
A demo can be found in the <a href='./example'>example directory</a>.
|
|
75
75
|
|
|
@@ -123,7 +123,12 @@ import houdini from 'houdini-preprocess'
|
|
|
123
123
|
alias: {
|
|
124
124
|
$houdini: path.resolve('.', '$houdini')
|
|
125
125
|
}
|
|
126
|
-
}
|
|
126
|
+
},
|
|
127
|
+
server: {
|
|
128
|
+
fs: {
|
|
129
|
+
allow: ['.'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
127
132
|
}
|
|
128
133
|
}
|
|
129
134
|
}
|
|
@@ -327,23 +332,30 @@ the result of query:
|
|
|
327
332
|
{/if}
|
|
328
333
|
```
|
|
329
334
|
|
|
330
|
-
###
|
|
335
|
+
### Load Hooks
|
|
331
336
|
|
|
332
337
|
Sometimes you will need to add additional logic to a component's query. For example, you might want to
|
|
333
338
|
check if the current session is valid before a query is sent to the server. In order to support this,
|
|
334
|
-
houdini will look for
|
|
335
|
-
any logic you need.
|
|
339
|
+
houdini will look for hook functions defined in the module context which can be used to perform
|
|
340
|
+
any logic you need.
|
|
341
|
+
|
|
342
|
+
#### `beforeLoad`
|
|
343
|
+
|
|
344
|
+
Called before Houdini executes load queries against the server. You can expect the same
|
|
345
|
+
arguments as SvelteKit's [`load`](https://kit.svelte.dev/docs#loading) hook.
|
|
346
|
+
|
|
347
|
+
If you return a value from this function, it will be passed as props to your component.
|
|
336
348
|
|
|
337
349
|
```svelte
|
|
338
350
|
<script context="module">
|
|
339
351
|
// It has access to the same arguments and this.error this.redirect as the variable functions
|
|
340
|
-
export function
|
|
352
|
+
export function beforeLoad({page, session}){
|
|
341
353
|
if(!session.authenticated){
|
|
342
354
|
return this.redirect(302, '/login')
|
|
343
355
|
}
|
|
344
356
|
|
|
345
|
-
|
|
346
|
-
|
|
357
|
+
return {
|
|
358
|
+
message: "There are this many items"
|
|
347
359
|
}
|
|
348
360
|
}
|
|
349
361
|
</script>
|
|
@@ -366,6 +378,42 @@ any logic you need. If you return a value from this function, it will be passed
|
|
|
366
378
|
{message}: {$data.items.length}
|
|
367
379
|
```
|
|
368
380
|
|
|
381
|
+
#### `afterLoad`
|
|
382
|
+
|
|
383
|
+
Called after Houdini executes load queries against the server. You can expect the same
|
|
384
|
+
arguments as SvelteKit's [`load`](https://kit.svelte.dev/docs#loading) hook, plus an additional
|
|
385
|
+
`data` property referencing query result data.
|
|
386
|
+
|
|
387
|
+
If you return a value from this function, it will be passed as props to your component.
|
|
388
|
+
|
|
389
|
+
```svelte
|
|
390
|
+
<script context="module">
|
|
391
|
+
export function MyProfileVariables({ page: { params: { id } } }) {
|
|
392
|
+
return { id }
|
|
393
|
+
}
|
|
394
|
+
export function afterLoad({ data }){
|
|
395
|
+
if(!data.MyProfile){
|
|
396
|
+
return this.error(404)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
</script>
|
|
400
|
+
|
|
401
|
+
<script>
|
|
402
|
+
import { query, graphql } from '$houdini'
|
|
403
|
+
|
|
404
|
+
// load the items
|
|
405
|
+
const { data } = query(graphql`
|
|
406
|
+
query MyProfile {
|
|
407
|
+
profile(id) {
|
|
408
|
+
name
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
`)
|
|
412
|
+
</script>
|
|
413
|
+
|
|
414
|
+
Hello I'm {$data.profile.name}
|
|
415
|
+
```
|
|
416
|
+
|
|
369
417
|
### Refetching Data
|
|
370
418
|
|
|
371
419
|
Refetching data is done with the `refetch` function provided from the result of a query:
|
|
@@ -572,6 +620,8 @@ query AllUsers {
|
|
|
572
620
|
}
|
|
573
621
|
}
|
|
574
622
|
```
|
|
623
|
+
> Keep in mind, if you are using fragment variables inside of a field flagged for
|
|
624
|
+
> list operations, you'll have to pass a value for the variable when performing the operation
|
|
575
625
|
|
|
576
626
|
## 📝 Mutations
|
|
577
627
|
|
package/build/cmd/generate.js
CHANGED
|
@@ -107,13 +107,17 @@ exports.runPipeline = function (config, docs) { return __awaiter(void 0, void 0,
|
|
|
107
107
|
// we need to create the runtime folder structure
|
|
108
108
|
_a.sent();
|
|
109
109
|
return [4 /*yield*/, houdini_common_1.runPipeline(config, [
|
|
110
|
-
transforms.internalSchema,
|
|
111
|
-
transforms.list,
|
|
112
|
-
transforms.addID,
|
|
113
110
|
validators.typeCheck,
|
|
114
|
-
transforms.typename,
|
|
115
111
|
validators.uniqueNames,
|
|
116
112
|
validators.noIDAlias,
|
|
113
|
+
transforms.internalSchema,
|
|
114
|
+
transforms.addID,
|
|
115
|
+
transforms.typename,
|
|
116
|
+
// list transform must go before fragment variables
|
|
117
|
+
// so that the mutation fragments are defined before they get mixed in
|
|
118
|
+
transforms.list,
|
|
119
|
+
// paginate transform needs to go before fragmentVariables
|
|
120
|
+
// so that the variable definitions get hashed
|
|
117
121
|
transforms.paginate,
|
|
118
122
|
transforms.fragmentVariables,
|
|
119
123
|
transforms.composeQueries,
|
|
@@ -65,7 +65,7 @@ function selection(_a) {
|
|
|
65
65
|
// look up the fragment definition
|
|
66
66
|
var fragmentDefinition = document.document.definitions.find(function (defn) { return defn.kind === 'FragmentDefinition' && defn.name.value === field.name.value; });
|
|
67
67
|
if (!fragmentDefinition) {
|
|
68
|
-
throw new Error('
|
|
68
|
+
throw new Error('selection: could not find definition for fragment ' + field.name.value);
|
|
69
69
|
}
|
|
70
70
|
// merge the fragments selection into ours
|
|
71
71
|
object = utils_1.deepMerge(object, selection({
|
|
@@ -191,7 +191,10 @@ function generateOperationTypeDefs(config, body, definition, selections, visited
|
|
|
191
191
|
types_1.readonlyProperty(AST.tsPropertySignature(AST.stringLiteral('input'), AST.tsTypeAnnotation(hasInputs
|
|
192
192
|
? AST.tsTypeReference(AST.identifier(inputTypeName))
|
|
193
193
|
: AST.tsNullKeyword()))),
|
|
194
|
-
types_1.readonlyProperty(AST.tsPropertySignature(AST.stringLiteral('result'), AST.tsTypeAnnotation(AST.
|
|
194
|
+
types_1.readonlyProperty(AST.tsPropertySignature(AST.stringLiteral('result'), AST.tsTypeAnnotation(AST.tsUnionType([
|
|
195
|
+
AST.tsTypeReference(AST.identifier(shapeTypeName)),
|
|
196
|
+
AST.tsUndefinedKeyword(),
|
|
197
|
+
])))),
|
|
195
198
|
]))),
|
|
196
199
|
// export the type that describes the result
|
|
197
200
|
AST.exportNamedDeclaration(AST.tsTypeAliasDeclaration(AST.identifier(shapeTypeName), inlineType_1.inlineType({
|
|
@@ -8,10 +8,3 @@ export declare type FragmentDependency = {
|
|
|
8
8
|
};
|
|
9
9
|
export default function includeFragmentDefinitions(config: Config, documents: CollectedGraphQLDocument[]): Promise<void>;
|
|
10
10
|
export declare function collectFragments(config: Config, docs: CollectedGraphQLDocument[]): Record<string, FragmentDependency>;
|
|
11
|
-
export declare function flattenFragments(operation: {
|
|
12
|
-
requiredFragments: Array<string>;
|
|
13
|
-
}, fragments: {
|
|
14
|
-
[name: string]: {
|
|
15
|
-
requiredFragments: Array<string>;
|
|
16
|
-
};
|
|
17
|
-
}): Array<string>;
|
|
@@ -78,7 +78,7 @@ var __spread = (this && this.__spread) || function () {
|
|
|
78
78
|
return ar;
|
|
79
79
|
};
|
|
80
80
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
81
|
-
exports.
|
|
81
|
+
exports.collectFragments = void 0;
|
|
82
82
|
// externals
|
|
83
83
|
var graphql_1 = require("graphql");
|
|
84
84
|
// includeFragmentDefinitions adds any referenced fragments to operations
|
|
@@ -199,7 +199,7 @@ function flattenFragments(operation, fragments) {
|
|
|
199
199
|
// grab the referenced fragment
|
|
200
200
|
var targetFragment = fragments[nextFragment];
|
|
201
201
|
if (!targetFragment) {
|
|
202
|
-
throw new Error('
|
|
202
|
+
throw new Error('compose: could not find definition for fragment ' + nextFragment);
|
|
203
203
|
}
|
|
204
204
|
// add this fragments dependents to the pile
|
|
205
205
|
remaining.push.apply(remaining, __spread(targetFragment.requiredFragments));
|
|
@@ -207,4 +207,3 @@ function flattenFragments(operation, fragments) {
|
|
|
207
207
|
// we're done
|
|
208
208
|
return __spread(frags);
|
|
209
209
|
}
|
|
210
|
-
exports.flattenFragments = flattenFragments;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { Config } from 'houdini-common';
|
|
2
2
|
import * as graphql from 'graphql';
|
|
3
3
|
import { CollectedGraphQLDocument } from '../types';
|
|
4
|
+
import { FragmentDependency } from './composeQueries';
|
|
4
5
|
export default function fragmentVariables(config: Config, documents: CollectedGraphQLDocument[]): Promise<void>;
|
|
6
|
+
declare type ValueMap = Record<string, graphql.ValueNode>;
|
|
7
|
+
export declare function inlineFragmentArgs({ config, fragmentDefinitions, document, generatedFragments, visitedFragments, scope, newName, }: {
|
|
8
|
+
config: Config;
|
|
9
|
+
fragmentDefinitions: Record<string, FragmentDependency>;
|
|
10
|
+
document: graphql.ASTNode;
|
|
11
|
+
generatedFragments: Record<string, graphql.FragmentDefinitionNode>;
|
|
12
|
+
visitedFragments: Set<string>;
|
|
13
|
+
scope: ValueMap | undefined | null;
|
|
14
|
+
newName?: string;
|
|
15
|
+
}): any;
|
|
5
16
|
export declare function withArguments(config: Config, node: graphql.FragmentSpreadNode): graphql.ArgumentNode[];
|
|
6
17
|
export declare type FragmentArgument = {
|
|
7
18
|
name: string;
|
|
@@ -10,3 +21,8 @@ export declare type FragmentArgument = {
|
|
|
10
21
|
defaultValue: graphql.ValueNode | null;
|
|
11
22
|
};
|
|
12
23
|
export declare function fragmentArguments(config: Config, definition: graphql.FragmentDefinitionNode): FragmentArgument[];
|
|
24
|
+
export declare function collectWithArguments(config: Config, node: graphql.FragmentSpreadNode, scope?: ValueMap | null): {
|
|
25
|
+
args: ValueMap | null;
|
|
26
|
+
hash: string;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -97,7 +97,7 @@ var __spread = (this && this.__spread) || function () {
|
|
|
97
97
|
return ar;
|
|
98
98
|
};
|
|
99
99
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
100
|
-
exports.fragmentArguments = exports.withArguments = void 0;
|
|
100
|
+
exports.collectWithArguments = exports.fragmentArguments = exports.withArguments = exports.inlineFragmentArgs = void 0;
|
|
101
101
|
var graphql = __importStar(require("graphql"));
|
|
102
102
|
var composeQueries_1 = require("./composeQueries");
|
|
103
103
|
var utils_1 = require("../utils");
|
|
@@ -105,11 +105,10 @@ var types_1 = require("../../runtime/types");
|
|
|
105
105
|
var GraphqlKinds = graphql.Kind;
|
|
106
106
|
// fragmentVariables transforms fragment spreads with variables into something the server can use
|
|
107
107
|
function fragmentVariables(config, documents) {
|
|
108
|
-
var _a;
|
|
109
108
|
return __awaiter(this, void 0, void 0, function () {
|
|
110
|
-
var fragments, generatedFragments, visitedFragments, documents_1, documents_1_1, doc_1, operation,
|
|
111
|
-
var e_1,
|
|
112
|
-
return __generator(this, function (
|
|
109
|
+
var fragments, generatedFragments, visitedFragments, documents_1, documents_1_1, doc_1, operation, doc;
|
|
110
|
+
var e_1, _a;
|
|
111
|
+
return __generator(this, function (_b) {
|
|
113
112
|
fragments = composeQueries_1.collectFragments(config, documents);
|
|
114
113
|
generatedFragments = {};
|
|
115
114
|
visitedFragments = new Set();
|
|
@@ -125,16 +124,6 @@ function fragmentVariables(config, documents) {
|
|
|
125
124
|
if (!operation) {
|
|
126
125
|
continue;
|
|
127
126
|
}
|
|
128
|
-
rootScope = ((_a = operation.variableDefinitions) === null || _a === void 0 ? void 0 : _a.reduce(function (scope, definition) {
|
|
129
|
-
var _a;
|
|
130
|
-
return (__assign(__assign({}, scope), (_a = {}, _a[definition.variable.name.value] = {
|
|
131
|
-
kind: 'Variable',
|
|
132
|
-
name: {
|
|
133
|
-
kind: 'Name',
|
|
134
|
-
value: definition.variable.name.value,
|
|
135
|
-
},
|
|
136
|
-
}, _a)));
|
|
137
|
-
}, {})) || {};
|
|
138
127
|
// inline any fragment arguments in the document
|
|
139
128
|
doc_1.document = inlineFragmentArgs({
|
|
140
129
|
config: config,
|
|
@@ -142,14 +131,14 @@ function fragmentVariables(config, documents) {
|
|
|
142
131
|
document: doc_1.document,
|
|
143
132
|
generatedFragments: generatedFragments,
|
|
144
133
|
visitedFragments: visitedFragments,
|
|
145
|
-
scope:
|
|
134
|
+
scope: null,
|
|
146
135
|
});
|
|
147
136
|
}
|
|
148
137
|
}
|
|
149
138
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
150
139
|
finally {
|
|
151
140
|
try {
|
|
152
|
-
if (documents_1_1 && !documents_1_1.done && (
|
|
141
|
+
if (documents_1_1 && !documents_1_1.done && (_a = documents_1.return)) _a.call(documents_1);
|
|
153
142
|
}
|
|
154
143
|
finally { if (e_1) throw e_1.error; }
|
|
155
144
|
}
|
|
@@ -172,37 +161,22 @@ function fragmentVariables(config, documents) {
|
|
|
172
161
|
exports.default = fragmentVariables;
|
|
173
162
|
function inlineFragmentArgs(_a) {
|
|
174
163
|
var config = _a.config, fragmentDefinitions = _a.fragmentDefinitions, document = _a.document, generatedFragments = _a.generatedFragments, visitedFragments = _a.visitedFragments, scope = _a.scope, newName = _a.newName;
|
|
164
|
+
// if the scope is null, use the root-level scope defined by the document's
|
|
165
|
+
// operation definition
|
|
166
|
+
if (!scope) {
|
|
167
|
+
scope = operationScope(document.definitions.find(function (_a) {
|
|
168
|
+
var kind = _a.kind;
|
|
169
|
+
return kind === GraphqlKinds.OPERATION_DEFINITION;
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
175
172
|
// look up the arguments for the fragment
|
|
176
173
|
var definitionArgs = fragmentArguments(config, document).reduce(function (acc, arg) {
|
|
177
174
|
var _a;
|
|
178
175
|
return (__assign(__assign({}, acc), (_a = {}, _a[arg.name] = arg, _a)));
|
|
179
176
|
}, {});
|
|
180
177
|
var result = graphql.visit(document, {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
var value = node.value;
|
|
184
|
-
if (value.kind !== 'Variable') {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
// if there's no scope we can't evaluate it
|
|
188
|
-
if (!scope) {
|
|
189
|
-
throw new Error(node.name.value +
|
|
190
|
-
' is not defined in the current scope: ' +
|
|
191
|
-
JSON.stringify(scope));
|
|
192
|
-
}
|
|
193
|
-
// is the variable in scope
|
|
194
|
-
var newValue = scope[value.name.value];
|
|
195
|
-
// if it is just use it
|
|
196
|
-
if (newValue) {
|
|
197
|
-
return __assign(__assign({}, node), { value: newValue });
|
|
198
|
-
}
|
|
199
|
-
// if the argument is required
|
|
200
|
-
if (definitionArgs[value.name.value] && definitionArgs[value.name.value].required) {
|
|
201
|
-
throw new Error('Missing value for required arg: ' + value.name.value);
|
|
202
|
-
}
|
|
203
|
-
// if we got this far, theres no value for a non-required arg, remove the node
|
|
204
|
-
return null;
|
|
205
|
-
},
|
|
178
|
+
// every time we run into a fragment spread we might need to replace it
|
|
179
|
+
// with a version that incorporates the current scope's variable values
|
|
206
180
|
FragmentSpread: function (node) {
|
|
207
181
|
var e_2, _a;
|
|
208
182
|
// look at the fragment spread to see if there are any default arguments
|
|
@@ -257,7 +231,8 @@ function inlineFragmentArgs(_a) {
|
|
|
257
231
|
return definition.kind === 'FragmentDefinition' &&
|
|
258
232
|
definition.name.value === node.name.value;
|
|
259
233
|
});
|
|
260
|
-
//
|
|
234
|
+
// keep walking down the referenced fragment's selection
|
|
235
|
+
// and replace the definition in the document
|
|
261
236
|
var localDefinitions = __spread(doc.document.definitions);
|
|
262
237
|
localDefinitions.splice(definitionIndex, 1);
|
|
263
238
|
localDefinitions.push(inlineFragmentArgs({
|
|
@@ -281,8 +256,35 @@ function inlineFragmentArgs(_a) {
|
|
|
281
256
|
}
|
|
282
257
|
}
|
|
283
258
|
},
|
|
259
|
+
// look at every time something is used as an argument
|
|
260
|
+
Argument: function (node) {
|
|
261
|
+
// if the argument is a variable we need to expand it to its value (passed from the parent)
|
|
262
|
+
var value = node.value;
|
|
263
|
+
if (value.kind !== 'Variable') {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// if there's no scope we can't evaluate it
|
|
267
|
+
if (!scope) {
|
|
268
|
+
throw new Error(node.name.value +
|
|
269
|
+
' is not defined in the current scope: ' +
|
|
270
|
+
JSON.stringify(scope));
|
|
271
|
+
}
|
|
272
|
+
// is the variable in scope
|
|
273
|
+
var newValue = scope[value.name.value];
|
|
274
|
+
// if it is just use it
|
|
275
|
+
if (newValue) {
|
|
276
|
+
return __assign(__assign({}, node), { value: newValue });
|
|
277
|
+
}
|
|
278
|
+
// if the argument is required
|
|
279
|
+
if (definitionArgs[value.name.value] && definitionArgs[value.name.value].required) {
|
|
280
|
+
throw new Error('Missing value for required arg: ' + value.name.value);
|
|
281
|
+
}
|
|
282
|
+
// if we got this far, theres no value for a non-required arg, remove the node
|
|
283
|
+
return null;
|
|
284
|
+
},
|
|
284
285
|
});
|
|
285
|
-
// if we
|
|
286
|
+
// if we computed a new name for the fragment (because we got here as part of analyzing a fragment
|
|
287
|
+
// spread with @with), we need to change the name of the fragment
|
|
286
288
|
if (newName) {
|
|
287
289
|
// the new name for the document
|
|
288
290
|
result.name = {
|
|
@@ -292,6 +294,7 @@ function inlineFragmentArgs(_a) {
|
|
|
292
294
|
}
|
|
293
295
|
return result;
|
|
294
296
|
}
|
|
297
|
+
exports.inlineFragmentArgs = inlineFragmentArgs;
|
|
295
298
|
function withArguments(config, node) {
|
|
296
299
|
var _a;
|
|
297
300
|
var withDirectives = (_a = node.directives) === null || _a === void 0 ? void 0 : _a.filter(function (directive) { return directive.name.value === config.withDirective; });
|
|
@@ -407,3 +410,17 @@ function collectWithArguments(config, node, scope) {
|
|
|
407
410
|
hash: '_' + utils_1.murmurHash(JSON.stringify(args)),
|
|
408
411
|
};
|
|
409
412
|
}
|
|
413
|
+
exports.collectWithArguments = collectWithArguments;
|
|
414
|
+
function operationScope(operation) {
|
|
415
|
+
var _a;
|
|
416
|
+
return (((_a = operation.variableDefinitions) === null || _a === void 0 ? void 0 : _a.reduce(function (scope, definition) {
|
|
417
|
+
var _a;
|
|
418
|
+
return (__assign(__assign({}, scope), (_a = {}, _a[definition.variable.name.value] = {
|
|
419
|
+
kind: 'Variable',
|
|
420
|
+
name: {
|
|
421
|
+
kind: 'Name',
|
|
422
|
+
value: definition.variable.name.value,
|
|
423
|
+
},
|
|
424
|
+
}, _a)));
|
|
425
|
+
}, {})) || {});
|
|
426
|
+
}
|
|
@@ -105,7 +105,6 @@ var graphql = __importStar(require("graphql"));
|
|
|
105
105
|
var types_1 = require("../types");
|
|
106
106
|
var utils_1 = require("../utils");
|
|
107
107
|
var types_2 = require("../../runtime/types");
|
|
108
|
-
var paginate_1 = require("./paginate");
|
|
109
108
|
// addListFragments adds fragments for the fields tagged with @list
|
|
110
109
|
function addListFragments(config, documents) {
|
|
111
110
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -118,7 +117,7 @@ function addListFragments(config, documents) {
|
|
|
118
117
|
doc.document = graphql.visit(doc.document, {
|
|
119
118
|
Directive: function (node, key, parent, path, ancestors) {
|
|
120
119
|
var _a;
|
|
121
|
-
// if we found a @list applied (
|
|
120
|
+
// if we found a @list applied (or a @paginate which implies a @list )
|
|
122
121
|
if ([config.listDirective, config.paginateDirective].includes(node.name.value)) {
|
|
123
122
|
// look up the name passed to the directive
|
|
124
123
|
var nameArg = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a.find(function (arg) { return arg.name.value === 'name'; });
|
|
@@ -178,27 +177,6 @@ function addListFragments(config, documents) {
|
|
|
178
177
|
}
|
|
179
178
|
}
|
|
180
179
|
},
|
|
181
|
-
Field: function (node, key, parent, path, ancestors) {
|
|
182
|
-
var _a;
|
|
183
|
-
// if the is marked with @list and is a connection, we need to make sure that we ask for
|
|
184
|
-
// the cursor fields
|
|
185
|
-
if (!((_a = node.directives) === null || _a === void 0 ? void 0 : _a.find(function (directive) { return directive.name.value === config.listDirective; }))) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
// the field is a list, is it a connection?
|
|
189
|
-
// look up the parent's type
|
|
190
|
-
var parentType = houdini_common_1.parentTypeFromAncestors(config.schema, ancestors);
|
|
191
|
-
// a non-connection list can just use the selection set of the tagged field
|
|
192
|
-
// but if this is a connection tagged with list we need to use the selection
|
|
193
|
-
// of the edges.node field
|
|
194
|
-
var targetField = node;
|
|
195
|
-
var targetFieldDefinition = parentType.getFields()[targetField.name.value];
|
|
196
|
-
var connection = connectionSelection(config, targetFieldDefinition, houdini_common_1.parentTypeFromAncestors(config.schema, ancestors), node.selectionSet).connection;
|
|
197
|
-
// if the field is a connection, add the cursor
|
|
198
|
-
if (connection) {
|
|
199
|
-
return __assign(__assign({}, node), { selectionSet: __assign(__assign({}, node.selectionSet), { selections: __spread(node.selectionSet.selections, paginate_1.pageInfoSelection) }) });
|
|
200
|
-
}
|
|
201
|
-
},
|
|
202
180
|
});
|
|
203
181
|
};
|
|
204
182
|
try {
|
|
@@ -1,37 +1,3 @@
|
|
|
1
1
|
import { Config } from 'houdini-common';
|
|
2
2
|
import { CollectedGraphQLDocument } from '../types';
|
|
3
3
|
export default function paginate(config: Config, documents: CollectedGraphQLDocument[]): Promise<void>;
|
|
4
|
-
export declare const pageInfoSelection: {
|
|
5
|
-
kind: string;
|
|
6
|
-
name: {
|
|
7
|
-
kind: string;
|
|
8
|
-
value: string;
|
|
9
|
-
};
|
|
10
|
-
selectionSet: {
|
|
11
|
-
kind: string;
|
|
12
|
-
selections: ({
|
|
13
|
-
kind: string;
|
|
14
|
-
name: {
|
|
15
|
-
kind: string;
|
|
16
|
-
value: string;
|
|
17
|
-
};
|
|
18
|
-
selectionSet?: undefined;
|
|
19
|
-
} | {
|
|
20
|
-
kind: string;
|
|
21
|
-
name: {
|
|
22
|
-
kind: string;
|
|
23
|
-
value: string;
|
|
24
|
-
};
|
|
25
|
-
selectionSet: {
|
|
26
|
-
kind: string;
|
|
27
|
-
selections: {
|
|
28
|
-
kind: string;
|
|
29
|
-
name: {
|
|
30
|
-
kind: string;
|
|
31
|
-
value: string;
|
|
32
|
-
};
|
|
33
|
-
}[];
|
|
34
|
-
};
|
|
35
|
-
})[];
|
|
36
|
-
};
|
|
37
|
-
}[];
|
|
@@ -97,7 +97,6 @@ var __values = (this && this.__values) || function(o) {
|
|
|
97
97
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
98
98
|
};
|
|
99
99
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
100
|
-
exports.pageInfoSelection = void 0;
|
|
101
100
|
// externals
|
|
102
101
|
var graphql = __importStar(require("graphql"));
|
|
103
102
|
var houdini_common_1 = require("houdini-common");
|
|
@@ -192,7 +191,7 @@ function paginate(config, documents) {
|
|
|
192
191
|
? // no need to add any fields to the selection if we're dealing with offset pagination
|
|
193
192
|
node.selectionSet
|
|
194
193
|
: // add the page info if we are dealing with cursor-based pagination
|
|
195
|
-
__assign(__assign({}, node.selectionSet), { selections: __spread(node.selectionSet.selections,
|
|
194
|
+
__assign(__assign({}, node.selectionSet), { selections: __spread(node.selectionSet.selections, pageInfoSelection) }) });
|
|
196
195
|
},
|
|
197
196
|
});
|
|
198
197
|
// if we saw the paginate directive we need to add arguments to the fragment or query that contain the
|
|
@@ -611,7 +610,7 @@ function objectNode(_a) {
|
|
|
611
610
|
}
|
|
612
611
|
return node;
|
|
613
612
|
}
|
|
614
|
-
|
|
613
|
+
var pageInfoSelection = [
|
|
615
614
|
{
|
|
616
615
|
kind: 'Field',
|
|
617
616
|
name: {
|
|
@@ -247,6 +247,11 @@ function typeCheck(config, docs) {
|
|
|
247
247
|
var targetField = ancestors[ancestors.length - 1];
|
|
248
248
|
var targetFieldDefinition = parentType.getFields()[targetField.name.value];
|
|
249
249
|
var type = list_1.connectionSelection(config, targetFieldDefinition, houdini_common_1.parentTypeFromAncestors(config.schema, ancestors), targetField.selectionSet).type;
|
|
250
|
+
// make sure there is an id field
|
|
251
|
+
if (!type.getFields()['id']) {
|
|
252
|
+
errors.push(new types_1.HoudiniErrorTodo("@" + config.listDirective + " can only be applied to types with an id field."));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
250
255
|
// add the list to the list
|
|
251
256
|
lists.push(listName);
|
|
252
257
|
listTypes.push(type.name);
|
|
@@ -265,6 +270,10 @@ function typeCheck(config, docs) {
|
|
|
265
270
|
}
|
|
266
271
|
finally { if (e_1) throw e_1.error; }
|
|
267
272
|
}
|
|
273
|
+
// if we got errors
|
|
274
|
+
if (errors.length > 0) {
|
|
275
|
+
throw errors;
|
|
276
|
+
}
|
|
268
277
|
rules = __spread(graphql.specifiedRules).filter(
|
|
269
278
|
// remove rules that conflict with houdini
|
|
270
279
|
function (rule) {
|
|
@@ -302,7 +311,9 @@ function typeCheck(config, docs) {
|
|
|
302
311
|
// validate any fragment arguments
|
|
303
312
|
validateFragmentArguments(config, fragments),
|
|
304
313
|
// make sure there are pagination args on fields marked with @paginate
|
|
305
|
-
paginateArgs(config)
|
|
314
|
+
paginateArgs(config),
|
|
315
|
+
// make sure every argument defined in a fragment is used
|
|
316
|
+
noUnusedFragmentArguments(config));
|
|
306
317
|
try {
|
|
307
318
|
for (docs_2 = __values(docs), docs_2_1 = docs_2.next(); !docs_2_1.done; docs_2_1 = docs_2.next()) {
|
|
308
319
|
_a = docs_2_1.value, filename = _a.filename, parsed = _a.document;
|
|
@@ -659,6 +670,46 @@ function paginateArgs(config) {
|
|
|
659
670
|
};
|
|
660
671
|
};
|
|
661
672
|
}
|
|
673
|
+
function noUnusedFragmentArguments(config) {
|
|
674
|
+
return function (ctx) {
|
|
675
|
+
// if we run into a fragment definition with arguments we need to make sure every argument is used
|
|
676
|
+
var args = new Set();
|
|
677
|
+
return {
|
|
678
|
+
// when we first see a fragment definition
|
|
679
|
+
enter: {
|
|
680
|
+
FragmentDefinition: function (node) {
|
|
681
|
+
var e_7, _a;
|
|
682
|
+
var _b;
|
|
683
|
+
var definitionArguments = (_b = node.directives) === null || _b === void 0 ? void 0 : _b.filter(function (directive) { return directive.name.value === config.argumentsDirective; }).flatMap(function (directive) { return directive.arguments; });
|
|
684
|
+
try {
|
|
685
|
+
for (var _c = __values((definitionArguments === null || definitionArguments === void 0 ? void 0 : definitionArguments.map(function (arg) { return arg === null || arg === void 0 ? void 0 : arg.name.value; })) || []), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
686
|
+
var arg = _d.value;
|
|
687
|
+
args.add(arg);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
691
|
+
finally {
|
|
692
|
+
try {
|
|
693
|
+
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
694
|
+
}
|
|
695
|
+
finally { if (e_7) throw e_7.error; }
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
Variable: function (node) {
|
|
699
|
+
args.delete(node.name.value);
|
|
700
|
+
},
|
|
701
|
+
},
|
|
702
|
+
leave: {
|
|
703
|
+
// once we're done with the definition make sure we used everything
|
|
704
|
+
FragmentDefinition: function (node) {
|
|
705
|
+
if (args.size > 0) {
|
|
706
|
+
ctx.reportError(new graphql.GraphQLError('Encountered unused fragment arguments: ' + __spread(args).join(',')));
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
}
|
|
662
713
|
function nodeDirectives(config, directives) {
|
|
663
714
|
var queryType = config.schema.getQueryType();
|
|
664
715
|
var possibleNodes = [(queryType === null || queryType === void 0 ? void 0 : queryType.name) || ''];
|