polen 0.11.0-next.22 → 0.11.0-next.24

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 (93) hide show
  1. package/build/api/config/normalized.d.ts +200 -200
  2. package/build/api/examples/schemas/catalog.d.ts +4 -4
  3. package/build/api/examples/schemas/type-usage-index.d.ts +5 -5
  4. package/build/api/examples/schemas/type-usage-index.js +2 -2
  5. package/build/api/examples/schemas/type-usage-index.js.map +1 -1
  6. package/build/api/examples/type-usage-indexer.d.ts.map +1 -1
  7. package/build/api/examples/type-usage-indexer.js +41 -35
  8. package/build/api/examples/type-usage-indexer.js.map +1 -1
  9. package/build/api/schema/input-sources/directory.d.ts +1 -1
  10. package/build/api/schema/input-sources/directory.js +3 -3
  11. package/build/api/schema/input-sources/directory.js.map +1 -1
  12. package/build/api/schema/input-sources/file.d.ts +1 -1
  13. package/build/api/schema/input-sources/file.js +3 -3
  14. package/build/api/schema/input-sources/file.js.map +1 -1
  15. package/build/api/schema/input-sources/introspection-file.d.ts +1 -1
  16. package/build/api/schema/input-sources/introspection.d.ts +1 -1
  17. package/build/api/schema/input-sources/memory.d.ts +1 -1
  18. package/build/api/schema/input-sources/memory.js +3 -3
  19. package/build/api/schema/input-sources/memory.js.map +1 -1
  20. package/build/api/schema/input-sources/versioned-directory.d.ts +2 -2
  21. package/build/api/schema/input-sources/versioned-directory.js +3 -3
  22. package/build/api/schema/input-sources/versioned-directory.js.map +1 -1
  23. package/build/cli/commands/open.js +1 -1
  24. package/build/cli/commands/open.js.map +1 -1
  25. package/build/lib/catalog/catalog.d.ts +30 -30
  26. package/build/lib/catalog/unversioned.d.ts +8 -8
  27. package/build/lib/catalog/versioned.d.ts +16 -16
  28. package/build/lib/change/change.d.ts +6 -6
  29. package/build/lib/grafaid/$$.d.ts +2 -0
  30. package/build/lib/grafaid/$$.d.ts.map +1 -1
  31. package/build/lib/grafaid/$$.js +2 -0
  32. package/build/lib/grafaid/$$.js.map +1 -1
  33. package/build/lib/grafaid/parse-error.d.ts +46 -0
  34. package/build/lib/grafaid/parse-error.d.ts.map +1 -0
  35. package/build/lib/grafaid/parse-error.js +29 -0
  36. package/build/lib/grafaid/parse-error.js.map +1 -0
  37. package/build/lib/grafaid/parse.d.ts +70 -0
  38. package/build/lib/grafaid/parse.d.ts.map +1 -0
  39. package/build/lib/grafaid/parse.js +119 -0
  40. package/build/lib/grafaid/parse.js.map +1 -0
  41. package/build/lib/grafaid/schema/ast.d.ts +0 -2
  42. package/build/lib/grafaid/schema/ast.d.ts.map +1 -1
  43. package/build/lib/grafaid/schema/ast.js +1 -7
  44. package/build/lib/grafaid/schema/ast.js.map +1 -1
  45. package/build/lib/grafaid/schema/read.js +2 -2
  46. package/build/lib/grafaid/schema/read.js.map +1 -1
  47. package/build/lib/grafaid/schema/schema.d.ts +2 -1
  48. package/build/lib/grafaid/schema/schema.d.ts.map +1 -1
  49. package/build/lib/grafaid/schema/schema.js +5 -1
  50. package/build/lib/grafaid/schema/schema.js.map +1 -1
  51. package/build/lib/graphql-schema-loader/graphql-schema-loader.d.ts.map +1 -1
  52. package/build/lib/graphql-schema-loader/graphql-schema-loader.js +4 -4
  53. package/build/lib/graphql-schema-loader/graphql-schema-loader.js.map +1 -1
  54. package/build/lib/revision/revision.d.ts +30 -30
  55. package/build/lib/schema/schema.d.ts +18 -18
  56. package/build/lib/schema/unversioned.d.ts +28 -28
  57. package/build/lib/schema/versioned.d.ts +16 -16
  58. package/build/template/components/ExampleLink.d.ts.map +1 -1
  59. package/build/template/components/ExampleLink.js +4 -2
  60. package/build/template/components/ExampleLink.js.map +1 -1
  61. package/build/template/components/NamedType.d.ts.map +1 -1
  62. package/build/template/components/NamedType.js +1 -1
  63. package/build/template/components/NamedType.js.map +1 -1
  64. package/build/template/components/VersionCoveragePicker.d.ts.map +1 -1
  65. package/build/template/components/VersionCoveragePicker.js +6 -1
  66. package/build/template/components/VersionCoveragePicker.js.map +1 -1
  67. package/build/template/routes/pages.d.ts.map +1 -1
  68. package/build/template/routes/pages.js +5 -1
  69. package/build/template/routes/pages.js.map +1 -1
  70. package/build/template/stores/changelog.d.ts +1 -1
  71. package/package.json +1 -1
  72. package/src/api/examples/schemas/type-usage-index.ts +2 -2
  73. package/src/api/examples/type-usage-indexer.test.ts +152 -234
  74. package/src/api/examples/type-usage-indexer.ts +64 -52
  75. package/src/api/schema/$.test.ts +1 -1
  76. package/src/api/schema/input-sources/directory.ts +3 -3
  77. package/src/api/schema/input-sources/file.ts +3 -3
  78. package/src/api/schema/input-sources/memory.ts +3 -3
  79. package/src/api/schema/input-sources/versioned-directory.ts +3 -3
  80. package/src/cli/commands/open.ts +1 -1
  81. package/src/lib/grafaid/$$.ts +2 -0
  82. package/src/lib/grafaid/parse-error.ts +69 -0
  83. package/src/lib/grafaid/parse.test.ts +175 -0
  84. package/src/lib/grafaid/parse.ts +165 -0
  85. package/src/lib/grafaid/schema/ast.ts +1 -9
  86. package/src/lib/grafaid/schema/read.ts +2 -2
  87. package/src/lib/grafaid/schema/schema.ts +10 -2
  88. package/src/lib/graphql-schema-loader/graphql-schema-loader.ts +4 -12
  89. package/src/lib/path-map/$.test.ts +28 -13
  90. package/src/template/components/ExampleLink.tsx +4 -2
  91. package/src/template/components/NamedType.tsx +3 -1
  92. package/src/template/components/VersionCoveragePicker.tsx +8 -2
  93. package/src/template/routes/pages.tsx +6 -1
@@ -2,82 +2,90 @@ import { Catalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
3
  import { Schema } from '#lib/schema/$'
4
4
  import { Version } from '#lib/version/$'
5
- import { HashMap, HashSet, Schema as S } from 'effect'
6
- import { buildSchema } from 'graphql'
5
+ import { HashMap, HashSet } from 'effect'
6
+ import { buildSchema, type GraphQLSchema } from 'graphql'
7
7
  import { describe, expect, test } from 'vitest'
8
8
  import { Example } from './schemas/example/example.js'
9
- import * as ExampleReferenceModule from './schemas/type-usage-index.js'
9
+ import { ExampleReference } from './schemas/type-usage-index.js'
10
10
  import { createTypeUsageIndex, getExampleReferencesForType } from './type-usage-indexer.js'
11
11
 
12
- describe('type-usage-indexer', () => {
13
- const schemaString = `
14
- type Query {
15
- user(id: ID!): User
16
- users: [User!]!
17
- product(id: ID!): Product
18
- }
19
-
20
- type User {
21
- id: ID!
22
- name: String!
23
- email: String!
24
- }
25
-
26
- type Product {
27
- id: ID!
28
- name: String!
29
- price: Float!
30
- }
31
-
32
- interface Node {
33
- id: ID!
34
- }
35
-
36
- union SearchResult = User | Product
37
- `
38
-
39
- const schemaDef = buildSchema(schemaString)
40
- const version1 = Version.decodeSync('1.0.0')
41
- const version2 = Version.decodeSync('2.0.0')
42
-
43
- describe('createTypeUsageIndex', () => {
44
- test('indexes unversioned examples', () => {
45
- const example = Example.make({
46
- name: 'get-user',
47
- path: 'examples/get-user.graphql',
48
- document: Document.Unversioned.make({
49
- document: 'query { user(id: "1") { id name } }',
50
- }),
51
- })
52
-
53
- const catalog = Catalog.Unversioned.make({
54
- schema: Schema.Unversioned.make({
55
- definition: schemaDef,
56
- revisions: [],
57
- }),
58
- })
59
-
60
- const index = createTypeUsageIndex([example], catalog)
61
-
62
- // For unversioned examples, they get indexed with the latest version (1.0.0 default)
63
- const defaultVersion = Version.decodeSync('1.0.0')
12
+ // Test schema
13
+ const schemaString = `
14
+ type Query {
15
+ user(id: ID!): User
16
+ users: [User!]!
17
+ product(id: ID!): Product
18
+ }
19
+ type User {
20
+ id: ID!
21
+ name: String!
22
+ email: String!
23
+ }
24
+ type Product {
25
+ id: ID!
26
+ name: String!
27
+ price: Float!
28
+ }
29
+ interface Node {
30
+ id: ID!
31
+ }
32
+ union SearchResult = User | Product
33
+ `
34
+ const schemaDef = buildSchema(schemaString)
35
+ const version1 = Version.decodeSync('1.0.0')
36
+ const version2 = Version.decodeSync('2.0.0')
37
+
38
+ // Test helpers
39
+ const makeUnversionedCatalog = (definition: GraphQLSchema) =>
40
+ Catalog.Unversioned.make({
41
+ schema: Schema.Unversioned.make({ definition, revisions: [] }),
42
+ })
64
43
 
65
- // Should index Query and User types
66
- const queryRefs = getExampleReferencesForType(index, 'Query')
67
- const userRefs = getExampleReferencesForType(index, 'User')
44
+ const makeVersionedCatalog = (definition: GraphQLSchema, versions: Version.Version[]) =>
45
+ Catalog.Versioned.make({
46
+ entries: HashMap.make(
47
+ ...versions.map(v =>
48
+ [
49
+ v,
50
+ Schema.Versioned.make({
51
+ version: v,
52
+ definition,
53
+ branchPoint: null,
54
+ revisions: [],
55
+ }),
56
+ ] as const
57
+ ),
58
+ ),
59
+ })
68
60
 
69
- expect(HashSet.size(queryRefs)).toBe(1)
70
- expect([...queryRefs][0]).toEqual({ name: 'get-user', version: defaultVersion })
61
+ describe('createTypeUsageIndex', () => {
62
+ test.for([
63
+ { type: 'Query', shouldExist: true },
64
+ { type: 'User', shouldExist: true },
65
+ { type: 'Product', shouldExist: false },
66
+ ])('indexes unversioned example - type $type indexed=$shouldExist', ({ type, shouldExist }) => {
67
+ const example = Example.make({
68
+ name: 'get-user',
69
+ path: 'examples/get-user.graphql',
70
+ document: Document.Unversioned.make({
71
+ document: 'query { user(id: "1") { id name } }',
72
+ }),
73
+ })
71
74
 
72
- expect(HashSet.size(userRefs)).toBe(1)
73
- expect([...userRefs][0]).toEqual({ name: 'get-user', version: defaultVersion })
75
+ const index = createTypeUsageIndex([example], makeUnversionedCatalog(schemaDef))
76
+ const refs = getExampleReferencesForType(index, type)
74
77
 
75
- // Should not index Product type (not used)
76
- const productRefs = getExampleReferencesForType(index, 'Product')
77
- expect(HashSet.size(productRefs)).toBe(0)
78
- })
78
+ if (shouldExist) {
79
+ expect(HashSet.size(refs)).toBe(1)
80
+ expect([...refs][0]).toEqual({ name: 'get-user', version: null })
81
+ } else {
82
+ expect(HashSet.size(refs)).toBe(0)
83
+ }
84
+ })
79
85
 
80
- test('indexes versioned examples', () => {
86
+ test.for([version1, version2])(
87
+ 'indexes versioned examples for version %s',
88
+ (version) => {
81
89
  const example = Example.make({
82
90
  name: 'get-user-versioned',
83
91
  path: 'examples/get-user-versioned.graphql',
@@ -89,188 +97,98 @@ describe('type-usage-indexer', () => {
89
97
  }),
90
98
  })
91
99
 
92
- const catalog = Catalog.Versioned.make({
93
- entries: HashMap.make(
94
- [
95
- version1,
96
- Schema.Versioned.make({
97
- version: version1,
98
- definition: schemaDef,
99
- branchPoint: null,
100
- revisions: [],
101
- }),
102
- ],
103
- [
104
- version2,
105
- Schema.Versioned.make({
106
- version: version2,
107
- definition: schemaDef,
108
- branchPoint: null,
109
- revisions: [],
110
- }),
111
- ],
112
- ),
113
- })
114
-
115
- const index = createTypeUsageIndex([example], catalog)
116
-
117
- // Check version 1 references
118
- const userRefsV1 = getExampleReferencesForType(index, 'User', version1)
119
- expect(HashSet.size(userRefsV1)).toBe(1)
120
- expect([...userRefsV1][0]).toEqual({ name: 'get-user-versioned', version: version1 })
121
-
122
- // Check version 2 references
123
- const userRefsV2 = getExampleReferencesForType(index, 'User', version2)
124
- expect(HashSet.size(userRefsV2)).toBe(1)
125
- expect([...userRefsV2][0]).toEqual({ name: 'get-user-versioned', version: version2 })
126
- })
127
-
128
- test('deduplicates example references using HashSet', () => {
129
- // Create two examples that use the same types
130
- const example1 = Example.make({
131
- name: 'get-user-1',
132
- path: 'examples/get-user-1.graphql',
133
- document: Document.Unversioned.make({
134
- document: 'query { user(id: "1") { id name } }',
135
- }),
136
- })
100
+ const index = createTypeUsageIndex(
101
+ [example],
102
+ makeVersionedCatalog(schemaDef, [version1, version2]),
103
+ )
137
104
 
138
- const example2 = Example.make({
139
- name: 'get-user-2',
140
- path: 'examples/get-user-2.graphql',
105
+ const userRefs = getExampleReferencesForType(index, 'User', version)
106
+ expect(HashSet.size(userRefs)).toBe(1)
107
+ expect([...userRefs][0]).toEqual({ name: 'get-user-versioned', version })
108
+ },
109
+ )
110
+
111
+ test('deduplicates example references using HashSet', () => {
112
+ const examples = ['get-user-1', 'get-user-2'].map(name =>
113
+ Example.make({
114
+ name,
115
+ path: `examples/${name}.graphql`,
141
116
  document: Document.Unversioned.make({
142
- document: 'query { user(id: "2") { id name } }',
117
+ document: `query { user(id: "${name}") { id name } }`,
143
118
  }),
144
119
  })
120
+ )
145
121
 
146
- const catalog = Catalog.Unversioned.make({
147
- schema: Schema.Unversioned.make({
148
- definition: schemaDef,
149
- revisions: [],
150
- }),
151
- })
152
-
153
- const index = createTypeUsageIndex([example1, example2], catalog)
154
-
155
- // For unversioned examples with unversioned catalog, use default version
156
- const defaultVersion = Version.decodeSync('1.0.0')
122
+ const index = createTypeUsageIndex(examples, makeUnversionedCatalog(schemaDef))
123
+ const userRefs = getExampleReferencesForType(index, 'User')
157
124
 
158
- // Both examples should be indexed for User type
159
- const userRefs = getExampleReferencesForType(index, 'User')
160
- expect(HashSet.size(userRefs)).toBe(2)
161
-
162
- const refNames = [...userRefs].map(ref => ref.name).sort()
163
- expect(refNames).toEqual(['get-user-1', 'get-user-2'])
125
+ expect(HashSet.size(userRefs)).toBe(2)
126
+ expect([...userRefs].map(ref => ref.name).sort()).toEqual(['get-user-1', 'get-user-2'])
127
+ expect([...userRefs].every(ref => ref.version === null)).toBe(true)
128
+ })
164
129
 
165
- // All should have the same version
166
- for (const ref of userRefs) {
167
- expect(ref.version).toEqual(defaultVersion)
168
- }
130
+ test('handles interface and union types', () => {
131
+ const example = Example.make({
132
+ name: 'search',
133
+ path: 'examples/search.graphql',
134
+ document: Document.Unversioned.make({
135
+ document: `query { user(id: "1") { ... on Node { id } } }`,
136
+ }),
169
137
  })
170
138
 
171
- test('handles interface and union types', () => {
172
- const example = Example.make({
173
- name: 'search',
174
- path: 'examples/search.graphql',
175
- document: Document.Unversioned.make({
176
- document: `
177
- query {
178
- user(id: "1") {
179
- ... on Node {
180
- id
181
- }
182
- }
183
- }
184
- `,
185
- }),
186
- })
187
-
188
- const catalog = Catalog.Unversioned.make({
189
- schema: Schema.Unversioned.make({
190
- definition: schemaDef,
191
- revisions: [],
192
- }),
193
- })
194
-
195
- const index = createTypeUsageIndex([example], catalog)
139
+ const index = createTypeUsageIndex([example], makeUnversionedCatalog(schemaDef))
140
+ const nodeRefs = getExampleReferencesForType(index, 'Node')
196
141
 
197
- // For unversioned example with unversioned catalog
198
- const defaultVersion = Version.decodeSync('1.0.0')
142
+ expect(HashSet.size(nodeRefs)).toBe(1)
143
+ expect([...nodeRefs][0]).toEqual({ name: 'search', version: null })
144
+ })
199
145
 
200
- // Should index the Node interface
201
- const nodeRefs = getExampleReferencesForType(index, 'Node')
202
- expect(HashSet.size(nodeRefs)).toBe(1)
203
- expect([...nodeRefs][0]).toEqual({ name: 'search', version: defaultVersion })
146
+ test('indexes examples with version sets', () => {
147
+ const versionSet = HashSet.make(version1, version2)
148
+ const example = Example.make({
149
+ name: 'shared-example',
150
+ path: 'examples/shared.graphql',
151
+ document: Document.Versioned.make({
152
+ versionDocuments: HashMap.make([versionSet, 'query { user(id: "1") { id name } }']),
153
+ }),
204
154
  })
205
155
 
206
- test('indexes examples with version sets', () => {
207
- // Create a versioned document where multiple versions share the same document
208
- const versionSet = HashSet.make(version1, version2)
209
- const example = Example.make({
210
- name: 'shared-example',
211
- path: 'examples/shared.graphql',
212
- document: Document.Versioned.make({
213
- versionDocuments: HashMap.make(
214
- [versionSet, 'query { user(id: "1") { id name } }'],
215
- ),
216
- }),
217
- })
218
-
219
- const catalog = Catalog.Versioned.make({
220
- entries: HashMap.make(
221
- [
222
- version1,
223
- Schema.Versioned.make({
224
- version: version1,
225
- definition: schemaDef,
226
- branchPoint: null,
227
- revisions: [],
228
- }),
229
- ],
230
- [
231
- version2,
232
- Schema.Versioned.make({
233
- version: version2,
234
- definition: schemaDef,
235
- branchPoint: null,
236
- revisions: [],
237
- }),
238
- ],
239
- ),
240
- })
241
-
242
- const index = createTypeUsageIndex([example], catalog)
243
-
244
- // Both versions should have the same example reference
245
- const userRefsV1 = getExampleReferencesForType(index, 'User', version1)
246
- expect(HashSet.size(userRefsV1)).toBe(1)
247
- expect([...userRefsV1][0]).toEqual({ name: 'shared-example', version: version1 })
156
+ const index = createTypeUsageIndex(
157
+ [example],
158
+ makeVersionedCatalog(schemaDef, [version1, version2]),
159
+ )
248
160
 
249
- const userRefsV2 = getExampleReferencesForType(index, 'User', version2)
250
- expect(HashSet.size(userRefsV2)).toBe(1)
251
- expect([...userRefsV2][0]).toEqual({ name: 'shared-example', version: version2 })
252
- })
161
+ // Both versions should have the same example reference
162
+ for (const version of [version1, version2]) {
163
+ const userRefs = getExampleReferencesForType(index, 'User', version)
164
+ expect(HashSet.size(userRefs)).toBe(1)
165
+ expect([...userRefs][0]).toEqual({ name: 'shared-example', version })
166
+ }
253
167
  })
168
+ })
254
169
 
255
- describe('ExampleReference', () => {
256
- test('ExampleReference structural equality works with HashSet', () => {
257
- // Use the Schema's make constructor to create Data instances with proper Equal/Hash support
258
- const version = Version.decodeSync('1.0.0')
259
-
260
- const ref1 = ExampleReferenceModule.ExampleReference.make({ name: 'example1', version })
261
- const ref2 = ExampleReferenceModule.ExampleReference.make({ name: 'example1', version })
262
- const ref3 = ExampleReferenceModule.ExampleReference.make({ name: 'example2', version })
263
-
264
- // Create a HashSet and add references
265
- let set = HashSet.empty<ExampleReferenceModule.ExampleReference>()
266
- set = HashSet.add(set, ref1)
267
- set = HashSet.add(set, ref2) // Should not increase size (duplicate)
268
- set = HashSet.add(set, ref3)
269
-
270
- // Should have only 2 unique references
271
- expect(HashSet.size(set)).toBe(2)
272
- expect(HashSet.has(set, ExampleReferenceModule.ExampleReference.make({ name: 'example1', version }))).toBe(true)
273
- expect(HashSet.has(set, ExampleReferenceModule.ExampleReference.make({ name: 'example2', version }))).toBe(true)
274
- })
170
+ describe('ExampleReference', () => {
171
+ test('structural equality works with HashSet', () => {
172
+ const version = Version.decodeSync('1.0.0')
173
+
174
+ // Create set with duplicates to test deduplication
175
+ const refs = [
176
+ ExampleReference.make({ name: 'example1', version }),
177
+ ExampleReference.make({ name: 'example1', version }), // duplicate
178
+ ExampleReference.make({ name: 'example2', version }),
179
+ ExampleReference.make({ name: 'example3', version: null }),
180
+ ExampleReference.make({ name: 'example3', version: null }), // duplicate
181
+ ]
182
+
183
+ const set = refs.reduce(
184
+ (acc, ref) => HashSet.add(acc, ref),
185
+ HashSet.empty<ExampleReference>(),
186
+ )
187
+
188
+ // Should have only 3 unique references
189
+ expect(HashSet.size(set)).toBe(3)
190
+ expect(HashSet.has(set, ExampleReference.make({ name: 'example1', version }))).toBe(true)
191
+ expect(HashSet.has(set, ExampleReference.make({ name: 'example2', version }))).toBe(true)
192
+ expect(HashSet.has(set, ExampleReference.make({ name: 'example3', version: null }))).toBe(true)
275
193
  })
276
194
  })
@@ -1,19 +1,11 @@
1
1
  import { Catalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
+ import { Grafaid } from '#lib/grafaid'
4
+ import { Schema } from '#lib/schema/$'
3
5
  import { Version } from '#lib/version/$'
4
- import { HashMap, HashSet, Option } from 'effect'
6
+ import { Effect, HashMap, HashSet, Option } from 'effect'
5
7
  import { Schema as S } from 'effect'
6
- import {
7
- type DocumentNode,
8
- getNamedType,
9
- type GraphQLSchema,
10
- isInterfaceType,
11
- isObjectType,
12
- isUnionType,
13
- Kind,
14
- parse,
15
- visit,
16
- } from 'graphql'
8
+ import { getNamedType, type GraphQLSchema, isInterfaceType, isObjectType, isUnionType, Kind, visit } from 'graphql'
17
9
  import type { Example } from './schemas/example/example.js'
18
10
  import { ExampleReference, type TypeUsageIndex, UNVERSIONED_KEY, type VersionKey } from './schemas/type-usage-index.js'
19
11
 
@@ -30,20 +22,17 @@ import { ExampleReference, type TypeUsageIndex, UNVERSIONED_KEY, type VersionKey
30
22
  * - For interfaces: both the interface and all implementations
31
23
  * - For unions: both the union and all member types
32
24
  */
33
- const extractTypesFromQuery = (
25
+ const extractTypesFromDocument = (
34
26
  documentString: string,
35
27
  schema: GraphQLSchema,
36
28
  ): Set<string> => {
37
29
  const types = new Set<string>()
38
30
  const visitedTypes = new Set<string>() // Prevent infinite recursion
39
31
 
40
- let ast: DocumentNode
41
- try {
42
- ast = parse(documentString)
43
- } catch {
44
- // If parsing fails, return empty set
45
- return types
46
- }
32
+ // Use Effect to parse, but handle it synchronously since this function is synchronous
33
+ const ast = Effect.runSync(
34
+ Grafaid.Parse.parseDocument(documentString, { source: 'example' }),
35
+ )
47
36
 
48
37
  // Helper to add a type and its related types
49
38
  const addType = (typeName: string) => {
@@ -164,6 +153,43 @@ const extractTypesFromQuery = (
164
153
  // Index Creation
165
154
  // ============================================================================
166
155
 
156
+ /**
157
+ * Process a document version and add its type usage to the index.
158
+ *
159
+ * @param example - The example being processed
160
+ * @param documentContent - The document content to extract types from
161
+ * @param schema - The schema containing version and definition
162
+ * @param hashMap - The current type usage index
163
+ * @returns Updated type usage index
164
+ */
165
+ const processDocumentVersion = (
166
+ example: Example,
167
+ documentContent: string,
168
+ schema: Schema.Schema,
169
+ hashMap: TypeUsageIndex,
170
+ ): TypeUsageIndex => {
171
+ const types = extractTypesFromDocument(documentContent, schema.definition)
172
+
173
+ // Get version from schema (null for unversioned)
174
+ const version = Schema.getVersion(schema) ?? null
175
+
176
+ // Map to storage key: use version or UNVERSIONED_KEY
177
+ const versionKey: VersionKey = version ?? UNVERSIONED_KEY
178
+
179
+ // Create reference with nullable version
180
+ const exampleRef = ExampleReference.make({
181
+ name: example.name,
182
+ version,
183
+ })
184
+
185
+ let updatedMap = hashMap
186
+ for (const typeName of types) {
187
+ updatedMap = addExampleToIndex(updatedMap, versionKey, typeName, exampleRef)
188
+ }
189
+
190
+ return updatedMap
191
+ }
192
+
167
193
  /**
168
194
  * Create a type usage index from examples and schemas.
169
195
  *
@@ -177,44 +203,34 @@ export const createTypeUsageIndex = (
177
203
  let hashMap = HashMap.empty<VersionKey, HashMap.HashMap<string, HashSet.HashSet<ExampleReference>>>()
178
204
 
179
205
  for (const example of examples) {
180
- // Process based on document type
181
206
  if (Document.Unversioned.is(example.document)) {
182
- // Unversioned document
207
+ // For unversioned: get latest schema from catalog
183
208
  const schema = Catalog.getLatest(schemasCatalog)
184
- const types = extractTypesFromQuery(example.document.document, schema.definition)
185
-
186
- for (const typeName of types) {
187
- // For unversioned, use the latest version from the catalog
188
- const latestVersion = Option.getOrElse(
189
- Catalog.getLatestVersion(schemasCatalog),
190
- () => Version.fromString('1.0.0'),
191
- )
192
- hashMap = addExampleToIndex(hashMap, UNVERSIONED_KEY, typeName, example, latestVersion)
193
- }
209
+ hashMap = processDocumentVersion(
210
+ example,
211
+ example.document.document,
212
+ schema,
213
+ hashMap,
214
+ )
194
215
  } else if (Document.Versioned.is(example.document)) {
195
- // Versioned document - process each version covered
216
+ // For versioned: process each version
196
217
  const allVersions = Document.Versioned.getAllVersions(example.document)
197
218
 
198
219
  for (const version of allVersions) {
199
- // Use centralized resolution to get schema for version
200
220
  const schemaOption = Option.liftThrowable(
201
221
  () => Catalog.resolveCatalogSchema(schemasCatalog, version),
202
222
  )()
203
- if (Option.isNone(schemaOption)) {
204
- // Skip if version not found in catalog
205
- continue
206
- }
207
- const schema = schemaOption.value
208
-
209
- const documentStringOption = Document.Versioned.getContentForVersion(example.document, version)
210
- if (Option.isNone(documentStringOption)) continue
211
- const documentString = documentStringOption.value
223
+ if (Option.isNone(schemaOption)) continue
212
224
 
213
- const types = extractTypesFromQuery(documentString, schema.definition)
225
+ const documentOption = Document.Versioned.getContentForVersion(example.document, version)
226
+ if (Option.isNone(documentOption)) continue
214
227
 
215
- for (const typeName of types) {
216
- hashMap = addExampleToIndex(hashMap, version, typeName, example, version)
217
- }
228
+ hashMap = processDocumentVersion(
229
+ example,
230
+ documentOption.value,
231
+ schemaOption.value,
232
+ hashMap,
233
+ )
218
234
  }
219
235
  }
220
236
  }
@@ -229,12 +245,8 @@ const addExampleToIndex = (
229
245
  index: TypeUsageIndex,
230
246
  versionKey: VersionKey,
231
247
  typeName: string,
232
- example: Example,
233
- version: Version.Version,
248
+ exampleRef: ExampleReference,
234
249
  ): TypeUsageIndex => {
235
- // Create lightweight reference using the schema's make constructor
236
- const exampleRef = ExampleReference.make({ name: example.name, version })
237
-
238
250
  // Get or create the version's type map
239
251
  const versionMap = HashMap.get(index, versionKey).pipe(
240
252
  Option.getOrElse(HashMap.empty<string, HashSet.HashSet<S.Schema.Type<typeof ExampleReference>>>),
@@ -112,7 +112,7 @@ const createTestConfig = (overrides?: Partial<Config.Config>): Config.Config =>
112
112
  // Helper to build GraphQL schema using Grafaid to avoid realm issues
113
113
  const buildSchemaWithGrafaid = (sdl: string) =>
114
114
  Effect.gen(function*() {
115
- const ast = yield* Grafaid.Schema.AST.parse(sdl)
115
+ const ast = yield* Grafaid.Parse.parseSchema(sdl, { source: 'test' })
116
116
  return yield* Grafaid.Schema.fromAST(ast)
117
117
  })
118
118
 
@@ -186,11 +186,11 @@ const read = (
186
186
  Effect.gen(function*() {
187
187
  const fs = yield* FileSystem
188
188
  const content = yield* fs.readFileString(revisionInput.filePath)
189
- const ast = yield* Grafaid.Schema.AST.parse(content).pipe(
189
+ const ast = yield* Grafaid.Parse.parseSchema(content, { source: revisionInput.filePath }).pipe(
190
190
  Effect.mapError((error) =>
191
191
  new InputSourceError({
192
192
  source: 'directory',
193
- message: `Failed to parse schema file ${revisionInput.filePath}: ${error}`,
193
+ message: error.message,
194
194
  cause: error,
195
195
  })
196
196
  ),
@@ -199,7 +199,7 @@ const read = (
199
199
  Effect.mapError((error) =>
200
200
  new InputSourceError({
201
201
  source: 'directory',
202
- message: `Failed to build schema from ${revisionInput.filePath}: ${error}`,
202
+ message: error.message,
203
203
  cause: error,
204
204
  })
205
205
  ),
@@ -73,11 +73,11 @@ export const loader = InputSource.createEffect({
73
73
  const fs = yield* FileSystem
74
74
  const content = yield* fs.readFileString(config.path)
75
75
 
76
- const ast = yield* Grafaid.Schema.AST.parse(content).pipe(
76
+ const ast = yield* Grafaid.Parse.parseSchema(content, { source: config.path }).pipe(
77
77
  Effect.mapError((error) =>
78
78
  new InputSource.InputSourceError({
79
79
  source: 'file',
80
- message: `Failed to parse schema file: ${error}`,
80
+ message: error.message,
81
81
  cause: error,
82
82
  })
83
83
  ),
@@ -86,7 +86,7 @@ export const loader = InputSource.createEffect({
86
86
  Effect.mapError((error) =>
87
87
  new InputSource.InputSourceError({
88
88
  source: 'file',
89
- message: `Failed to build schema: ${error}`,
89
+ message: error.message,
90
90
  cause: error,
91
91
  })
92
92
  ),