polen 0.11.0-next.16 → 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 (251) 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 +5 -5
  22. package/build/api/examples/diagnostic/missing-versions.d.ts +5 -4
  23. package/build/api/examples/diagnostic/missing-versions.d.ts.map +1 -1
  24. package/build/api/examples/diagnostic/missing-versions.js +3 -2
  25. package/build/api/examples/diagnostic/missing-versions.js.map +1 -1
  26. package/build/api/examples/diagnostic/unknown-version.d.ts +5 -4
  27. package/build/api/examples/diagnostic/unknown-version.d.ts.map +1 -1
  28. package/build/api/examples/diagnostic/unknown-version.js +3 -2
  29. package/build/api/examples/diagnostic/unknown-version.js.map +1 -1
  30. package/build/api/examples/diagnostic/validation-error.d.ts +3 -2
  31. package/build/api/examples/diagnostic/validation-error.d.ts.map +1 -1
  32. package/build/api/examples/diagnostic/validation-error.js +9 -3
  33. package/build/api/examples/diagnostic/validation-error.js.map +1 -1
  34. package/build/api/examples/diagnostic/validator.d.ts.map +1 -1
  35. package/build/api/examples/diagnostic/validator.js +115 -69
  36. package/build/api/examples/diagnostic/validator.js.map +1 -1
  37. package/build/api/examples/filter.d.ts.map +1 -1
  38. package/build/api/examples/filter.js +9 -6
  39. package/build/api/examples/filter.js.map +1 -1
  40. package/build/api/examples/scanner.d.ts.map +1 -1
  41. package/build/api/examples/scanner.js +93 -103
  42. package/build/api/examples/scanner.js.map +1 -1
  43. package/build/api/examples/type-usage-indexer.d.ts.map +1 -1
  44. package/build/api/examples/type-usage-indexer.js +18 -32
  45. package/build/api/examples/type-usage-indexer.js.map +1 -1
  46. package/build/api/iso/schema/routing.d.ts.map +1 -1
  47. package/build/api/iso/schema/routing.js +8 -8
  48. package/build/api/iso/schema/routing.js.map +1 -1
  49. package/build/api/iso/schema/validation.d.ts.map +1 -1
  50. package/build/api/iso/schema/validation.js +3 -2
  51. package/build/api/iso/schema/validation.js.map +1 -1
  52. package/build/api/schema/input-sources/directory.js +2 -2
  53. package/build/api/schema/input-sources/directory.js.map +1 -1
  54. package/build/api/schema/input-sources/versioned-directory.d.ts +3 -3
  55. package/build/api/schema/input-sources/versioned-directory.d.ts.map +1 -1
  56. package/build/api/schema/input-sources/versioned-directory.js +6 -4
  57. package/build/api/schema/input-sources/versioned-directory.js.map +1 -1
  58. package/build/api/schema/load.d.ts.map +1 -1
  59. package/build/api/schema/load.js +2 -2
  60. package/build/api/schema/load.js.map +1 -1
  61. package/build/cli/commands/hero-image.js +1 -1
  62. package/build/cli/commands/hero-image.js.map +1 -1
  63. package/build/lib/catalog/catalog.d.ts +65 -24
  64. package/build/lib/catalog/catalog.d.ts.map +1 -1
  65. package/build/lib/catalog/catalog.js +72 -16
  66. package/build/lib/catalog/catalog.js.map +1 -1
  67. package/build/lib/catalog/versioned.d.ts +46 -26
  68. package/build/lib/catalog/versioned.d.ts.map +1 -1
  69. package/build/lib/catalog/versioned.js +44 -7
  70. package/build/lib/catalog/versioned.js.map +1 -1
  71. package/build/lib/catalog-statistics/analyze-catalog.js +3 -3
  72. package/build/lib/catalog-statistics/analyze-catalog.js.map +1 -1
  73. package/build/lib/document/document.d.ts +55 -5
  74. package/build/lib/document/document.d.ts.map +1 -1
  75. package/build/lib/document/document.js +96 -2
  76. package/build/lib/document/document.js.map +1 -1
  77. package/build/lib/document/versioned.d.ts +2 -2
  78. package/build/lib/document/versioned.d.ts.map +1 -1
  79. package/build/lib/document/versioned.js +7 -7
  80. package/build/lib/document/versioned.js.map +1 -1
  81. package/build/lib/lifecycles/lifecycles.d.ts +5 -4
  82. package/build/lib/lifecycles/lifecycles.d.ts.map +1 -1
  83. package/build/lib/lifecycles/lifecycles.js +15 -13
  84. package/build/lib/lifecycles/lifecycles.js.map +1 -1
  85. package/build/lib/version-coverage/$$.d.ts +2 -0
  86. package/build/lib/version-coverage/$$.d.ts.map +1 -0
  87. package/build/lib/version-coverage/$$.js +2 -0
  88. package/build/lib/version-coverage/$$.js.map +1 -0
  89. package/build/lib/version-coverage/$.d.ts.map +1 -0
  90. package/build/lib/version-coverage/$.js.map +1 -0
  91. package/build/lib/{version-selection/version-selection.d.ts → version-coverage/version-coverage.d.ts} +1 -1
  92. package/build/lib/version-coverage/version-coverage.d.ts.map +1 -0
  93. package/build/lib/{version-selection/version-selection.js → version-coverage/version-coverage.js} +2 -2
  94. package/build/lib/version-coverage/version-coverage.js.map +1 -0
  95. package/build/template/components/Changelog/Changelog.d.ts.map +1 -1
  96. package/build/template/components/Changelog/Changelog.js +7 -7
  97. package/build/template/components/Changelog/Changelog.js.map +1 -1
  98. package/build/template/components/GraphQLDocument.d.ts +1 -1
  99. package/build/template/components/GraphQLDocument.d.ts.map +1 -1
  100. package/build/template/components/GraphQLDocument.js +10 -38
  101. package/build/template/components/GraphQLDocument.js.map +1 -1
  102. package/build/template/components/GraphQLInteractive/lib/parser.d.ts +28 -0
  103. package/build/template/components/GraphQLInteractive/lib/parser.d.ts.map +1 -1
  104. package/build/template/components/GraphQLInteractive/lib/parser.js +60 -27
  105. package/build/template/components/GraphQLInteractive/lib/parser.js.map +1 -1
  106. package/build/template/components/VersionCoveragePicker.d.ts +1 -1
  107. package/build/template/components/VersionCoveragePicker.d.ts.map +1 -1
  108. package/build/template/components/VersionCoveragePicker.js +4 -6
  109. package/build/template/components/VersionCoveragePicker.js.map +1 -1
  110. package/build/template/components/VersionPicker.d.ts.map +1 -1
  111. package/build/template/components/VersionPicker.js +5 -2
  112. package/build/template/components/VersionPicker.js.map +1 -1
  113. package/build/template/components/home/FeaturesGrid.js +1 -1
  114. package/build/template/components/home/FeaturesGrid.js.map +1 -1
  115. package/build/template/components/home/HeroSection.js +1 -1
  116. package/build/template/components/home/HeroSection.js.map +1 -1
  117. package/build/template/components/home/QuickStart.d.ts.map +1 -1
  118. package/build/template/components/home/QuickStart.js +8 -4
  119. package/build/template/components/home/QuickStart.js.map +1 -1
  120. package/build/template/components/home/RecentChanges.d.ts.map +1 -1
  121. package/build/template/components/home/RecentChanges.js +2 -1
  122. package/build/template/components/home/RecentChanges.js.map +1 -1
  123. package/build/template/hooks/use-highlighted.d.ts.map +1 -1
  124. package/build/template/hooks/use-highlighted.js +19 -13
  125. package/build/template/hooks/use-highlighted.js.map +1 -1
  126. package/build/template/lib/fetch-text.d.ts +18 -0
  127. package/build/template/lib/fetch-text.d.ts.map +1 -1
  128. package/build/template/lib/fetch-text.js +32 -4
  129. package/build/template/lib/fetch-text.js.map +1 -1
  130. package/build/template/routes/changelog.d.ts +1 -1
  131. package/build/template/routes/changelog.d.ts.map +1 -1
  132. package/build/template/routes/changelog.js +7 -4
  133. package/build/template/routes/changelog.js.map +1 -1
  134. package/build/template/routes/examples/_index.js +1 -1
  135. package/build/template/routes/examples/_index.js.map +1 -1
  136. package/build/template/routes/examples/name.d.ts.map +1 -1
  137. package/build/template/routes/examples/name.js +4 -2
  138. package/build/template/routes/examples/name.js.map +1 -1
  139. package/build/template/routes/reference.js +6 -6
  140. package/build/template/routes/reference.js.map +1 -1
  141. package/build/template/stores/toast.d.ts.map +1 -1
  142. package/build/template/stores/toast.js +5 -3
  143. package/build/template/stores/toast.js.map +1 -1
  144. package/build/vite/plugins/navbar.js +1 -1
  145. package/build/vite/plugins/navbar.js.map +1 -1
  146. package/build/vite/plugins/routes-manifest.js +1 -1
  147. package/build/vite/plugins/routes-manifest.js.map +1 -1
  148. package/package.json +7 -7
  149. package/src/api/builder/ssg/generate.ts +10 -5
  150. package/src/api/builder/ssg/page-generator.worker.ts +18 -3
  151. package/src/api/config/normalized.ts +12 -3
  152. package/src/api/config-template/template.ts +2 -2
  153. package/src/api/content/sidebar.ts +3 -3
  154. package/src/api/examples/config.test.ts +10 -0
  155. package/src/api/examples/config.ts +33 -4
  156. package/src/api/examples/diagnostic/missing-versions.ts +3 -2
  157. package/src/api/examples/diagnostic/unknown-version.ts +3 -2
  158. package/src/api/examples/diagnostic/validation-error.ts +9 -3
  159. package/src/api/examples/diagnostic/validator.test.ts +100 -55
  160. package/src/api/examples/diagnostic/validator.ts +148 -105
  161. package/src/api/examples/filter.ts +9 -6
  162. package/src/api/examples/scanner.ts +144 -120
  163. package/src/api/examples/type-usage-indexer.test.ts +44 -33
  164. package/src/api/examples/type-usage-indexer.ts +25 -40
  165. package/src/api/iso/schema/routing.ts +10 -10
  166. package/src/api/iso/schema/validation.ts +3 -2
  167. package/src/api/schema/$.test.ts +2 -2
  168. package/src/api/schema/input-sources/directory.ts +2 -2
  169. package/src/api/schema/input-sources/versioned-directory.ts +11 -8
  170. package/src/api/schema/load.ts +2 -2
  171. package/src/cli/commands/hero-image.ts +1 -1
  172. package/src/lib/catalog/catalog.ts +93 -16
  173. package/src/lib/catalog/versioned.ts +57 -7
  174. package/src/lib/catalog-statistics/$.test.ts +22 -12
  175. package/src/lib/catalog-statistics/analyze-catalog.ts +3 -3
  176. package/src/lib/document/document.ts +135 -2
  177. package/src/lib/document/versioned.ts +8 -8
  178. package/src/lib/lifecycles/lifecycles.ts +33 -28
  179. package/src/lib/version-coverage/$$.ts +1 -0
  180. package/src/lib/{version-selection/version-selection.ts → version-coverage/version-coverage.ts} +1 -1
  181. package/src/template/components/Changelog/Changelog.tsx +10 -6
  182. package/src/template/components/GraphQLDocument.tsx +11 -68
  183. package/src/template/components/GraphQLInteractive/lib/parser.ts +81 -29
  184. package/src/template/components/VersionCoveragePicker.tsx +4 -5
  185. package/src/template/components/VersionPicker.tsx +9 -2
  186. package/src/template/components/home/FeaturesGrid.tsx +1 -1
  187. package/src/template/components/home/HeroSection.tsx +1 -1
  188. package/src/template/components/home/QuickStart.tsx +16 -7
  189. package/src/template/components/home/RecentChanges.tsx +3 -1
  190. package/src/template/hooks/use-highlighted.ts +31 -19
  191. package/src/template/lib/fetch-text.ts +45 -4
  192. package/src/template/routes/changelog.tsx +10 -4
  193. package/src/template/routes/examples/_index.tsx +1 -1
  194. package/src/template/routes/examples/name.tsx +4 -2
  195. package/src/template/routes/reference.tsx +6 -6
  196. package/src/template/stores/toast.ts +6 -3
  197. package/src/vite/plugins/navbar.ts +1 -1
  198. package/src/vite/plugins/routes-manifest.ts +1 -1
  199. package/build/lib/graph/$$.d.ts +0 -2
  200. package/build/lib/graph/$$.d.ts.map +0 -1
  201. package/build/lib/graph/$$.js +0 -2
  202. package/build/lib/graph/$$.js.map +0 -1
  203. package/build/lib/graph/$.d.ts +0 -2
  204. package/build/lib/graph/$.d.ts.map +0 -1
  205. package/build/lib/graph/$.js +0 -2
  206. package/build/lib/graph/$.js.map +0 -1
  207. package/build/lib/graph/graph.d.ts +0 -127
  208. package/build/lib/graph/graph.d.ts.map +0 -1
  209. package/build/lib/graph/graph.js +0 -152
  210. package/build/lib/graph/graph.js.map +0 -1
  211. package/build/lib/mask/$$.d.ts +0 -3
  212. package/build/lib/mask/$$.d.ts.map +0 -1
  213. package/build/lib/mask/$$.js +0 -3
  214. package/build/lib/mask/$$.js.map +0 -1
  215. package/build/lib/mask/$.d.ts +0 -2
  216. package/build/lib/mask/$.d.ts.map +0 -1
  217. package/build/lib/mask/$.js +0 -2
  218. package/build/lib/mask/$.js.map +0 -1
  219. package/build/lib/mask/apply.d.ts +0 -86
  220. package/build/lib/mask/apply.d.ts.map +0 -1
  221. package/build/lib/mask/apply.js +0 -86
  222. package/build/lib/mask/apply.js.map +0 -1
  223. package/build/lib/mask/mask.d.ts +0 -124
  224. package/build/lib/mask/mask.d.ts.map +0 -1
  225. package/build/lib/mask/mask.js +0 -137
  226. package/build/lib/mask/mask.js.map +0 -1
  227. package/build/lib/mask/mask.test-d.d.ts +0 -2
  228. package/build/lib/mask/mask.test-d.d.ts.map +0 -1
  229. package/build/lib/mask/mask.test-d.js +0 -102
  230. package/build/lib/mask/mask.test-d.js.map +0 -1
  231. package/build/lib/version-selection/$$.d.ts +0 -2
  232. package/build/lib/version-selection/$$.d.ts.map +0 -1
  233. package/build/lib/version-selection/$$.js +0 -2
  234. package/build/lib/version-selection/$$.js.map +0 -1
  235. package/build/lib/version-selection/$.d.ts.map +0 -1
  236. package/build/lib/version-selection/$.js.map +0 -1
  237. package/build/lib/version-selection/version-selection.d.ts.map +0 -1
  238. package/build/lib/version-selection/version-selection.js.map +0 -1
  239. package/src/lib/graph/$$.ts +0 -1
  240. package/src/lib/graph/$.ts +0 -1
  241. package/src/lib/graph/graph.ts +0 -197
  242. package/src/lib/mask/$$.ts +0 -2
  243. package/src/lib/mask/$.test.ts +0 -226
  244. package/src/lib/mask/$.ts +0 -1
  245. package/src/lib/mask/apply.ts +0 -134
  246. package/src/lib/mask/mask.test-d.ts +0 -156
  247. package/src/lib/mask/mask.ts +0 -244
  248. package/src/lib/version-selection/$$.ts +0 -1
  249. /package/build/lib/{version-selection → version-coverage}/$.d.ts +0 -0
  250. /package/build/lib/{version-selection → version-coverage}/$.js +0 -0
  251. /package/src/lib/{version-selection → version-coverage}/$.ts +0 -0
@@ -1,18 +1,17 @@
1
1
  import { Catalog as SchemaCatalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
3
  import { EffectGlob } from '#lib/effect-glob/$'
4
- import { VersionCoverage } from '#lib/version-selection/$'
4
+ import { VersionCoverage } from '#lib/version-coverage'
5
5
  import { Version } from '#lib/version/$'
6
6
  import { FileSystem } from '@effect/platform'
7
7
  import { Str } from '@wollybeard/kit'
8
- import { Effect, HashMap, HashSet, Match } from 'effect'
8
+ import { Array, Effect, HashMap, HashSet, Match } from 'effect'
9
9
  import * as Path from 'node:path'
10
10
  import type { Diagnostic } from './diagnostic/diagnostic.js'
11
11
  import {
12
12
  makeDiagnosticDuplicateContent,
13
13
  makeDiagnosticMissingVersions,
14
14
  makeDiagnosticUnknownVersion,
15
- makeDiagnosticUnusedDefault,
16
15
  } from './diagnostic/diagnostic.js'
17
16
  import { validateExamples } from './diagnostic/validator.js'
18
17
  import { Catalog } from './schemas/catalog.js'
@@ -44,11 +43,26 @@ const VERSIONED_FILE_PATTERN = Str.pattern<{ groups: ['name', 'version'] }>(
44
43
  /^(?<name>.+?)\.(?<version>.+)$/,
45
44
  )
46
45
 
46
+ // ============================================================================
47
+ // File Parsing Types
48
+ // ============================================================================
49
+
50
+ type ParsedExampleFile =
51
+ | { type: 'unversioned'; name: string; file: string }
52
+ | { type: 'versioned'; name: string; version: Version.Version; file: string }
53
+ | { type: 'default'; name: string; file: string }
54
+
55
+ type GroupedExampleFiles = Map<string, {
56
+ unversioned?: string
57
+ versioned: Map<Version.Version, string>
58
+ default?: string
59
+ }>
60
+
47
61
  // ============================================================================
48
62
  // Helpers
49
63
  // ============================================================================
50
64
 
51
- const parseExampleFilename = (filename: string): { name: string; version: string | null } => {
65
+ const parseExampleFile = (filename: string): ParsedExampleFile => {
52
66
  const parsed = Path.parse(filename)
53
67
  const base = parsed.name
54
68
 
@@ -60,41 +74,105 @@ const parseExampleFilename = (filename: string): { name: string; version: string
60
74
 
61
75
  // Handle special 'default' keyword
62
76
  if (versionStr === 'default') {
63
- return { name, version: 'default' }
77
+ return { type: 'default', name, file: filename }
64
78
  }
65
- const decoded = Version.decodeSync(versionStr)
66
- // Return canonical version string
67
- return { name, version: Version.encodeSync(decoded) }
79
+
80
+ const version = Version.decodeSync(versionStr)
81
+ return { type: 'versioned', name, version, file: filename }
68
82
  }
69
83
 
70
84
  // No version found - this is an unversioned example
71
- return { name: base, version: null }
85
+ return { type: 'unversioned', name: base, file: filename }
72
86
  }
73
87
 
74
- const groupExampleFiles = (files: string[]): Map<string, Map<string | null, string>> => {
75
- const grouped = new Map<string, Map<string | null, string>>()
88
+ const groupExampleFiles = (files: string[]): GroupedExampleFiles => {
89
+ const grouped: GroupedExampleFiles = new Map()
76
90
 
77
91
  for (const file of files) {
78
- const { name, version } = parseExampleFilename(file)
92
+ const parsed = parseExampleFile(file)
79
93
 
80
- if (!grouped.has(name)) {
81
- grouped.set(name, new Map())
94
+ if (!grouped.has(parsed.name)) {
95
+ grouped.set(parsed.name, {
96
+ versioned: new Map(),
97
+ })
98
+ }
99
+
100
+ const group = grouped.get(parsed.name)!
101
+
102
+ switch (parsed.type) {
103
+ case 'unversioned':
104
+ group.unversioned = parsed.file
105
+ break
106
+ case 'versioned':
107
+ group.versioned.set(parsed.version, parsed.file)
108
+ break
109
+ case 'default':
110
+ group.default = parsed.file
111
+ break
82
112
  }
83
- grouped.get(name)!.set(version, file)
84
113
  }
85
114
 
86
115
  return grouped
87
116
  }
88
117
 
118
+ /**
119
+ * Resolve .default files into proper version coverage.
120
+ * This erases the .default convention and converts it to semantic version sets.
121
+ */
122
+ const resolveDefaultFiles = (
123
+ grouped: GroupedExampleFiles,
124
+ schemaVersions: Version.Version[],
125
+ ): Map<string, {
126
+ versionDocuments: HashMap.HashMap<VersionCoverage.VersionCoverage, string>
127
+ unversioned?: string
128
+ }> => {
129
+ const resolved = new Map<string, {
130
+ versionDocuments: HashMap.HashMap<VersionCoverage.VersionCoverage, string>
131
+ unversioned?: string
132
+ }>()
133
+
134
+ for (const [name, group] of grouped) {
135
+ let versionDocuments = HashMap.empty<VersionCoverage.VersionCoverage, string>()
136
+
137
+ // Add explicit versions
138
+ for (const [version, file] of group.versioned) {
139
+ versionDocuments = HashMap.set(versionDocuments, version, file)
140
+ }
141
+
142
+ // Handle default file if present
143
+ if (group.default) {
144
+ // Determine which versions the default covers
145
+ const explicitVersions = HashSet.fromIterable(group.versioned.keys())
146
+ const defaultVersions = schemaVersions.filter(v => !HashSet.has(explicitVersions, v))
147
+
148
+ if (defaultVersions.length > 0) {
149
+ // Create version coverage for default
150
+ const defaultCoverage = defaultVersions.length === 1
151
+ ? defaultVersions[0]! // Single version
152
+ : HashSet.fromIterable(defaultVersions) // Version set
153
+
154
+ versionDocuments = HashMap.set(versionDocuments, defaultCoverage, group.default)
155
+ }
156
+ }
157
+
158
+ resolved.set(name, {
159
+ versionDocuments,
160
+ ...(group.unversioned ? { unversioned: group.unversioned } : {}),
161
+ })
162
+ }
163
+
164
+ return resolved
165
+ }
166
+
89
167
  const lintFileLayout = (
90
168
  example: Example.Example,
91
169
  schemaCatalog?: SchemaCatalog.Catalog,
92
170
  ): Diagnostic[] => {
93
171
  // Extract schema versions from catalog if provided
94
- const schemaVersions: string[] = schemaCatalog
172
+ const schemaVersions: Version.Version[] = schemaCatalog
95
173
  ? SchemaCatalog.fold(
96
- (versioned) => versioned.entries.map(entry => Version.encodeSync(entry.version)),
97
- (unversioned) => unversioned.schema.revisions?.map(r => r.date) ?? [],
174
+ (versioned) => SchemaCatalog.Versioned.getVersions(versioned),
175
+ (unversioned) => [], // Unversioned doesn't have Version objects, just dates
98
176
  )(schemaCatalog)
99
177
  : []
100
178
 
@@ -105,20 +183,22 @@ const lintFileLayout = (
105
183
  DocumentVersioned: (doc) => {
106
184
  // Get all versions covered by this document
107
185
  const coveredVersions = Document.Versioned.getAllVersions(doc)
108
- const coveredVersionStrings = coveredVersions.map(Version.encodeSync)
109
- const missingVersions = schemaVersions.filter(sv => !coveredVersionStrings.includes(sv))
186
+ const missingVersions = Array.filter(
187
+ schemaVersions,
188
+ sv => !Array.some(coveredVersions, cv => Version.equivalence(sv, cv)),
189
+ )
110
190
 
111
191
  if (missingVersions.length > 0) {
112
192
  diagnostics.push(makeDiagnosticMissingVersions({
113
193
  message: `Versioned example must provide documents for all schema versions`,
114
194
  example: { name: example.name, path: example.path },
115
- providedVersions: coveredVersionStrings,
195
+ providedVersions: coveredVersions,
116
196
  missingVersions,
117
197
  }))
118
198
  }
119
199
 
120
200
  // Check for duplicate content between selections
121
- const entries = Array.from(HashMap.entries(doc.versionDocuments))
201
+ const entries = [...HashMap.entries(doc.versionDocuments)]
122
202
  const duplicates: Array<{ version1: string; version2: string }> = []
123
203
  for (let i = 0; i < entries.length; i++) {
124
204
  for (let j = i + 1; j < entries.length; j++) {
@@ -162,32 +242,41 @@ export const scan = (
162
242
  const pattern = `**/*.{${extensions.join(',')}}`
163
243
  const files = options.files ?? (yield* EffectGlob.glob(pattern, { cwd: options.dir }))
164
244
 
245
+ // Get schema versions upfront for default file resolution
246
+ const schemaVersions: Version.Version[] = options.schemaCatalog
247
+ ? SchemaCatalog.fold(
248
+ (versioned) => SchemaCatalog.Versioned.getVersions(versioned),
249
+ () => [], // Unversioned schemas don't have version-specific examples
250
+ )(options.schemaCatalog)
251
+ : []
252
+
165
253
  // Group files by example
166
254
  const groupedFiles = groupExampleFiles(files)
167
255
 
256
+ // Resolve .default files into proper version coverage immediately
257
+ const resolvedFiles = resolveDefaultFiles(groupedFiles, schemaVersions)
258
+
168
259
  // Process each example group
169
260
  const examples: Example.Example[] = []
170
261
  const diagnostics: Diagnostic[] = []
171
262
 
172
- for (const [name, versions] of groupedFiles) {
173
- // Check if this is a versioned or unversioned example
174
- const hasMultipleVersions = versions.size > 1
175
- const hasUnversionedFile = versions.has(null)
176
- const hasDefaultFile = versions.has('default')
177
- const hasOnlyDefaultFile = hasDefaultFile && versions.size === 1
178
-
263
+ for (const [name, resolved] of resolvedFiles) {
179
264
  // Determine the base path for this example
180
- const firstFilePath = Array.from(versions.values())[0]!
181
- const basePath = versions.size === 1
182
- ? firstFilePath
183
- : Path.dirname(firstFilePath)
265
+ const firstFile = resolved.unversioned
266
+ || (HashMap.size(resolved.versionDocuments) > 0
267
+ ? HashMap.values(resolved.versionDocuments).next().value
268
+ : undefined)
269
+ if (!firstFile) continue // No files for this example
270
+
271
+ const basePath = HashMap.size(resolved.versionDocuments) > 1 || resolved.unversioned
272
+ ? Path.dirname(firstFile)
273
+ : firstFile
184
274
 
185
- let example: Example.Example
275
+ let example: Example.Example | undefined
186
276
 
187
- if (hasUnversionedFile && versions.size === 1) {
277
+ if (resolved.unversioned) {
188
278
  // Unversioned example - single file with no version
189
- const filePath = versions.get(null)!
190
- const fullPath = Path.join(options.dir, filePath)
279
+ const fullPath = Path.join(options.dir, resolved.unversioned)
191
280
  const document = yield* fs.readFileString(fullPath)
192
281
 
193
282
  example = Example.make({
@@ -197,98 +286,36 @@ export const scan = (
197
286
  document,
198
287
  }),
199
288
  })
200
- } else if (hasOnlyDefaultFile) {
201
- // Only default file - create versioned document with all schema versions as a set
202
- const filePath = versions.get('default')!
203
- const fullPath = Path.join(options.dir, filePath)
204
- const documentContent = yield* fs.readFileString(fullPath)
205
-
206
- // Get all schema versions to map to this default document
207
- const schemaVersions: Version.Version[] = options.schemaCatalog
208
- ? SchemaCatalog.fold(
209
- (versioned) => versioned.entries.map(entry => entry.version),
210
- () => [], // Unversioned schemas don't have version-specific examples
211
- )(options.schemaCatalog)
212
- : []
213
-
214
- if (schemaVersions.length > 0) {
215
- // Create a version set for all schema versions
216
- const versionSet = HashSet.fromIterable(schemaVersions)
217
- let versionDocuments = HashMap.empty<VersionCoverage.VersionCoverage, string>()
218
- versionDocuments = HashMap.set(versionDocuments, versionSet, documentContent)
219
-
220
- example = Example.make({
221
- name,
222
- path: basePath,
223
- document: Document.Versioned.make({
224
- versionDocuments,
225
- }),
226
- })
227
- } else {
228
- // No schema versions, treat as unversioned
229
- example = Example.make({
230
- name,
231
- path: basePath,
232
- document: Document.Unversioned.make({
233
- document: documentContent,
234
- }),
235
- })
236
- }
237
- } else {
238
- // Versioned example - multiple files or versioned files
289
+ } else if (HashMap.size(resolved.versionDocuments) > 0) {
290
+ // Versioned example - read all version documents
239
291
  let versionDocuments = HashMap.empty<VersionCoverage.VersionCoverage, string>()
240
- let defaultDocument: string | undefined
241
- const explicitVersions = new Set<string>() // Track which versions have explicit files
242
- const unknownVersions: string[] = []
243
-
244
- // Get available schema versions if catalog is provided
245
- const schemaVersions: string[] = options.schemaCatalog
246
- ? SchemaCatalog.fold(
247
- (versioned) => versioned.entries.map(entry => Version.encodeSync(entry.version)),
248
- () => [], // Unversioned schemas don't have version-specific examples
249
- )(options.schemaCatalog)
250
- : []
251
-
252
- // Read content for each version
253
- for (const [version, filePath] of versions) {
254
- const fullPath = Path.join(options.dir, filePath)
255
- const fileContent = yield* fs.readFileString(fullPath)
256
-
257
- if (version === 'default') {
258
- defaultDocument = fileContent
259
- } else if (version !== null) {
260
- // Check if this version exists in the schema
261
- if (options.schemaCatalog && schemaVersions.length > 0 && !schemaVersions.includes(version)) {
262
- unknownVersions.push(version)
292
+ const unknownVersions: Version.Version[] = []
293
+ const schemaVersionsSet = HashSet.fromIterable(schemaVersions)
294
+
295
+ for (const [versionCoverage, filePath] of HashMap.entries(resolved.versionDocuments)) {
296
+ // Check if version is known (only for single versions, not sets)
297
+ if (Version.is(versionCoverage)) {
298
+ const versionExists = HashSet.has(schemaVersionsSet, versionCoverage)
299
+ if (options.schemaCatalog && schemaVersions.length > 0 && !versionExists) {
300
+ unknownVersions.push(versionCoverage)
263
301
  // Create diagnostic for unknown version
264
302
  diagnostics.push(makeDiagnosticUnknownVersion({
265
- message: `Example "${name}" specifies version "${version}" which does not exist in the schema`,
303
+ message: `Example "${name}" specifies version "${
304
+ Version.encodeSync(versionCoverage)
305
+ }" which does not exist in the schema`,
266
306
  example: { name, path: basePath },
267
- version,
307
+ version: versionCoverage,
268
308
  availableVersions: schemaVersions,
269
309
  }))
270
310
  // Skip this version - don't include it in the example
271
311
  continue
272
312
  }
273
-
274
- const versionObj = Version.decodeSync(version)
275
- versionDocuments = HashMap.set(versionDocuments, versionObj, fileContent)
276
- explicitVersions.add(version)
277
313
  }
278
- }
279
-
280
- if (defaultDocument) {
281
- // If we have a default, determine which versions it applies to
282
- const defaultVersions = schemaVersions.filter(v => !explicitVersions.has(v))
283
314
 
284
- if (defaultVersions.length > 0) {
285
- // Create a version set for the default document
286
- const defaultVersionSet = defaultVersions.length === 1
287
- ? Version.decodeSync(defaultVersions[0]!) // Single version
288
- : HashSet.fromIterable(defaultVersions.map(_ => Version.decodeSync(_))) // Version set
315
+ const fullPath = Path.join(options.dir, filePath)
316
+ const fileContent = yield* fs.readFileString(fullPath)
289
317
 
290
- versionDocuments = HashMap.set(versionDocuments, defaultVersionSet, defaultDocument)
291
- }
318
+ versionDocuments = HashMap.set(versionDocuments, versionCoverage, fileContent)
292
319
  }
293
320
 
294
321
  if (HashMap.size(versionDocuments) > 0) {
@@ -303,9 +330,6 @@ export const scan = (
303
330
  } else if (unknownVersions.length > 0) {
304
331
  // All versions were unknown, skip this example entirely
305
332
  continue
306
- } else {
307
- // No versions at all - shouldn't happen
308
- continue
309
333
  }
310
334
  }
311
335
 
@@ -1,6 +1,5 @@
1
1
  import { Catalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
- import { Revision } from '#lib/revision/$'
4
3
  import { Schema } from '#lib/schema/$'
5
4
  import { Version } from '#lib/version/$'
6
5
  import { HashMap, HashSet, Schema as S } from 'effect'
@@ -17,23 +16,23 @@ describe('type-usage-indexer', () => {
17
16
  users: [User!]!
18
17
  product(id: ID!): Product
19
18
  }
20
-
19
+
21
20
  type User {
22
21
  id: ID!
23
22
  name: String!
24
23
  email: String!
25
24
  }
26
-
25
+
27
26
  type Product {
28
27
  id: ID!
29
28
  name: String!
30
29
  price: Float!
31
30
  }
32
-
31
+
33
32
  interface Node {
34
33
  id: ID!
35
34
  }
36
-
35
+
37
36
  union SearchResult = User | Product
38
37
  `
39
38
 
@@ -91,20 +90,26 @@ describe('type-usage-indexer', () => {
91
90
  })
92
91
 
93
92
  const catalog = Catalog.Versioned.make({
94
- entries: [
95
- Schema.Versioned.make({
96
- version: version1,
97
- definition: schemaDef,
98
- branchPoint: null,
99
- revisions: [],
100
- }),
101
- Schema.Versioned.make({
102
- version: version2,
103
- definition: schemaDef,
104
- branchPoint: null,
105
- revisions: [],
106
- }),
107
- ],
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
+ ),
108
113
  })
109
114
 
110
115
  const index = createTypeUsageIndex([example], catalog)
@@ -212,20 +217,26 @@ describe('type-usage-indexer', () => {
212
217
  })
213
218
 
214
219
  const catalog = Catalog.Versioned.make({
215
- entries: [
216
- Schema.Versioned.make({
217
- version: version1,
218
- definition: schemaDef,
219
- branchPoint: null,
220
- revisions: [],
221
- }),
222
- Schema.Versioned.make({
223
- version: version2,
224
- definition: schemaDef,
225
- branchPoint: null,
226
- revisions: [],
227
- }),
228
- ],
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
+ ),
229
240
  })
230
241
 
231
242
  const index = createTypeUsageIndex([example], catalog)
@@ -1,6 +1,5 @@
1
1
  import { Catalog } from '#lib/catalog/$'
2
2
  import { Document } from '#lib/document/$'
3
- import { Schema } from '#lib/schema/$'
4
3
  import { Version } from '#lib/version/$'
5
4
  import { HashMap, HashSet, Option } from 'effect'
6
5
  import { Schema as S } from 'effect'
@@ -76,19 +75,19 @@ const extractTypesFromQuery = (
76
75
  const resolveFieldType = (
77
76
  fieldName: string,
78
77
  parentTypeName: string | null,
79
- ): string | null => {
80
- if (!parentTypeName) return null
78
+ ): Option.Option<string> => {
79
+ if (!parentTypeName) return Option.none()
81
80
 
82
81
  const parentType = schema.getType(parentTypeName)
83
82
  if (!parentType || !isObjectType(parentType) && !isInterfaceType(parentType)) {
84
- return null
83
+ return Option.none()
85
84
  }
86
85
 
87
86
  const field = parentType.getFields()[fieldName]
88
- if (!field) return null
87
+ if (!field) return Option.none()
89
88
 
90
89
  const namedType = getNamedType(field.type)
91
- return namedType.name
90
+ return Option.some(namedType.name)
92
91
  }
93
92
 
94
93
  // Track the current type context as we traverse
@@ -120,8 +119,9 @@ const extractTypesFromQuery = (
120
119
  // Special handling for __typename
121
120
  if (node.name.value === '__typename') return
122
121
 
123
- const fieldType = resolveFieldType(node.name.value, currentType)
124
- if (fieldType) {
122
+ const fieldTypeOption = resolveFieldType(node.name.value, currentType)
123
+ if (Option.isSome(fieldTypeOption)) {
124
+ const fieldType = fieldTypeOption.value
125
125
  addType(fieldType)
126
126
  // Update context for nested selections
127
127
  if (node.selectionSet) {
@@ -160,32 +160,6 @@ const extractTypesFromQuery = (
160
160
  return types
161
161
  }
162
162
 
163
- // ============================================================================
164
- // Helper Functions
165
- // ============================================================================
166
-
167
- /**
168
- * Get a schema by version from the catalog.
169
- */
170
- const getSchemaByVersion = (
171
- catalog: Catalog.Catalog,
172
- version: Version.Version,
173
- ): Schema.Schema | undefined => {
174
- if (Catalog.Versioned.is(catalog)) {
175
- // Find the schema with matching version
176
- return catalog.entries.find(entry =>
177
- Schema.Versioned.is(entry)
178
- && Version.equivalence(entry.version, version)
179
- )
180
- }
181
- // For unversioned catalog, return the single schema if version matches
182
- if (Catalog.Unversioned.is(catalog)) {
183
- // Unversioned catalogs don't have versions, so we can't match
184
- return undefined
185
- }
186
- return undefined
187
- }
188
-
189
163
  // ============================================================================
190
164
  // Index Creation
191
165
  // ============================================================================
@@ -206,12 +180,15 @@ export const createTypeUsageIndex = (
206
180
  // Process based on document type
207
181
  if (Document.Unversioned.is(example.document)) {
208
182
  // Unversioned document
209
- const schema = Catalog.getLatestSchema(schemasCatalog)
183
+ const schema = Catalog.getLatest(schemasCatalog)
210
184
  const types = extractTypesFromQuery(example.document.document, schema.definition)
211
185
 
212
186
  for (const typeName of types) {
213
187
  // For unversioned, use the latest version from the catalog
214
- const latestVersion = Catalog.getLatestVersionIdentifier(schemasCatalog) ?? Version.fromString('1.0.0')
188
+ const latestVersion = Option.getOrElse(
189
+ Catalog.getLatestVersion(schemasCatalog),
190
+ () => Version.fromString('1.0.0'),
191
+ )
215
192
  index = addExampleToIndex(index, UNVERSIONED_KEY, typeName, example, latestVersion)
216
193
  }
217
194
  } else if (Document.Versioned.is(example.document)) {
@@ -219,11 +196,19 @@ export const createTypeUsageIndex = (
219
196
  const allVersions = Document.Versioned.getAllVersions(example.document)
220
197
 
221
198
  for (const version of allVersions) {
222
- const schema = getSchemaByVersion(schemasCatalog, version)
223
- if (!schema) continue
199
+ // Use centralized resolution to get schema for version
200
+ const schemaOption = Option.liftThrowable(
201
+ () => Catalog.resolveCatalogSchema(schemasCatalog, version),
202
+ )()
203
+ if (Option.isNone(schemaOption)) {
204
+ // Skip if version not found in catalog
205
+ continue
206
+ }
207
+ const schema = schemaOption.value
224
208
 
225
- const documentString = Document.Versioned.getContentForVersion(example.document, version)
226
- if (!documentString) continue
209
+ const documentStringOption = Document.Versioned.getContentForVersion(example.document, version)
210
+ if (Option.isNone(documentStringOption)) continue
211
+ const documentString = documentStringOption.value
227
212
 
228
213
  const types = extractTypesFromQuery(documentString, schema.definition)
229
214
 
@@ -1,6 +1,7 @@
1
1
  import { Grafaid } from '#lib/grafaid'
2
2
  import { Schema } from '#lib/schema/$'
3
3
  import { Version } from '#lib/version/$'
4
+ import { Array, Option, Predicate } from 'effect'
4
5
 
5
6
  export interface ReferencePathParts {
6
7
  version?: Version.Version
@@ -46,16 +47,15 @@ export const createReferenceVersionPath = (version?: Version.Version): string =>
46
47
  export const joinSegmentsAndPaths = (
47
48
  ...segmentsOrPaths: (string | undefined | null | (string | null | undefined)[])[]
48
49
  ): string => {
49
- const path = '/' + segmentsOrPaths
50
- .flat()
51
- .filter((_): _ is string => _ !== undefined && _ !== null)
52
- .map(chunkUnformatted =>
53
- chunkUnformatted
54
- .replace(/^\//, '')
55
- .replace(/\/$/, '')
56
- )
57
- .filter(Boolean)
58
- .join('/')
50
+ const segments = Array.filterMap(
51
+ segmentsOrPaths.flat(),
52
+ (segment) => {
53
+ if (!Predicate.isNotNullable(segment)) return Option.none()
54
+ const cleaned = segment.replace(/^\//, '').replace(/\/$/, '')
55
+ return cleaned ? Option.some(cleaned) : Option.none()
56
+ },
57
+ )
58
+ const path = '/' + segments.join('/')
59
59
 
60
60
  return path
61
61
  }
@@ -1,4 +1,5 @@
1
1
  import { Grafaid } from '#lib/grafaid'
2
+ import { Array, Option } from 'effect'
2
3
  import type { GraphQLFieldMap, GraphQLSchema } from 'graphql'
3
4
 
4
5
  export interface PathValidation {
@@ -28,8 +29,8 @@ export const doesPathExist = (schema: GraphQLSchema, path: PathValidation): bool
28
29
  if (!path.argument) return true
29
30
 
30
31
  // Check if argument exists
31
- const arg = field.args.find(a => a.name === path.argument)
32
- return !!arg
32
+ const arg = Array.findFirst(field.args, a => a.name === path.argument)
33
+ return Option.isSome(arg)
33
34
  }
34
35
 
35
36
  /**