polen 0.11.0-next.17 → 0.11.0-next.18

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 (196) hide show
  1. package/build/api/builder/ssg/generate.d.ts.map +1 -1
  2. package/build/api/builder/ssg/generate.js +5 -5
  3. package/build/api/builder/ssg/generate.js.map +1 -1
  4. package/build/api/builder/ssg/page-generator.worker.js +13 -3
  5. package/build/api/builder/ssg/page-generator.worker.js.map +1 -1
  6. package/build/api/config/input.d.ts +88 -3
  7. package/build/api/config/input.d.ts.map +1 -1
  8. package/build/api/config/normalized.d.ts +92 -7
  9. package/build/api/config/normalized.d.ts.map +1 -1
  10. package/build/api/config/normalized.js +11 -3
  11. package/build/api/config/normalized.js.map +1 -1
  12. package/build/api/config-template/template.js +2 -2
  13. package/build/api/config-template/template.js.map +1 -1
  14. package/build/api/content/sidebar.d.ts.map +1 -1
  15. package/build/api/content/sidebar.js +2 -1
  16. package/build/api/content/sidebar.js.map +1 -1
  17. package/build/api/examples/config.d.ts +366 -3
  18. package/build/api/examples/config.d.ts.map +1 -1
  19. package/build/api/examples/config.js +25 -3
  20. package/build/api/examples/config.js.map +1 -1
  21. package/build/api/examples/diagnostic/diagnostic.d.ts +1 -1
  22. package/build/api/examples/diagnostic/validation-error.d.ts +3 -2
  23. package/build/api/examples/diagnostic/validation-error.d.ts.map +1 -1
  24. package/build/api/examples/diagnostic/validation-error.js +9 -3
  25. package/build/api/examples/diagnostic/validation-error.js.map +1 -1
  26. package/build/api/examples/diagnostic/validator.d.ts.map +1 -1
  27. package/build/api/examples/diagnostic/validator.js +115 -68
  28. package/build/api/examples/diagnostic/validator.js.map +1 -1
  29. package/build/api/examples/filter.d.ts.map +1 -1
  30. package/build/api/examples/filter.js +9 -6
  31. package/build/api/examples/filter.js.map +1 -1
  32. package/build/api/examples/scanner.d.ts.map +1 -1
  33. package/build/api/examples/scanner.js +89 -103
  34. package/build/api/examples/scanner.js.map +1 -1
  35. package/build/api/examples/type-usage-indexer.d.ts.map +1 -1
  36. package/build/api/examples/type-usage-indexer.js +17 -30
  37. package/build/api/examples/type-usage-indexer.js.map +1 -1
  38. package/build/api/iso/schema/routing.d.ts.map +1 -1
  39. package/build/api/iso/schema/routing.js +8 -8
  40. package/build/api/iso/schema/routing.js.map +1 -1
  41. package/build/api/iso/schema/validation.d.ts.map +1 -1
  42. package/build/api/iso/schema/validation.js +3 -2
  43. package/build/api/iso/schema/validation.js.map +1 -1
  44. package/build/api/schema/input-sources/directory.js +2 -2
  45. package/build/api/schema/input-sources/directory.js.map +1 -1
  46. package/build/api/schema/input-sources/versioned-directory.d.ts.map +1 -1
  47. package/build/api/schema/input-sources/versioned-directory.js +3 -3
  48. package/build/api/schema/input-sources/versioned-directory.js.map +1 -1
  49. package/build/api/schema/load.d.ts.map +1 -1
  50. package/build/api/schema/load.js +1 -1
  51. package/build/api/schema/load.js.map +1 -1
  52. package/build/lib/catalog/catalog.d.ts +43 -3
  53. package/build/lib/catalog/catalog.d.ts.map +1 -1
  54. package/build/lib/catalog/catalog.js +67 -5
  55. package/build/lib/catalog/catalog.js.map +1 -1
  56. package/build/lib/catalog/versioned.d.ts +11 -1
  57. package/build/lib/catalog/versioned.d.ts.map +1 -1
  58. package/build/lib/catalog/versioned.js +23 -5
  59. package/build/lib/catalog/versioned.js.map +1 -1
  60. package/build/lib/document/document.d.ts +55 -5
  61. package/build/lib/document/document.d.ts.map +1 -1
  62. package/build/lib/document/document.js +96 -2
  63. package/build/lib/document/document.js.map +1 -1
  64. package/build/lib/document/versioned.d.ts +2 -2
  65. package/build/lib/document/versioned.d.ts.map +1 -1
  66. package/build/lib/document/versioned.js +7 -7
  67. package/build/lib/document/versioned.js.map +1 -1
  68. package/build/lib/lifecycles/lifecycles.d.ts +5 -4
  69. package/build/lib/lifecycles/lifecycles.d.ts.map +1 -1
  70. package/build/lib/lifecycles/lifecycles.js +14 -12
  71. package/build/lib/lifecycles/lifecycles.js.map +1 -1
  72. package/build/lib/version-coverage/$$.d.ts +2 -0
  73. package/build/lib/version-coverage/$$.d.ts.map +1 -0
  74. package/build/lib/version-coverage/$$.js +2 -0
  75. package/build/lib/version-coverage/$$.js.map +1 -0
  76. package/build/lib/version-coverage/$.d.ts.map +1 -0
  77. package/build/lib/version-coverage/$.js.map +1 -0
  78. package/build/lib/{version-selection/version-selection.d.ts → version-coverage/version-coverage.d.ts} +1 -1
  79. package/build/lib/version-coverage/version-coverage.d.ts.map +1 -0
  80. package/build/lib/{version-selection/version-selection.js → version-coverage/version-coverage.js} +2 -2
  81. package/build/lib/version-coverage/version-coverage.js.map +1 -0
  82. package/build/template/components/GraphQLDocument.d.ts +1 -1
  83. package/build/template/components/GraphQLDocument.d.ts.map +1 -1
  84. package/build/template/components/GraphQLDocument.js +10 -39
  85. package/build/template/components/GraphQLDocument.js.map +1 -1
  86. package/build/template/components/GraphQLInteractive/lib/parser.d.ts +28 -0
  87. package/build/template/components/GraphQLInteractive/lib/parser.d.ts.map +1 -1
  88. package/build/template/components/GraphQLInteractive/lib/parser.js +60 -27
  89. package/build/template/components/GraphQLInteractive/lib/parser.js.map +1 -1
  90. package/build/template/components/VersionCoveragePicker.d.ts +1 -1
  91. package/build/template/components/VersionCoveragePicker.d.ts.map +1 -1
  92. package/build/template/components/VersionCoveragePicker.js +4 -6
  93. package/build/template/components/VersionCoveragePicker.js.map +1 -1
  94. package/build/template/components/home/QuickStart.d.ts.map +1 -1
  95. package/build/template/components/home/QuickStart.js +8 -4
  96. package/build/template/components/home/QuickStart.js.map +1 -1
  97. package/build/template/hooks/use-highlighted.d.ts.map +1 -1
  98. package/build/template/hooks/use-highlighted.js +19 -13
  99. package/build/template/hooks/use-highlighted.js.map +1 -1
  100. package/build/template/lib/fetch-text.d.ts +18 -0
  101. package/build/template/lib/fetch-text.d.ts.map +1 -1
  102. package/build/template/lib/fetch-text.js +32 -4
  103. package/build/template/lib/fetch-text.js.map +1 -1
  104. package/build/template/routes/examples/name.d.ts.map +1 -1
  105. package/build/template/routes/examples/name.js +4 -2
  106. package/build/template/routes/examples/name.js.map +1 -1
  107. package/build/template/stores/toast.d.ts.map +1 -1
  108. package/build/template/stores/toast.js +5 -3
  109. package/build/template/stores/toast.js.map +1 -1
  110. package/package.json +7 -7
  111. package/src/api/builder/ssg/generate.ts +10 -5
  112. package/src/api/builder/ssg/page-generator.worker.ts +18 -3
  113. package/src/api/config/normalized.ts +12 -3
  114. package/src/api/config-template/template.ts +2 -2
  115. package/src/api/content/sidebar.ts +3 -3
  116. package/src/api/examples/config.test.ts +10 -0
  117. package/src/api/examples/config.ts +33 -4
  118. package/src/api/examples/diagnostic/validation-error.ts +9 -3
  119. package/src/api/examples/diagnostic/validator.test.ts +30 -0
  120. package/src/api/examples/diagnostic/validator.ts +148 -103
  121. package/src/api/examples/filter.ts +9 -6
  122. package/src/api/examples/scanner.ts +136 -117
  123. package/src/api/examples/type-usage-indexer.ts +24 -36
  124. package/src/api/iso/schema/routing.ts +10 -10
  125. package/src/api/iso/schema/validation.ts +3 -2
  126. package/src/api/schema/input-sources/directory.ts +2 -2
  127. package/src/api/schema/input-sources/versioned-directory.ts +5 -7
  128. package/src/api/schema/load.ts +1 -1
  129. package/src/lib/catalog/catalog.ts +89 -6
  130. package/src/lib/catalog/versioned.ts +26 -5
  131. package/src/lib/document/document.ts +135 -2
  132. package/src/lib/document/versioned.ts +8 -8
  133. package/src/lib/lifecycles/lifecycles.ts +32 -27
  134. package/src/lib/version-coverage/$$.ts +1 -0
  135. package/src/lib/{version-selection/version-selection.ts → version-coverage/version-coverage.ts} +1 -1
  136. package/src/template/components/GraphQLDocument.tsx +11 -69
  137. package/src/template/components/GraphQLInteractive/lib/parser.ts +81 -29
  138. package/src/template/components/VersionCoveragePicker.tsx +4 -5
  139. package/src/template/components/home/QuickStart.tsx +16 -7
  140. package/src/template/hooks/use-highlighted.ts +31 -19
  141. package/src/template/lib/fetch-text.ts +45 -4
  142. package/src/template/routes/examples/name.tsx +4 -2
  143. package/src/template/stores/toast.ts +6 -3
  144. package/build/lib/graph/$$.d.ts +0 -2
  145. package/build/lib/graph/$$.d.ts.map +0 -1
  146. package/build/lib/graph/$$.js +0 -2
  147. package/build/lib/graph/$$.js.map +0 -1
  148. package/build/lib/graph/$.d.ts +0 -2
  149. package/build/lib/graph/$.d.ts.map +0 -1
  150. package/build/lib/graph/$.js +0 -2
  151. package/build/lib/graph/$.js.map +0 -1
  152. package/build/lib/graph/graph.d.ts +0 -127
  153. package/build/lib/graph/graph.d.ts.map +0 -1
  154. package/build/lib/graph/graph.js +0 -152
  155. package/build/lib/graph/graph.js.map +0 -1
  156. package/build/lib/mask/$$.d.ts +0 -3
  157. package/build/lib/mask/$$.d.ts.map +0 -1
  158. package/build/lib/mask/$$.js +0 -3
  159. package/build/lib/mask/$$.js.map +0 -1
  160. package/build/lib/mask/$.d.ts +0 -2
  161. package/build/lib/mask/$.d.ts.map +0 -1
  162. package/build/lib/mask/$.js +0 -2
  163. package/build/lib/mask/$.js.map +0 -1
  164. package/build/lib/mask/apply.d.ts +0 -86
  165. package/build/lib/mask/apply.d.ts.map +0 -1
  166. package/build/lib/mask/apply.js +0 -86
  167. package/build/lib/mask/apply.js.map +0 -1
  168. package/build/lib/mask/mask.d.ts +0 -124
  169. package/build/lib/mask/mask.d.ts.map +0 -1
  170. package/build/lib/mask/mask.js +0 -137
  171. package/build/lib/mask/mask.js.map +0 -1
  172. package/build/lib/mask/mask.test-d.d.ts +0 -2
  173. package/build/lib/mask/mask.test-d.d.ts.map +0 -1
  174. package/build/lib/mask/mask.test-d.js +0 -102
  175. package/build/lib/mask/mask.test-d.js.map +0 -1
  176. package/build/lib/version-selection/$$.d.ts +0 -2
  177. package/build/lib/version-selection/$$.d.ts.map +0 -1
  178. package/build/lib/version-selection/$$.js +0 -2
  179. package/build/lib/version-selection/$$.js.map +0 -1
  180. package/build/lib/version-selection/$.d.ts.map +0 -1
  181. package/build/lib/version-selection/$.js.map +0 -1
  182. package/build/lib/version-selection/version-selection.d.ts.map +0 -1
  183. package/build/lib/version-selection/version-selection.js.map +0 -1
  184. package/src/lib/graph/$$.ts +0 -1
  185. package/src/lib/graph/$.ts +0 -1
  186. package/src/lib/graph/graph.ts +0 -197
  187. package/src/lib/mask/$$.ts +0 -2
  188. package/src/lib/mask/$.test.ts +0 -226
  189. package/src/lib/mask/$.ts +0 -1
  190. package/src/lib/mask/apply.ts +0 -134
  191. package/src/lib/mask/mask.test-d.ts +0 -156
  192. package/src/lib/mask/mask.ts +0 -244
  193. package/src/lib/version-selection/$$.ts +0 -1
  194. /package/build/lib/{version-selection → version-coverage}/$.d.ts +0 -0
  195. /package/build/lib/{version-selection → version-coverage}/$.js +0 -0
  196. /package/src/lib/{version-selection → version-coverage}/$.ts +0 -0
@@ -1,13 +1,33 @@
1
1
  import { S } from '#lib/kit-temp/effect'
2
2
  import { Schema } from '#lib/schema/$'
3
+ import { VersionCoverage } from '#lib/version-coverage'
3
4
  import { Version } from '#lib/version/$'
4
- import { HashMap, Match } from 'effect'
5
+ import { Data, Either, HashMap, Match, Option } from 'effect'
5
6
  import * as Unversioned from './unversioned.js'
6
7
  import * as Versioned from './versioned.js'
7
8
 
8
9
  export * as Unversioned from './unversioned.js'
9
10
  export * as Versioned from './versioned.js'
10
11
 
12
+ // ============================================================================
13
+ // Error Types
14
+ // ============================================================================
15
+
16
+ /**
17
+ * Error thrown when a version is not found in the catalog
18
+ */
19
+ export class VersionNotFoundInCatalogError extends Data.TaggedError('VersionNotFoundInCatalogError')<{
20
+ readonly version: string
21
+ readonly reason: string
22
+ }> {}
23
+
24
+ /**
25
+ * Error thrown when a catalog has no entries
26
+ */
27
+ export class EmptyCatalogError extends Data.TaggedError('EmptyCatalogError')<{
28
+ readonly reason: string
29
+ }> {}
30
+
11
31
  // ============================================================================
12
32
  // Schema
13
33
  // ============================================================================
@@ -87,14 +107,77 @@ export const getLatest = (catalog: Catalog): Schema.Schema =>
87
107
 
88
108
  /**
89
109
  * Get the latest version identifier from a catalog.
90
- * Returns the version for versioned catalogs, or null for unversioned catalogs.
110
+ * Returns the version for versioned catalogs, or none for unversioned catalogs.
91
111
  */
92
- export const getLatestVersion = (catalog?: Catalog): Version.Version | null => {
93
- if (!catalog) return null
112
+ export const getLatestVersion = (catalog?: Catalog): Option.Option<Version.Version> => {
113
+ if (!catalog) return Option.none()
94
114
  return Match.value(catalog).pipe(
95
115
  Match.tagsExhaustive({
96
- CatalogUnversioned: () => null,
97
- CatalogVersioned: (cat) => Versioned.getVersions(cat)[0] ?? null,
116
+ CatalogUnversioned: () => Option.none(),
117
+ CatalogVersioned: (cat) => {
118
+ const versions = Versioned.getVersions(cat)
119
+ return versions[0] ? Option.some(versions[0]) : Option.none()
120
+ },
98
121
  }),
99
122
  )
100
123
  }
124
+
125
+ // ============================================================================
126
+ // Resolution Functions
127
+ // ============================================================================
128
+
129
+ /**
130
+ * Resolve schema from catalog for a given version coverage.
131
+ *
132
+ * @param catalog - The schema catalog
133
+ * @param versionCoverage - The version coverage to use (optional, defaults to latest)
134
+ * @returns Either with the resolved schema or error
135
+ */
136
+ export const resolveCatalogSchemaEither = (
137
+ catalog: Catalog,
138
+ versionCoverage?: VersionCoverage.VersionCoverage | null,
139
+ ): Either.Either<Schema.Schema, VersionNotFoundInCatalogError | EmptyCatalogError> => {
140
+ if (Unversioned.is(catalog)) {
141
+ return Either.right(catalog.schema)
142
+ }
143
+
144
+ // If no version coverage specified, use latest
145
+ if (!versionCoverage) {
146
+ return Versioned.getLatest(catalog)
147
+ }
148
+
149
+ // Get the latest version from the coverage
150
+ const version = VersionCoverage.getLatest(versionCoverage)
151
+
152
+ const schemaOption = HashMap.get(catalog.entries, version)
153
+ if (Option.isNone(schemaOption)) {
154
+ return Either.left(
155
+ new VersionNotFoundInCatalogError({
156
+ version: Version.encodeSync(version),
157
+ reason: `Version ${Version.encodeSync(version)} not found in catalog`,
158
+ }),
159
+ )
160
+ }
161
+
162
+ return Either.right(Option.getOrThrow(schemaOption))
163
+ }
164
+
165
+ /**
166
+ * Resolve schema from catalog for a given version coverage.
167
+ *
168
+ * @param catalog - The schema catalog
169
+ * @param versionCoverage - The version coverage to use (optional, defaults to latest)
170
+ * @returns The resolved schema
171
+ * @throws {Error} If catalog is versioned but version is not found
172
+ * @deprecated Use resolveCatalogSchemaEither which returns Either
173
+ */
174
+ export const resolveCatalogSchema = (
175
+ catalog: Catalog,
176
+ versionCoverage?: VersionCoverage.VersionCoverage | null,
177
+ ): Schema.Schema => {
178
+ const result = resolveCatalogSchemaEither(catalog, versionCoverage)
179
+ if (Either.isLeft(result)) {
180
+ throw new Error(result.left.reason)
181
+ }
182
+ return result.right
183
+ }
@@ -1,7 +1,8 @@
1
1
  import { S } from '#lib/kit-temp/effect'
2
- import { Array, HashMap, Iterable, Order, pipe } from 'effect'
2
+ import { Array, Either, HashMap, Iterable, Order, pipe } from 'effect'
3
3
  import { Schema } from '../schema/$.js'
4
4
  import { Version } from '../version/$.js'
5
+ import { EmptyCatalogError } from './catalog.js'
5
6
 
6
7
  // ============================================================================
7
8
  // Schema
@@ -50,6 +51,25 @@ export const equivalence = S.equivalence(Versioned)
50
51
  // Domain Logic
51
52
  // ============================================================================
52
53
 
54
+ /**
55
+ * Get the latest schema from a versioned catalog.
56
+ * The latest version is determined by Version.max comparison.
57
+ *
58
+ * @param catalog - The versioned catalog
59
+ * @returns Either with the latest schema or EmptyCatalogError
60
+ */
61
+ export const getLatest = (catalog: Versioned): Either.Either<Schema.Versioned.Versioned, EmptyCatalogError> => {
62
+ const schema = getAll(catalog)[0]
63
+ if (!schema) {
64
+ return Either.left(
65
+ new EmptyCatalogError({
66
+ reason: 'Versioned catalog has no entries - cannot get latest schema',
67
+ }),
68
+ )
69
+ }
70
+ return Either.right(schema)
71
+ }
72
+
53
73
  /**
54
74
  * Get the latest schema definition from a versioned catalog.
55
75
  * The latest version is determined by Version.max comparison.
@@ -57,13 +77,14 @@ export const equivalence = S.equivalence(Versioned)
57
77
  * @param catalog - The versioned catalog
58
78
  * @returns The GraphQL schema definition of the latest version
59
79
  * @throws {Error} If the catalog has no entries
80
+ * @deprecated Use getLatest which returns Either
60
81
  */
61
82
  export const getLatestOrThrow = (catalog: Versioned): Schema.Versioned.Versioned => {
62
- const schema = getAll(catalog)[0]
63
- if (!schema) {
64
- throw new Error('Versioned catalog has no entries - cannot get latest schema')
83
+ const result = getLatest(catalog)
84
+ if (Either.isLeft(result)) {
85
+ throw new Error(result.left.reason)
65
86
  }
66
- return schema
87
+ return result.right
67
88
  }
68
89
 
69
90
  /**
@@ -1,6 +1,30 @@
1
+ import { Catalog } from '#lib/catalog/$'
1
2
  import { S } from '#lib/kit-temp/effect'
3
+ import { Schema } from '#lib/schema/$'
4
+ import { VersionCoverage } from '#lib/version-coverage'
5
+ import { Version } from '#lib/version/$'
6
+ import { Data, Either, Option } from 'effect'
2
7
  import { DocumentUnversioned } from './unversioned.js'
3
- import { DocumentVersioned } from './versioned.js'
8
+ import * as DocumentVersioned from './versioned.js'
9
+
10
+ // ============================================================================
11
+ // Error Types
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Error thrown when trying to use version coverage with an unversioned catalog
16
+ */
17
+ export class VersionCoverageMismatchError extends Data.TaggedError('VersionCoverageMismatchError')<{
18
+ readonly reason: string
19
+ }> {}
20
+
21
+ /**
22
+ * Error thrown when a version is not found in the document
23
+ */
24
+ export class VersionNotFoundInDocumentError extends Data.TaggedError('VersionNotFoundInDocumentError')<{
25
+ readonly version: string
26
+ readonly reason: string
27
+ }> {}
4
28
 
5
29
  // ============================================================================
6
30
  // Schema
@@ -13,7 +37,7 @@ import { DocumentVersioned } from './versioned.js'
13
37
  */
14
38
  export const Document = S.Union(
15
39
  DocumentUnversioned,
16
- DocumentVersioned,
40
+ DocumentVersioned.DocumentVersioned,
17
41
  )
18
42
 
19
43
  // ============================================================================
@@ -35,3 +59,112 @@ export const is = S.is(Document)
35
59
  export const decode = S.decode(Document)
36
60
  export const decodeSync = S.decodeSync(Document)
37
61
  export const encode = S.encode(Document)
62
+
63
+ // ============================================================================
64
+ // Domain Logic - Resolution Functions
65
+ // ============================================================================
66
+
67
+ /**
68
+ * Resolve document content for a given version coverage.
69
+ *
70
+ * @param document - The document to resolve content from
71
+ * @param versionCoverage - The version coverage to use (optional, defaults to latest)
72
+ * @returns The resolved document content
73
+ * @throws {Error} If version is not found in document
74
+ */
75
+ export const resolveDocumentContent = (
76
+ document: Document,
77
+ versionCoverage?: VersionCoverage.VersionCoverage | null,
78
+ ): string => {
79
+ if (document._tag === 'DocumentUnversioned') {
80
+ return document.document
81
+ }
82
+
83
+ // If no version coverage specified, use latest
84
+ if (!versionCoverage) {
85
+ return DocumentVersioned.getContentForLatestVersionOrThrow(document)
86
+ }
87
+
88
+ // Get the latest version from the coverage
89
+ const version = VersionCoverage.getLatest(versionCoverage)
90
+ const contentOption = DocumentVersioned.getContentForVersion(document, version)
91
+
92
+ if (Option.isNone(contentOption)) {
93
+ throw new VersionNotFoundInDocumentError({
94
+ version: Version.encodeSync(version),
95
+ reason: `Version ${Version.encodeSync(version)} not covered by document`,
96
+ })
97
+ }
98
+
99
+ return contentOption.value
100
+ }
101
+
102
+ /**
103
+ * Resolve both document content and schema for a given version coverage.
104
+ * This is the primary resolution function that handles all combinations
105
+ * of versioned/unversioned documents and catalogs.
106
+ *
107
+ * @param document - The document to resolve content from
108
+ * @param catalog - The schema catalog (optional)
109
+ * @param versionCoverage - The version coverage to use (optional, defaults to latest)
110
+ * @returns Either with resolved content and optional schema, or error
111
+ */
112
+ export const resolveDocumentAndSchema = (
113
+ document: Document,
114
+ catalog?: Catalog.Catalog,
115
+ versionCoverage?: VersionCoverage.VersionCoverage | null,
116
+ ): Either.Either<
117
+ { content: string; schema?: Schema.Schema },
118
+ | VersionCoverageMismatchError
119
+ | VersionNotFoundInDocumentError
120
+ | Catalog.VersionNotFoundInCatalogError
121
+ | Catalog.EmptyCatalogError
122
+ > => {
123
+ // Handle unversioned document
124
+ if (document._tag === 'DocumentUnversioned') {
125
+ const content = document.document
126
+
127
+ if (!catalog) {
128
+ return Either.right({ content })
129
+ }
130
+
131
+ return Catalog.resolveCatalogSchemaEither(catalog, null).pipe(
132
+ Either.map(schema => ({ content, schema })),
133
+ )
134
+ }
135
+
136
+ // Handle versioned document
137
+ let content: string
138
+ try {
139
+ content = resolveDocumentContent(document, versionCoverage)
140
+ } catch (error) {
141
+ // resolveDocumentContent throws our tagged error
142
+ if (error instanceof VersionNotFoundInDocumentError) {
143
+ return Either.left(error)
144
+ }
145
+ // This shouldn't happen but handle gracefully
146
+ return Either.left(
147
+ new VersionNotFoundInDocumentError({
148
+ version: String(versionCoverage),
149
+ reason: error instanceof Error ? error.message : String(error),
150
+ }),
151
+ )
152
+ }
153
+
154
+ if (!catalog) {
155
+ return Either.right({ content })
156
+ }
157
+
158
+ // Cannot use version coverage with unversioned catalog
159
+ if (versionCoverage && Catalog.Unversioned.is(catalog)) {
160
+ return Either.left(
161
+ new VersionCoverageMismatchError({
162
+ reason: 'Cannot use a version coverage with an unversioned catalog',
163
+ }),
164
+ )
165
+ }
166
+
167
+ return Catalog.resolveCatalogSchemaEither(catalog, versionCoverage).pipe(
168
+ Either.map(schema => ({ content, schema })),
169
+ )
170
+ }
@@ -1,5 +1,5 @@
1
1
  import { S } from '#lib/kit-temp/effect'
2
- import { VersionCoverage } from '#lib/version-selection/$'
2
+ import { VersionCoverage } from '#lib/version-coverage'
3
3
  import { Version } from '#lib/version/$'
4
4
  import { HashMap, Option } from 'effect'
5
5
 
@@ -56,21 +56,21 @@ export const encode = S.encode(DocumentVersioned)
56
56
  export const getContentForVersion = (
57
57
  doc: DocumentVersioned,
58
58
  version: Version.Version,
59
- ): string | null => {
59
+ ): Option.Option<string> => {
60
60
  // Try exact match first (single version key)
61
61
  const exactMatch = HashMap.get(doc.versionDocuments, version)
62
62
  if (Option.isSome(exactMatch)) {
63
- return exactMatch.value
63
+ return Option.some(exactMatch.value)
64
64
  }
65
65
 
66
66
  // Check version sets
67
67
  for (const [selection, content] of HashMap.entries(doc.versionDocuments)) {
68
68
  if (VersionCoverage.isSet(selection) && VersionCoverage.contains(selection, version)) {
69
- return content
69
+ return Option.some(content)
70
70
  }
71
71
  }
72
72
 
73
- return null
73
+ return Option.none()
74
74
  }
75
75
 
76
76
  /**
@@ -98,9 +98,9 @@ export const getContentForLatestVersionOrThrow = (doc: DocumentVersioned): strin
98
98
  // Use Version.max with reduce to find the latest version
99
99
  const latestVersion = versions.reduce(Version.max)
100
100
 
101
- const content = getContentForVersion(doc, latestVersion)
102
- if (!content) {
101
+ const contentOption = getContentForVersion(doc, latestVersion)
102
+ if (Option.isNone(contentOption)) {
103
103
  throw new Error('Latest version not found in document')
104
104
  }
105
- return content
105
+ return contentOption.value
106
106
  }
@@ -3,7 +3,7 @@ import { Change } from '#lib/change/$'
3
3
  import { Revision } from '#lib/revision/$'
4
4
  import { Schema } from '#lib/schema/$'
5
5
  import { Version } from '#lib/version/$'
6
- import { Match } from 'effect'
6
+ import { Match, Option } from 'effect'
7
7
 
8
8
  // ============================================================================
9
9
  // Lifecycles Type - Simple Index
@@ -44,21 +44,21 @@ export type Since =
44
44
  /**
45
45
  * Extract the type name from a change
46
46
  */
47
- const extractTypeNameFromChange = (change: Change.Change): string | null => {
47
+ const extractTypeNameFromChange = (change: Change.Change): Option.Option<string> => {
48
48
  return Match.value(change).pipe(
49
- Match.tag('TYPE_ADDED', (c) => c.name),
50
- Match.tag('TYPE_REMOVED', (c) => c.name),
51
- Match.tag('FIELD_ADDED', (c) => c.typeName),
52
- Match.tag('FIELD_REMOVED', (c) => c.typeName),
53
- Match.tag('INPUT_FIELD_ADDED', (c) => c.inputName),
54
- Match.tag('INPUT_FIELD_REMOVED', (c) => c.inputName),
55
- Match.tag('ENUM_VALUE_ADDED', (c) => c.enumName),
56
- Match.tag('ENUM_VALUE_REMOVED', (c) => c.enumName),
57
- Match.tag('UNION_MEMBER_ADDED', (c) => c.unionName),
58
- Match.tag('UNION_MEMBER_REMOVED', (c) => c.unionName),
59
- Match.tag('OBJECT_TYPE_INTERFACE_ADDED', (c) => c.objectName),
60
- Match.tag('OBJECT_TYPE_INTERFACE_REMOVED', (c) => c.objectName),
61
- Match.orElse(() => null),
49
+ Match.tag('TYPE_ADDED', (c) => Option.some(c.name)),
50
+ Match.tag('TYPE_REMOVED', (c) => Option.some(c.name)),
51
+ Match.tag('FIELD_ADDED', (c) => Option.some(c.typeName)),
52
+ Match.tag('FIELD_REMOVED', (c) => Option.some(c.typeName)),
53
+ Match.tag('INPUT_FIELD_ADDED', (c) => Option.some(c.inputName)),
54
+ Match.tag('INPUT_FIELD_REMOVED', (c) => Option.some(c.inputName)),
55
+ Match.tag('ENUM_VALUE_ADDED', (c) => Option.some(c.enumName)),
56
+ Match.tag('ENUM_VALUE_REMOVED', (c) => Option.some(c.enumName)),
57
+ Match.tag('UNION_MEMBER_ADDED', (c) => Option.some(c.unionName)),
58
+ Match.tag('UNION_MEMBER_REMOVED', (c) => Option.some(c.unionName)),
59
+ Match.tag('OBJECT_TYPE_INTERFACE_ADDED', (c) => Option.some(c.objectName)),
60
+ Match.tag('OBJECT_TYPE_INTERFACE_REMOVED', (c) => Option.some(c.objectName)),
61
+ Match.orElse(() => Option.none()),
62
62
  )
63
63
  }
64
64
 
@@ -72,8 +72,9 @@ export const createFromSchema = (schema: Schema.Schema): Lifecycles => {
72
72
  for (const revision of schema.revisions) {
73
73
  // Process all changes in this revision
74
74
  for (const change of revision.changes) {
75
- const typeName = extractTypeNameFromChange(change)
76
- if (typeName) {
75
+ const typeNameOption = extractTypeNameFromChange(change)
76
+ if (Option.isSome(typeNameOption)) {
77
+ const typeName = typeNameOption.value
77
78
  if (!lifecycles[typeName]) {
78
79
  lifecycles[typeName] = []
79
80
  }
@@ -100,8 +101,9 @@ export const create = (catalog: Catalog.Catalog): Lifecycles => {
100
101
  for (const revision of schema.revisions) {
101
102
  // Process all changes in this revision
102
103
  for (const change of revision.changes) {
103
- const typeName = extractTypeNameFromChange(change)
104
- if (typeName) {
104
+ const typeNameOption = extractTypeNameFromChange(change)
105
+ if (Option.isSome(typeNameOption)) {
106
+ const typeName = typeNameOption.value
105
107
  if (!lifecycles[typeName]) {
106
108
  lifecycles[typeName] = []
107
109
  }
@@ -477,9 +479,9 @@ export const getFieldLifecycle = (
477
479
  lifecycles: Lifecycles,
478
480
  typeName: string,
479
481
  fieldName: string,
480
- ): { events: ChangeEntry[] } | undefined => {
482
+ ): Option.Option<{ events: ChangeEntry[] }> => {
481
483
  const entries = lifecycles[typeName]
482
- if (!entries) return undefined
484
+ if (!entries) return Option.none()
483
485
 
484
486
  // Filter entries related to this specific field
485
487
  const fieldEntries = entries.filter(entry => {
@@ -497,25 +499,28 @@ export const getFieldLifecycle = (
497
499
  && entry.change.fieldName === fieldName)
498
500
  })
499
501
 
500
- if (fieldEntries.length === 0) return undefined
502
+ if (fieldEntries.length === 0) return Option.none()
501
503
 
502
504
  // Return in a format compatible with existing code that expects an object with events
503
- return { events: fieldEntries }
505
+ return Option.some({ events: fieldEntries })
504
506
  }
505
507
 
506
508
  /**
507
509
  * Get type lifecycle info (for compatibility with existing UI code)
508
510
  */
509
- export const getTypeLifecycle = (lifecycles: Lifecycles, typeName: string): { events: ChangeEntry[] } | undefined => {
511
+ export const getTypeLifecycle = (
512
+ lifecycles: Lifecycles,
513
+ typeName: string,
514
+ ): Option.Option<{ events: ChangeEntry[] }> => {
510
515
  const entries = lifecycles[typeName]
511
- if (!entries) return undefined
516
+ if (!entries) return Option.none()
512
517
 
513
518
  // Filter entries related to type-level changes
514
519
  const typeEntries = entries.filter(entry => {
515
520
  return entry.change._tag === 'TYPE_ADDED' || entry.change._tag === 'TYPE_REMOVED'
516
521
  })
517
522
 
518
- if (typeEntries.length === 0) return undefined
523
+ if (typeEntries.length === 0) return Option.none()
519
524
 
520
- return { events: typeEntries }
525
+ return Option.some({ events: typeEntries })
521
526
  }
@@ -0,0 +1 @@
1
+ export * from './version-coverage.js'
@@ -58,7 +58,7 @@ export const encodeSync = S.encodeSync(VersionCoverage)
58
58
  export const equivalence = S.equivalence(VersionCoverage)
59
59
 
60
60
  // ============================================================================
61
- // Domain Logic
61
+ // Domain Logic - Basic Operations
62
62
  // ============================================================================
63
63
 
64
64
  /**
@@ -1,12 +1,7 @@
1
1
  import { Catalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
- import { S } from '#lib/kit-temp/$'
4
- import type { Schema } from '#lib/schema/$'
5
- import { VersionCoverage } from '#lib/version-selection/$'
6
- import { VersionCoverageSet } from '#lib/version-selection/version-selection'
7
- import { Version } from '#lib/version/$'
8
- import { Array, HashMap, Match, Option } from 'effect'
9
- import type { GraphQLSchema } from 'graphql'
3
+ import { VersionCoverage } from '#lib/version-coverage'
4
+ import { Either, Option } from 'effect'
10
5
  import * as React from 'react'
11
6
  import { useHighlighted } from '../hooks/use-highlighted.js'
12
7
  import { GraphQLInteractive } from './GraphQLInteractive/GraphQLInteractive.js'
@@ -47,7 +42,7 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
47
42
  /// ━ VERSION MANAGEMENT
48
43
  const isControlled = controlledVersionCoverage !== undefined
49
44
  const [internalVersionCoverage, setInternalVersionCoverage] = React.useState<VersionCoverage.VersionCoverage | null>(
50
- Catalog.getLatestVersion(schemaCatalog),
45
+ Option.getOrNull(Catalog.getLatestVersion(schemaCatalog)),
51
46
  )
52
47
  const selectedVersionCoverage = isControlled ? controlledVersionCoverage : internalVersionCoverage
53
48
  const internalOnVersionChange = (version: VersionCoverage.VersionCoverage) => {
@@ -58,11 +53,15 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
58
53
  }
59
54
 
60
55
  /// ━ DATA RESOLUTION
61
- const {
62
- schema,
63
- content,
64
- } = resolveSelectedVerCov(document, selectedVersionCoverage, schemaCatalog)
56
+ const result = Document.resolveDocumentAndSchema(document, schemaCatalog, selectedVersionCoverage)
65
57
 
58
+ // Handle resolution errors gracefully
59
+ if (Either.isLeft(result)) {
60
+ console.error('Failed to resolve document and schema:', result.left.message)
61
+ return null
62
+ }
63
+
64
+ const { schema, content } = result.right
66
65
  const highlightedCode = useHighlighted(content, { interactive: true })
67
66
 
68
67
  if (!highlightedCode) {
@@ -87,60 +86,3 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
87
86
  />
88
87
  )
89
88
  }
90
-
91
- /**
92
- * Matches a document with an optional schema catalog, returning the document content,
93
- * corresponding schema, and available versions for the selected version.
94
- *
95
- * @param document - The document to retrieve content from (required)
96
- * @param selectedVersionCoverage - The version to select (optional, defaults to latest)
97
- * @param schemaCatalog - The schema catalog to match against (optional)
98
- * @returns Object with document content, optional schema, and available versions
99
- * @throws {Error} If versions in catalog don't match versions in document
100
- */
101
- type Result = { content: string; schema?: Schema.Schema }
102
- const resolveSelectedVerCov = (
103
- document: Document.Document,
104
- selectedVersionCoverage?: VersionCoverage.VersionCoverage | null,
105
- schemaCatalog?: Catalog.Catalog,
106
- ): Result => {
107
- if (Document.Unversioned.is(document)) {
108
- return {
109
- content: document.document,
110
- schema: Match.value(schemaCatalog).pipe(
111
- Match.tagsExhaustive({
112
- CatalogUnversioned: (catalog) => catalog.schema,
113
- CatalogVersioned: (catalog) => Catalog.Versioned.getLatestOrThrow(catalog),
114
- }),
115
- ),
116
- }
117
- }
118
-
119
- return Match.value(selectedVersionCoverage).pipe(
120
- Match.whenOr(null, undefined, _ => {
121
- const content = Document.Versioned.getContentForLatestVersionOrThrow(document)
122
- return { content }
123
- }),
124
- Match.orElse(_ => {
125
- const version = VersionCoverage.getLatest(_)
126
-
127
- const content = Document.Versioned.getContentForVersion(document, version)
128
- if (!content) {
129
- throw new Error(`Version ${Version.encodeSync(version)} not covered by document`)
130
- }
131
-
132
- if (!schemaCatalog) return { version, content }
133
-
134
- if (Catalog.Unversioned.is(schemaCatalog)) {
135
- throw new Error('Cannot use a set of versions with an unversioned catalog')
136
- }
137
- const schemaOption = HashMap.get(schemaCatalog.entries, version)
138
- if (Option.isNone(schemaOption)) {
139
- throw new Error(`Version ${Version.encodeSync(version)} not found in catalog`)
140
- }
141
- const schema = Option.getOrThrow(schemaOption)
142
-
143
- return { content, schema: schema }
144
- }),
145
- )
146
- }