houdini-svelte 0.17.0-next.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +21 -0
  3. package/package.json +57 -0
  4. package/src/plugin/codegen/adapter.ts +45 -0
  5. package/src/plugin/codegen/components/index.ts +149 -0
  6. package/src/plugin/codegen/index.ts +28 -0
  7. package/src/plugin/codegen/routes/index.ts +307 -0
  8. package/src/plugin/codegen/routes/kit.test.ts +276 -0
  9. package/src/plugin/codegen/stores/fragment.ts +83 -0
  10. package/src/plugin/codegen/stores/index.ts +55 -0
  11. package/src/plugin/codegen/stores/mutation.ts +56 -0
  12. package/src/plugin/codegen/stores/query.test.ts +504 -0
  13. package/src/plugin/codegen/stores/query.ts +97 -0
  14. package/src/plugin/codegen/stores/subscription.ts +57 -0
  15. package/src/plugin/extract.test.ts +290 -0
  16. package/src/plugin/extract.ts +127 -0
  17. package/src/plugin/extractLoadFunction.test.ts +247 -0
  18. package/src/plugin/extractLoadFunction.ts +249 -0
  19. package/src/plugin/fsPatch.ts +238 -0
  20. package/src/plugin/imports.ts +28 -0
  21. package/src/plugin/index.ts +165 -0
  22. package/src/plugin/kit.ts +382 -0
  23. package/src/plugin/transforms/index.ts +90 -0
  24. package/src/plugin/transforms/kit/index.ts +20 -0
  25. package/src/plugin/transforms/kit/init.test.ts +28 -0
  26. package/src/plugin/transforms/kit/init.ts +75 -0
  27. package/src/plugin/transforms/kit/load.test.ts +1234 -0
  28. package/src/plugin/transforms/kit/load.ts +506 -0
  29. package/src/plugin/transforms/kit/session.test.ts +268 -0
  30. package/src/plugin/transforms/kit/session.ts +161 -0
  31. package/src/plugin/transforms/query.test.ts +99 -0
  32. package/src/plugin/transforms/query.ts +263 -0
  33. package/src/plugin/transforms/reactive.ts +126 -0
  34. package/src/plugin/transforms/tags.ts +20 -0
  35. package/src/plugin/transforms/types.ts +9 -0
  36. package/src/plugin/validate.test.ts +95 -0
  37. package/src/plugin/validate.ts +50 -0
  38. package/src/preprocess/index.ts +33 -0
  39. package/src/runtime/adapter.ts +21 -0
  40. package/src/runtime/fragments.ts +86 -0
  41. package/src/runtime/index.ts +72 -0
  42. package/src/runtime/network.ts +6 -0
  43. package/src/runtime/session.ts +187 -0
  44. package/src/runtime/stores/fragment.ts +48 -0
  45. package/src/runtime/stores/index.ts +5 -0
  46. package/src/runtime/stores/mutation.ts +185 -0
  47. package/src/runtime/stores/pagination/cursor.ts +265 -0
  48. package/src/runtime/stores/pagination/fetch.ts +7 -0
  49. package/src/runtime/stores/pagination/fragment.ts +236 -0
  50. package/src/runtime/stores/pagination/index.ts +7 -0
  51. package/src/runtime/stores/pagination/offset.ts +162 -0
  52. package/src/runtime/stores/pagination/pageInfo.test.ts +39 -0
  53. package/src/runtime/stores/pagination/pageInfo.ts +67 -0
  54. package/src/runtime/stores/pagination/query.ts +132 -0
  55. package/src/runtime/stores/query.ts +524 -0
  56. package/src/runtime/stores/store.ts +13 -0
  57. package/src/runtime/stores/subscription.ts +107 -0
  58. package/src/runtime/types.ts +40 -0
  59. package/src/test/index.ts +208 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # houdini-svelte
2
+
3
+ ## 0.17.0-next.0
4
+
5
+ ### ⚠️ Breaking Changes
6
+
7
+ - [#593](https://github.com/HoudiniGraphql/houdini/pull/593) [`c1363fe`](https://github.com/HoudiniGraphql/houdini/commit/c1363fe938ab94281272cad8939b892fd705a803) Thanks [@AlecAivazis](https://github.com/AlecAivazis)! - Split houdini into two packages: `houdini` and `houdini-svelte`
8
+
9
+ ### ✨ Features
10
+
11
+ - [#593](https://github.com/HoudiniGraphql/houdini/pull/593) [`c1363fe`](https://github.com/HoudiniGraphql/houdini/commit/c1363fe938ab94281272cad8939b892fd705a803) Thanks [@AlecAivazis](https://github.com/AlecAivazis)! - Adding layout.gql special file
12
+
13
+ - [#610](https://github.com/HoudiniGraphql/houdini/pull/610) [`3168f7d`](https://github.com/HoudiniGraphql/houdini/commit/3168f7dffd06f5074d08652d2d2c459377bc73d6) Thanks [@AlecAivazis](https://github.com/AlecAivazis)! - Generate variable function definitions for non-route queries
14
+
15
+ ### 🐛 Fixes
16
+
17
+ - [#613](https://github.com/HoudiniGraphql/houdini/pull/613) [`eb3ffe1`](https://github.com/HoudiniGraphql/houdini/commit/eb3ffe1fbf14180210464863cb7e2ca29892a1fe) Thanks [@AlecAivazis](https://github.com/AlecAivazis)! - Avoid unnecessary data prop being added to route
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Alec Aivazis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "houdini-svelte",
3
+ "version": "0.17.0-next.0",
4
+ "description": "The svelte plugin for houdini",
5
+ "type": "module",
6
+ "dependencies": {
7
+ "@kitql/helper": "^0.5.0",
8
+ "@sveltejs/kit": "1.0.0-next.505",
9
+ "ast-types": "^0.15.1",
10
+ "estree-walker": "^3.0.1",
11
+ "graphql": "^16.6.0",
12
+ "houdini": "^0.17.0-next.0",
13
+ "scripts": "^1.0.0",
14
+ "minimatch": "^5.1.0",
15
+ "recast": "^0.21.5",
16
+ "svelte": "^3.52.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/minimatch": "^5.1.2",
20
+ "vitest": "^0.23.4"
21
+ },
22
+ "peerDependencies": {
23
+ "graphql": "^0.13.0 || ^14.0.0 || ^15.0.0"
24
+ },
25
+ "exports": {
26
+ "./package.json": "./package.json",
27
+ ".": {
28
+ "import": "./build/plugin-esm/index.js",
29
+ "require": "./build/plugin-cjs/index.js"
30
+ },
31
+ "./preprocess": {
32
+ "import": "./build/preprocess-esm/index.js",
33
+ "require": "./build/preprocess-cjs/index.js"
34
+ },
35
+ "./test": {
36
+ "import": "./build/test-esm/index.js",
37
+ "require": "./build/test-cjs/index.js"
38
+ }
39
+ },
40
+ "typesVersions": {
41
+ "*": {
42
+ "preprocess": [
43
+ "build/preprocess/index.d.ts"
44
+ ],
45
+ "test": [
46
+ "build/test/index.d.ts"
47
+ ]
48
+ }
49
+ },
50
+ "main": "./build/plugin-cjs/index.js",
51
+ "types": "./build/plugin/index.d.ts",
52
+ "scripts": {
53
+ "tests": "vitest",
54
+ "compile": "scripts build --plugin",
55
+ "typedefs": "scripts typedefs --plugin"
56
+ }
57
+ }
@@ -0,0 +1,45 @@
1
+ import { fs, path } from 'houdini'
2
+
3
+ import { PluginGenerateInput } from '.'
4
+
5
+ export default async function generateAdapter({ config, framework }: PluginGenerateInput) {
6
+ // we only need to generate an adapter for kit (the default one is fine for vanilla svelte)
7
+ if (framework !== 'kit') {
8
+ return
9
+ }
10
+
11
+ // the location of the adapter
12
+ const adapterLocation = path.join(config.pluginRuntimeDirectory('houdini-svelte'), 'adapter.js')
13
+
14
+ // figure out which adapter we need to lay down
15
+ const adapter = {
16
+ kit: sveltekitAdapter,
17
+ }[framework]
18
+
19
+ // write the index file that exports the runtime
20
+ await fs.mkdirp(path.dirname(adapterLocation))
21
+ await fs.writeFile(adapterLocation, adapter)
22
+ }
23
+
24
+ const sveltekitAdapter = `import { goto as go } from '$app/navigation'
25
+ import { get } from 'svelte/store';
26
+ import { browser, prerendering } from '$app/environment'
27
+ import { page } from '$app/stores'
28
+ import { error as svelteKitError } from '@sveltejs/kit'
29
+
30
+ export function goTo(location, options) {
31
+ go(location, options)
32
+ }
33
+
34
+ export const isBrowser = browser
35
+
36
+ export let clientStarted = false;
37
+
38
+ export function setClientStarted() {
39
+ clientStarted = true
40
+ }
41
+
42
+ export const isPrerender = prerendering
43
+
44
+ export const error = svelteKitError
45
+ `
@@ -0,0 +1,149 @@
1
+ import { ArtifactKind, Config, fs, GenerateHookInput, path } from 'houdini'
2
+
3
+ import { Framework } from '../../kit'
4
+
5
+ export default async function componentTypesGenerator(
6
+ framework: Framework,
7
+ { config, documents }: GenerateHookInput
8
+ ) {
9
+ // if we treat the documents as the source of truth for files that match
10
+ // we can just filter out the ones that don't apply:t
11
+ // - in kit, exclude the route directory
12
+ // - group the files by directory
13
+ // - generate ./$houdini in the typeroot directory at the correct spot
14
+
15
+ // there could be many queries in a given component so we can't just think about filepaths
16
+ const queries: Record<string, { name: string; query: string }[]> = {}
17
+ for (const document of documents) {
18
+ if (document.kind !== ArtifactKind.Query) {
19
+ continue
20
+ }
21
+
22
+ queries[document.filename] = (queries[document.filename] ?? []).concat({
23
+ name: document.name,
24
+ query: document.originalString,
25
+ })
26
+ }
27
+ let matches = Object.keys(queries).filter((filepath) => filepath.endsWith('.svelte'))
28
+
29
+ // if we are in kit, don't consider the source directory
30
+ if (framework === 'kit') {
31
+ matches = matches.filter((match) => !match.startsWith(config.routesDir))
32
+ }
33
+
34
+ // group the files by directory
35
+ const files: ProjectDirs = {
36
+ dirs: {},
37
+ files: [],
38
+ }
39
+
40
+ // put every file we found in the right place
41
+ for (let file of matches) {
42
+ // only worry about things relative to the project root
43
+ file = path.relative(config.projectRoot, file)
44
+
45
+ // walk down the path
46
+ let target = files
47
+ const parts = file.split('/')
48
+ for (const [i, part] of parts.entries()) {
49
+ // if we are at the end of the path, we are looking at a file
50
+ if (i === parts.length - 1) {
51
+ target.files.push(part)
52
+ continue
53
+ }
54
+
55
+ // we are on a file
56
+ if (!target.dirs[part]) {
57
+ target.dirs[part] = {
58
+ dirs: {},
59
+ files: [],
60
+ }
61
+ }
62
+
63
+ // there is guaranteed to be an entry for this particular filepath part
64
+ // focus on it and move onto the next one
65
+ target = target.dirs[part]
66
+ }
67
+ }
68
+
69
+ // now that we've grouped together all of the files together, we can just walk down the
70
+ // structure and generate the necessary types at the right place.
71
+ await walk_project(config, files, queries, config.projectRoot)
72
+ }
73
+
74
+ async function walk_project(
75
+ config: Config,
76
+ dirs: ProjectDirs,
77
+ queries: Record<string, { name: string; query: string }[]>,
78
+ root: string
79
+ ) {
80
+ // process every child directory
81
+ await Promise.all(
82
+ Object.entries(dirs.dirs).map(async ([path_part, child]) => {
83
+ // keep going with the new root
84
+ return walk_project(config, child, queries, path.join(root, path_part))
85
+ })
86
+ )
87
+
88
+ // if we don't have any files at this spot we're done
89
+ if (dirs.files.length === 0) {
90
+ return
91
+ }
92
+
93
+ // every query in this directory needs an entry in the file
94
+ let typeFile = "import type { ComponentProps } from 'svelte'"
95
+ for (const file of dirs.files) {
96
+ const no_ext = path.parse(file).name
97
+ const prop_type = no_ext + 'Props'
98
+
99
+ // figure out the full file path
100
+ const filepath = path.join(root, file)
101
+
102
+ // we need to figure out the props for this component
103
+ const contents = await fs.readFile(filepath)
104
+ // make typescript happy
105
+ if (!contents) {
106
+ continue
107
+ }
108
+
109
+ // define the prop types for the component
110
+ typeFile =
111
+ `
112
+ import ${no_ext} from './${file}'
113
+ ` +
114
+ typeFile +
115
+ `
116
+ type ${prop_type} = ComponentProps<${no_ext}>
117
+ `
118
+
119
+ // a file can contain multiple queries
120
+ for (const query of queries[filepath]) {
121
+ // we can't generate actual type defs for props so let's just export a
122
+ // generic typedefinition
123
+ typeFile =
124
+ `
125
+ import type { ${query.name}$input } from '${path
126
+ .relative(filepath, path.join(config.artifactDirectory, query.name))
127
+ .replace('/$houdini', '')}'
128
+ ` +
129
+ typeFile +
130
+ `
131
+ export type ${config.variableFunctionName(
132
+ query.name
133
+ )} = <_Props = ${prop_type}>(args: { props: _Props }) => FragmentQueryVars$input
134
+ `
135
+ }
136
+ }
137
+
138
+ // we need to write this file in the correct location in the type root dir
139
+ const relative = path.join(config.typeRootDir, path.relative(config.projectRoot, root))
140
+
141
+ // write the file
142
+ await fs.mkdirp(relative)
143
+ await fs.writeFile(path.join(relative, '$houdini.d.ts'), typeFile)
144
+ }
145
+
146
+ type ProjectDirs = {
147
+ dirs: Record<string, ProjectDirs>
148
+ files: string[]
149
+ }
@@ -0,0 +1,28 @@
1
+ import { GenerateHookInput, fs, Config } from 'houdini'
2
+
3
+ import { stores_directory, type_route_dir } from '../kit'
4
+ import adapter from './adapter'
5
+ import components from './components'
6
+ import kit from './routes'
7
+ import stores from './stores'
8
+
9
+ export default async function (input: PluginGenerateInput) {
10
+ // create the static directories
11
+ await Promise.all([
12
+ fs.mkdirp(type_route_dir(input.config)),
13
+ fs.mkdirp(stores_directory(input.plugin_root)),
14
+ ])
15
+
16
+ // generate the files
17
+ await Promise.all([
18
+ adapter(input),
19
+ kit(input.framework, input),
20
+ stores(input),
21
+ components(input.framework, input),
22
+ ])
23
+ }
24
+
25
+ export type PluginGenerateInput = Omit<GenerateHookInput, 'config'> & {
26
+ config: Config
27
+ framework: 'kit' | 'svelte'
28
+ }
@@ -0,0 +1,307 @@
1
+ import { OperationDefinitionNode } from 'graphql'
2
+ import { Config, fs, GenerateHookInput, path } from 'houdini'
3
+
4
+ import { extract_load_function } from '../../extractLoadFunction'
5
+ import {
6
+ type_route_dir,
7
+ walk_routes,
8
+ stores_directory_name,
9
+ store_suffix,
10
+ Framework,
11
+ } from '../../kit'
12
+
13
+ export default async function svelteKitGenerator(
14
+ framework: Framework,
15
+ { config }: GenerateHookInput
16
+ ) {
17
+ // this generator creates the locally imported type definitions.
18
+ // the component type generator will handle
19
+ if (framework !== 'kit') {
20
+ return
21
+ }
22
+
23
+ // we need to walk down their route directory and create any variable definitions we need
24
+ await walk_routes(config, framework, {
25
+ async route({
26
+ dirpath,
27
+ pageScript,
28
+ layoutScript,
29
+ routePageQuery,
30
+ routeLayoutQuery,
31
+ inlineLayoutQueries,
32
+ inlineQueries,
33
+ }) {
34
+ // in order to create the variable definition we need to know every query that is being
35
+ // used in a specific route so we can generate versions of the variable functions with
36
+ // the Params type from './$types' provided by the sveltekit rootDir
37
+
38
+ let scriptPageExports: string[] = []
39
+ let scriptLayoutExports: string[] = []
40
+
41
+ const pageQueries = inlineQueries.concat(routePageQuery ?? [])
42
+ const layoutQueries = inlineLayoutQueries.concat(routeLayoutQuery ?? [])
43
+
44
+ // pageScript need to be imported so we can figure out if there is a houdini_load
45
+ // and what's inside.
46
+ if (pageScript) {
47
+ // import the houdini_load function
48
+ const { houdini_load, exports } = await extract_load_function(config, pageScript)
49
+
50
+ // add every load to the list
51
+ pageQueries.push(...(houdini_load ?? []))
52
+ scriptPageExports = exports
53
+ }
54
+
55
+ // pageScript need to be imported so we can figure out if there is a houdini_load
56
+ // and what's inside.
57
+ if (layoutScript) {
58
+ // import the houdini_load function
59
+ const { houdini_load, exports } = await extract_load_function(config, layoutScript)
60
+
61
+ // add every load to the list
62
+ layoutQueries.push(...(houdini_load ?? []))
63
+ scriptLayoutExports = exports
64
+ }
65
+
66
+ // if we have no queries, there's nothing to do
67
+ if (pageQueries.length === 0 && layoutQueries.length === 0) {
68
+ return
69
+ }
70
+
71
+ // we need to write the type defs to the same route path relative to the type root
72
+ // const targetPath = path.join(config.typeRouteDir,
73
+ const relativePath = path.relative(config.routesDir, dirpath)
74
+ const target = path.join(type_route_dir(config), relativePath, config.typeRootFile)
75
+
76
+ // we can't import from $houdini so we need to compute the relative path from the import
77
+ const houdiniRelative = path.relative(target, config.typeRootDir)
78
+
79
+ // the unique set of query names
80
+ const queryNames: string[] = []
81
+ const uniqueQueries: OperationDefinitionNode[] = []
82
+ for (const query of pageQueries) {
83
+ if (!queryNames.includes(query.name!.value)) {
84
+ queryNames.push(query.name!.value)
85
+ uniqueQueries.push(query)
86
+ }
87
+ }
88
+
89
+ const layoutNames: string[] = []
90
+ const uniqueLayoutQueries: OperationDefinitionNode[] = []
91
+ for (const layout of layoutQueries) {
92
+ if (!layoutNames.includes(layout.name!.value)) {
93
+ layoutNames.push(layout.name!.value)
94
+ uniqueLayoutQueries.push(layout)
95
+ }
96
+ }
97
+
98
+ // we need to create a typescript file that has a definition of the variable and hook functions
99
+ const typeDefs = getTypeDefs(
100
+ houdiniRelative,
101
+ config,
102
+ uniqueQueries,
103
+ pageQueries,
104
+ uniqueLayoutQueries,
105
+ layoutQueries,
106
+ scriptPageExports,
107
+ scriptLayoutExports
108
+ )
109
+
110
+ // make sure we have a home for the directory
111
+ await fs.mkdirp(path.dirname(target))
112
+
113
+ // write the file
114
+ await fs.writeFile(target, typeDefs)
115
+ },
116
+ })
117
+ }
118
+
119
+ function getTypeDefs(
120
+ houdiniRelative: string,
121
+ config: Config,
122
+ uniqueQueries: OperationDefinitionNode[],
123
+ pageQueries: OperationDefinitionNode[],
124
+ uniqueLayoutQueries: OperationDefinitionNode[],
125
+ layoutQueries: OperationDefinitionNode[],
126
+ scriptPageExports: string[],
127
+ scriptLayoutExports: string[]
128
+ ) {
129
+ const afterPageLoad = scriptPageExports.includes('afterLoad')
130
+ const beforePageLoad = scriptPageExports.includes('beforeLoad')
131
+ const onPageError = scriptPageExports.includes('onError')
132
+
133
+ const afterLayoutLoad = scriptLayoutExports.includes('afterLoad')
134
+ const beforeLayoutLoad = scriptLayoutExports.includes('beforeLoad')
135
+ const onLayoutError = scriptLayoutExports.includes('onError')
136
+
137
+ return `import type * as Kit from '@sveltejs/kit';
138
+ import type { VariableFunction, AfterLoadFunction, BeforeLoadFunction } from '${houdiniRelative}/plugins/houdini-svelte/runtime/types'
139
+ ${
140
+ pageQueries.length > 0
141
+ ? `import type { PageLoadEvent, PageData as KitPageData } from './$types'`
142
+ : ``
143
+ }
144
+ ${
145
+ layoutQueries.length > 0
146
+ ? `import type { LayoutLoadEvent, LayoutData as KitPageData } from './$types'`
147
+ : ``
148
+ }
149
+
150
+ ${append_Store(houdiniRelative, config, uniqueQueries)}
151
+ ${append_Store(houdiniRelative, config, uniqueLayoutQueries)}
152
+
153
+ ${pageQueries.length > 0 ? `type PageParams = PageLoadEvent['params']` : ``}
154
+ ${layoutQueries.length > 0 ? `type LayoutParams = LayoutLoadEvent['params']` : ``}
155
+
156
+ ${append_VariablesFunction('Page', config, uniqueQueries)}
157
+ ${append_VariablesFunction('Layout', config, uniqueLayoutQueries)}
158
+
159
+ ${append_afterLoad('Page', afterPageLoad, pageQueries)}
160
+ ${append_beforeLoad(beforePageLoad)}
161
+ ${append_onError(onPageError)}
162
+ ${append_afterLoad('Layout', afterLayoutLoad, layoutQueries)}
163
+ ${append_beforeLoad(beforeLayoutLoad)}
164
+ ${append_onError(onLayoutError)}
165
+
166
+ ${append_TypeData(
167
+ config,
168
+ layoutQueries,
169
+ 'Layout',
170
+ beforeLayoutLoad,
171
+ afterLayoutLoad,
172
+ onLayoutError
173
+ )}
174
+ ${append_TypeData(config, pageQueries, 'Page', beforePageLoad, afterPageLoad, onPageError)}
175
+ `
176
+ }
177
+
178
+ function append_Store(houdiniRelative: string, config: Config, queries: OperationDefinitionNode[]) {
179
+ return queries
180
+ .map((query) => {
181
+ const name = query.name!.value
182
+
183
+ return `import { ${name}$result, ${name}$input } from '${houdiniRelative}/${
184
+ config.artifactDirectoryName
185
+ }/${name}'
186
+ import { ${name}Store } from '${houdiniRelative}/${stores_directory_name()}/${name}'`
187
+ })
188
+ .join('\n')
189
+ }
190
+
191
+ function append_VariablesFunction(
192
+ type: `Page` | `Layout`,
193
+ config: Config,
194
+ queries: OperationDefinitionNode[]
195
+ ) {
196
+ return queries
197
+ .map((query) => {
198
+ const name = query.name!.value
199
+ // if the query does not have any variables, don't include anything
200
+ if (!query.variableDefinitions?.length) {
201
+ return ''
202
+ }
203
+
204
+ return `export type ${config.variableFunctionName(
205
+ name
206
+ )} = VariableFunction<${type}Params, ${name}$input>`
207
+ })
208
+ .join('\n')
209
+ }
210
+
211
+ function append_afterLoad(
212
+ type: `Page` | `Layout`,
213
+ afterLoad: boolean,
214
+ queries: OperationDefinitionNode[]
215
+ ) {
216
+ return afterLoad
217
+ ? `
218
+ type AfterLoadReturn = ReturnType<typeof import('./+${type.toLowerCase()}').afterLoad>;
219
+
220
+ type AfterLoadData = {
221
+ ${internal_append_afterLoad(queries)}
222
+ }
223
+
224
+ type LoadInput = {
225
+ ${internal_append_afterLoadInput(queries)}
226
+ }
227
+
228
+ export type AfterLoadEvent = {
229
+ event: PageLoadEvent
230
+ data: AfterLoadData
231
+ input: LoadInput
232
+ }
233
+ `
234
+ : ''
235
+ }
236
+
237
+ function internal_append_afterLoad(queries: OperationDefinitionNode[]) {
238
+ return `${queries
239
+ .map((query) => {
240
+ // if the query does not have any variables, don't include anything
241
+ const name = query.name!.value
242
+
243
+ return [name, name + '$result'].join(': ')
244
+ })
245
+ .join(', \n')}`
246
+ }
247
+
248
+ function internal_append_afterLoadInput(queries: OperationDefinitionNode[]) {
249
+ return `${queries
250
+ .filter((query) => query.variableDefinitions?.length)
251
+ .map((query) => {
252
+ // if the query does not have any variables, don't include anything
253
+ const name = query.name!.value
254
+
255
+ return [name, name + '$input'].join(': ')
256
+ })
257
+ .join(', \n')}`
258
+ }
259
+
260
+ function append_beforeLoad(beforeLoad: boolean) {
261
+ return beforeLoad
262
+ ? `
263
+ export type BeforeLoadEvent = PageLoadEvent
264
+
265
+ type BeforeLoadReturn = ReturnType<typeof import('./+page').beforeLoad>;
266
+ `
267
+ : ''
268
+ }
269
+
270
+ function append_onError(onError: boolean) {
271
+ return onError
272
+ ? `
273
+ export type OnErrorEvent = { event: LoadEvent, input: LoadInput, error: Error | Error[] }
274
+
275
+ type OnErrorReturn = ReturnType<typeof import('./+page').onError>;
276
+ `
277
+ : ''
278
+ }
279
+
280
+ function append_TypeData(
281
+ config: Config,
282
+ queries: OperationDefinitionNode[],
283
+ type: `Page` | `Layout`,
284
+ beforeLoad: boolean,
285
+ afterLoad: boolean,
286
+ onError: boolean
287
+ ) {
288
+ if (queries.length === 0) {
289
+ return ''
290
+ }
291
+
292
+ return `export type ${type}Data = {
293
+ ${queries
294
+ .map((query) => {
295
+ const name = query.name!.value
296
+
297
+ return [name, name + store_suffix(config)].join(': ')
298
+ })
299
+ .join(', \n')}
300
+ } ${internal_append_TypeDataExtra(beforeLoad, afterLoad, onError)}`
301
+ }
302
+
303
+ function internal_append_TypeDataExtra(beforeLoad: boolean, afterLoad: boolean, onError: boolean) {
304
+ return `${beforeLoad ? '& BeforeLoadReturn ' : ''} ${afterLoad ? '& AfterLoadReturn ' : ''} ${
305
+ onError ? '& OnErrorReturn ' : ''
306
+ }`
307
+ }