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.
- package/build/api/builder/ssg/generate.d.ts.map +1 -1
- package/build/api/builder/ssg/generate.js +5 -5
- package/build/api/builder/ssg/generate.js.map +1 -1
- package/build/api/builder/ssg/page-generator.worker.js +13 -3
- package/build/api/builder/ssg/page-generator.worker.js.map +1 -1
- package/build/api/config/input.d.ts +88 -3
- package/build/api/config/input.d.ts.map +1 -1
- package/build/api/config/normalized.d.ts +92 -7
- package/build/api/config/normalized.d.ts.map +1 -1
- package/build/api/config/normalized.js +11 -3
- package/build/api/config/normalized.js.map +1 -1
- package/build/api/config-template/template.js +2 -2
- package/build/api/config-template/template.js.map +1 -1
- package/build/api/content/sidebar.d.ts.map +1 -1
- package/build/api/content/sidebar.js +2 -1
- package/build/api/content/sidebar.js.map +1 -1
- package/build/api/examples/config.d.ts +366 -3
- package/build/api/examples/config.d.ts.map +1 -1
- package/build/api/examples/config.js +25 -3
- package/build/api/examples/config.js.map +1 -1
- package/build/api/examples/diagnostic/diagnostic.d.ts +1 -1
- package/build/api/examples/diagnostic/validation-error.d.ts +3 -2
- package/build/api/examples/diagnostic/validation-error.d.ts.map +1 -1
- package/build/api/examples/diagnostic/validation-error.js +9 -3
- package/build/api/examples/diagnostic/validation-error.js.map +1 -1
- package/build/api/examples/diagnostic/validator.d.ts.map +1 -1
- package/build/api/examples/diagnostic/validator.js +115 -68
- package/build/api/examples/diagnostic/validator.js.map +1 -1
- package/build/api/examples/filter.d.ts.map +1 -1
- package/build/api/examples/filter.js +9 -6
- package/build/api/examples/filter.js.map +1 -1
- package/build/api/examples/scanner.d.ts.map +1 -1
- package/build/api/examples/scanner.js +89 -103
- package/build/api/examples/scanner.js.map +1 -1
- package/build/api/examples/type-usage-indexer.d.ts.map +1 -1
- package/build/api/examples/type-usage-indexer.js +17 -30
- package/build/api/examples/type-usage-indexer.js.map +1 -1
- package/build/api/iso/schema/routing.d.ts.map +1 -1
- package/build/api/iso/schema/routing.js +8 -8
- package/build/api/iso/schema/routing.js.map +1 -1
- package/build/api/iso/schema/validation.d.ts.map +1 -1
- package/build/api/iso/schema/validation.js +3 -2
- package/build/api/iso/schema/validation.js.map +1 -1
- package/build/api/schema/input-sources/directory.js +2 -2
- package/build/api/schema/input-sources/directory.js.map +1 -1
- package/build/api/schema/input-sources/versioned-directory.d.ts.map +1 -1
- package/build/api/schema/input-sources/versioned-directory.js +3 -3
- package/build/api/schema/input-sources/versioned-directory.js.map +1 -1
- package/build/api/schema/load.d.ts.map +1 -1
- package/build/api/schema/load.js +1 -1
- package/build/api/schema/load.js.map +1 -1
- package/build/lib/catalog/catalog.d.ts +43 -3
- package/build/lib/catalog/catalog.d.ts.map +1 -1
- package/build/lib/catalog/catalog.js +67 -5
- package/build/lib/catalog/catalog.js.map +1 -1
- package/build/lib/catalog/versioned.d.ts +11 -1
- package/build/lib/catalog/versioned.d.ts.map +1 -1
- package/build/lib/catalog/versioned.js +23 -5
- package/build/lib/catalog/versioned.js.map +1 -1
- package/build/lib/document/document.d.ts +55 -5
- package/build/lib/document/document.d.ts.map +1 -1
- package/build/lib/document/document.js +96 -2
- package/build/lib/document/document.js.map +1 -1
- package/build/lib/document/versioned.d.ts +2 -2
- package/build/lib/document/versioned.d.ts.map +1 -1
- package/build/lib/document/versioned.js +7 -7
- package/build/lib/document/versioned.js.map +1 -1
- package/build/lib/lifecycles/lifecycles.d.ts +5 -4
- package/build/lib/lifecycles/lifecycles.d.ts.map +1 -1
- package/build/lib/lifecycles/lifecycles.js +14 -12
- package/build/lib/lifecycles/lifecycles.js.map +1 -1
- package/build/lib/version-coverage/$$.d.ts +2 -0
- package/build/lib/version-coverage/$$.d.ts.map +1 -0
- package/build/lib/version-coverage/$$.js +2 -0
- package/build/lib/version-coverage/$$.js.map +1 -0
- package/build/lib/version-coverage/$.d.ts.map +1 -0
- package/build/lib/version-coverage/$.js.map +1 -0
- package/build/lib/{version-selection/version-selection.d.ts → version-coverage/version-coverage.d.ts} +1 -1
- package/build/lib/version-coverage/version-coverage.d.ts.map +1 -0
- package/build/lib/{version-selection/version-selection.js → version-coverage/version-coverage.js} +2 -2
- package/build/lib/version-coverage/version-coverage.js.map +1 -0
- package/build/template/components/GraphQLDocument.d.ts +1 -1
- package/build/template/components/GraphQLDocument.d.ts.map +1 -1
- package/build/template/components/GraphQLDocument.js +10 -39
- package/build/template/components/GraphQLDocument.js.map +1 -1
- package/build/template/components/GraphQLInteractive/lib/parser.d.ts +28 -0
- package/build/template/components/GraphQLInteractive/lib/parser.d.ts.map +1 -1
- package/build/template/components/GraphQLInteractive/lib/parser.js +60 -27
- package/build/template/components/GraphQLInteractive/lib/parser.js.map +1 -1
- package/build/template/components/VersionCoveragePicker.d.ts +1 -1
- package/build/template/components/VersionCoveragePicker.d.ts.map +1 -1
- package/build/template/components/VersionCoveragePicker.js +4 -6
- package/build/template/components/VersionCoveragePicker.js.map +1 -1
- package/build/template/components/home/QuickStart.d.ts.map +1 -1
- package/build/template/components/home/QuickStart.js +8 -4
- package/build/template/components/home/QuickStart.js.map +1 -1
- package/build/template/hooks/use-highlighted.d.ts.map +1 -1
- package/build/template/hooks/use-highlighted.js +19 -13
- package/build/template/hooks/use-highlighted.js.map +1 -1
- package/build/template/lib/fetch-text.d.ts +18 -0
- package/build/template/lib/fetch-text.d.ts.map +1 -1
- package/build/template/lib/fetch-text.js +32 -4
- package/build/template/lib/fetch-text.js.map +1 -1
- package/build/template/routes/examples/name.d.ts.map +1 -1
- package/build/template/routes/examples/name.js +4 -2
- package/build/template/routes/examples/name.js.map +1 -1
- package/build/template/stores/toast.d.ts.map +1 -1
- package/build/template/stores/toast.js +5 -3
- package/build/template/stores/toast.js.map +1 -1
- package/package.json +7 -7
- package/src/api/builder/ssg/generate.ts +10 -5
- package/src/api/builder/ssg/page-generator.worker.ts +18 -3
- package/src/api/config/normalized.ts +12 -3
- package/src/api/config-template/template.ts +2 -2
- package/src/api/content/sidebar.ts +3 -3
- package/src/api/examples/config.test.ts +10 -0
- package/src/api/examples/config.ts +33 -4
- package/src/api/examples/diagnostic/validation-error.ts +9 -3
- package/src/api/examples/diagnostic/validator.test.ts +30 -0
- package/src/api/examples/diagnostic/validator.ts +148 -103
- package/src/api/examples/filter.ts +9 -6
- package/src/api/examples/scanner.ts +136 -117
- package/src/api/examples/type-usage-indexer.ts +24 -36
- package/src/api/iso/schema/routing.ts +10 -10
- package/src/api/iso/schema/validation.ts +3 -2
- package/src/api/schema/input-sources/directory.ts +2 -2
- package/src/api/schema/input-sources/versioned-directory.ts +5 -7
- package/src/api/schema/load.ts +1 -1
- package/src/lib/catalog/catalog.ts +89 -6
- package/src/lib/catalog/versioned.ts +26 -5
- package/src/lib/document/document.ts +135 -2
- package/src/lib/document/versioned.ts +8 -8
- package/src/lib/lifecycles/lifecycles.ts +32 -27
- package/src/lib/version-coverage/$$.ts +1 -0
- package/src/lib/{version-selection/version-selection.ts → version-coverage/version-coverage.ts} +1 -1
- package/src/template/components/GraphQLDocument.tsx +11 -69
- package/src/template/components/GraphQLInteractive/lib/parser.ts +81 -29
- package/src/template/components/VersionCoveragePicker.tsx +4 -5
- package/src/template/components/home/QuickStart.tsx +16 -7
- package/src/template/hooks/use-highlighted.ts +31 -19
- package/src/template/lib/fetch-text.ts +45 -4
- package/src/template/routes/examples/name.tsx +4 -2
- package/src/template/stores/toast.ts +6 -3
- package/build/lib/graph/$$.d.ts +0 -2
- package/build/lib/graph/$$.d.ts.map +0 -1
- package/build/lib/graph/$$.js +0 -2
- package/build/lib/graph/$$.js.map +0 -1
- package/build/lib/graph/$.d.ts +0 -2
- package/build/lib/graph/$.d.ts.map +0 -1
- package/build/lib/graph/$.js +0 -2
- package/build/lib/graph/$.js.map +0 -1
- package/build/lib/graph/graph.d.ts +0 -127
- package/build/lib/graph/graph.d.ts.map +0 -1
- package/build/lib/graph/graph.js +0 -152
- package/build/lib/graph/graph.js.map +0 -1
- package/build/lib/mask/$$.d.ts +0 -3
- package/build/lib/mask/$$.d.ts.map +0 -1
- package/build/lib/mask/$$.js +0 -3
- package/build/lib/mask/$$.js.map +0 -1
- package/build/lib/mask/$.d.ts +0 -2
- package/build/lib/mask/$.d.ts.map +0 -1
- package/build/lib/mask/$.js +0 -2
- package/build/lib/mask/$.js.map +0 -1
- package/build/lib/mask/apply.d.ts +0 -86
- package/build/lib/mask/apply.d.ts.map +0 -1
- package/build/lib/mask/apply.js +0 -86
- package/build/lib/mask/apply.js.map +0 -1
- package/build/lib/mask/mask.d.ts +0 -124
- package/build/lib/mask/mask.d.ts.map +0 -1
- package/build/lib/mask/mask.js +0 -137
- package/build/lib/mask/mask.js.map +0 -1
- package/build/lib/mask/mask.test-d.d.ts +0 -2
- package/build/lib/mask/mask.test-d.d.ts.map +0 -1
- package/build/lib/mask/mask.test-d.js +0 -102
- package/build/lib/mask/mask.test-d.js.map +0 -1
- package/build/lib/version-selection/$$.d.ts +0 -2
- package/build/lib/version-selection/$$.d.ts.map +0 -1
- package/build/lib/version-selection/$$.js +0 -2
- package/build/lib/version-selection/$$.js.map +0 -1
- package/build/lib/version-selection/$.d.ts.map +0 -1
- package/build/lib/version-selection/$.js.map +0 -1
- package/build/lib/version-selection/version-selection.d.ts.map +0 -1
- package/build/lib/version-selection/version-selection.js.map +0 -1
- package/src/lib/graph/$$.ts +0 -1
- package/src/lib/graph/$.ts +0 -1
- package/src/lib/graph/graph.ts +0 -197
- package/src/lib/mask/$$.ts +0 -2
- package/src/lib/mask/$.test.ts +0 -226
- package/src/lib/mask/$.ts +0 -1
- package/src/lib/mask/apply.ts +0 -134
- package/src/lib/mask/mask.test-d.ts +0 -156
- package/src/lib/mask/mask.ts +0 -244
- package/src/lib/version-selection/$$.ts +0 -1
- /package/build/lib/{version-selection → version-coverage}/$.d.ts +0 -0
- /package/build/lib/{version-selection → version-coverage}/$.js +0 -0
- /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-
|
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
|
65
|
+
const parseExampleFile = (filename: string): ParsedExampleFile => {
|
52
66
|
const parsed = Path.parse(filename)
|
53
67
|
const base = parsed.name
|
54
68
|
|
@@ -60,32 +74,96 @@ const parseExampleFilename = (filename: string): { name: string; version: string
|
|
60
74
|
|
61
75
|
// Handle special 'default' keyword
|
62
76
|
if (versionStr === 'default') {
|
63
|
-
return {
|
77
|
+
return { type: 'default', name, file: filename }
|
64
78
|
}
|
65
|
-
|
66
|
-
|
67
|
-
return { name, version:
|
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,
|
85
|
+
return { type: 'unversioned', name: base, file: filename }
|
72
86
|
}
|
73
87
|
|
74
|
-
const groupExampleFiles = (files: string[]):
|
75
|
-
const grouped = new Map
|
88
|
+
const groupExampleFiles = (files: string[]): GroupedExampleFiles => {
|
89
|
+
const grouped: GroupedExampleFiles = new Map()
|
76
90
|
|
77
91
|
for (const file of files) {
|
78
|
-
const
|
92
|
+
const parsed = parseExampleFile(file)
|
79
93
|
|
80
|
-
if (!grouped.has(name)) {
|
81
|
-
grouped.set(name,
|
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,
|
@@ -105,7 +183,10 @@ 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 missingVersions =
|
186
|
+
const missingVersions = Array.filter(
|
187
|
+
schemaVersions,
|
188
|
+
sv => !Array.some(coveredVersions, cv => Version.equivalence(sv, cv)),
|
189
|
+
)
|
109
190
|
|
110
191
|
if (missingVersions.length > 0) {
|
111
192
|
diagnostics.push(makeDiagnosticMissingVersions({
|
@@ -117,7 +198,7 @@ const lintFileLayout = (
|
|
117
198
|
}
|
118
199
|
|
119
200
|
// Check for duplicate content between selections
|
120
|
-
const entries =
|
201
|
+
const entries = [...HashMap.entries(doc.versionDocuments)]
|
121
202
|
const duplicates: Array<{ version1: string; version2: string }> = []
|
122
203
|
for (let i = 0; i < entries.length; i++) {
|
123
204
|
for (let j = i + 1; j < entries.length; j++) {
|
@@ -161,32 +242,41 @@ export const scan = (
|
|
161
242
|
const pattern = `**/*.{${extensions.join(',')}}`
|
162
243
|
const files = options.files ?? (yield* EffectGlob.glob(pattern, { cwd: options.dir }))
|
163
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
|
+
|
164
253
|
// Group files by example
|
165
254
|
const groupedFiles = groupExampleFiles(files)
|
166
255
|
|
256
|
+
// Resolve .default files into proper version coverage immediately
|
257
|
+
const resolvedFiles = resolveDefaultFiles(groupedFiles, schemaVersions)
|
258
|
+
|
167
259
|
// Process each example group
|
168
260
|
const examples: Example.Example[] = []
|
169
261
|
const diagnostics: Diagnostic[] = []
|
170
262
|
|
171
|
-
for (const [name,
|
172
|
-
// Check if this is a versioned or unversioned example
|
173
|
-
const hasMultipleVersions = versions.size > 1
|
174
|
-
const hasUnversionedFile = versions.has(null)
|
175
|
-
const hasDefaultFile = versions.has('default')
|
176
|
-
const hasOnlyDefaultFile = hasDefaultFile && versions.size === 1
|
177
|
-
|
263
|
+
for (const [name, resolved] of resolvedFiles) {
|
178
264
|
// Determine the base path for this example
|
179
|
-
const
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
183
274
|
|
184
|
-
let example: Example.Example
|
275
|
+
let example: Example.Example | undefined
|
185
276
|
|
186
|
-
if (
|
277
|
+
if (resolved.unversioned) {
|
187
278
|
// Unversioned example - single file with no version
|
188
|
-
const
|
189
|
-
const fullPath = Path.join(options.dir, filePath)
|
279
|
+
const fullPath = Path.join(options.dir, resolved.unversioned)
|
190
280
|
const document = yield* fs.readFileString(fullPath)
|
191
281
|
|
192
282
|
example = Example.make({
|
@@ -196,104 +286,36 @@ export const scan = (
|
|
196
286
|
document,
|
197
287
|
}),
|
198
288
|
})
|
199
|
-
} else if (
|
200
|
-
//
|
201
|
-
const filePath = versions.get('default')!
|
202
|
-
const fullPath = Path.join(options.dir, filePath)
|
203
|
-
const documentContent = yield* fs.readFileString(fullPath)
|
204
|
-
|
205
|
-
// Get all schema versions to map to this default document
|
206
|
-
const schemaVersions: Version.Version[] = options.schemaCatalog
|
207
|
-
? SchemaCatalog.fold(
|
208
|
-
(versioned) => SchemaCatalog.Versioned.getVersions(versioned),
|
209
|
-
() => [], // Unversioned schemas don't have version-specific examples
|
210
|
-
)(options.schemaCatalog)
|
211
|
-
: []
|
212
|
-
|
213
|
-
if (schemaVersions.length > 0) {
|
214
|
-
// Create a version set for all schema versions
|
215
|
-
const versionSet = HashSet.fromIterable(schemaVersions)
|
216
|
-
let versionDocuments = HashMap.empty<VersionCoverage.VersionCoverage, string>()
|
217
|
-
versionDocuments = HashMap.set(versionDocuments, versionSet, documentContent)
|
218
|
-
|
219
|
-
example = Example.make({
|
220
|
-
name,
|
221
|
-
path: basePath,
|
222
|
-
document: Document.Versioned.make({
|
223
|
-
versionDocuments,
|
224
|
-
}),
|
225
|
-
})
|
226
|
-
} else {
|
227
|
-
// No schema versions, treat as unversioned
|
228
|
-
example = Example.make({
|
229
|
-
name,
|
230
|
-
path: basePath,
|
231
|
-
document: Document.Unversioned.make({
|
232
|
-
document: documentContent,
|
233
|
-
}),
|
234
|
-
})
|
235
|
-
}
|
236
|
-
} else {
|
237
|
-
// Versioned example - multiple files or versioned files
|
289
|
+
} else if (HashMap.size(resolved.versionDocuments) > 0) {
|
290
|
+
// Versioned example - read all version documents
|
238
291
|
let versionDocuments = HashMap.empty<VersionCoverage.VersionCoverage, string>()
|
239
|
-
let defaultDocument: string | undefined
|
240
|
-
let explicitVersions = HashSet.empty<Version.Version>() // Track which versions have explicit files
|
241
292
|
const unknownVersions: Version.Version[] = []
|
242
|
-
|
243
|
-
// Get available schema versions if catalog is provided
|
244
|
-
const schemaVersions: Version.Version[] = options.schemaCatalog
|
245
|
-
? SchemaCatalog.fold(
|
246
|
-
(versioned) => SchemaCatalog.Versioned.getVersions(versioned),
|
247
|
-
() => [], // Unversioned schemas don't have version-specific examples
|
248
|
-
)(options.schemaCatalog)
|
249
|
-
: []
|
250
|
-
|
251
|
-
// Create HashSet for O(1) lookups
|
252
293
|
const schemaVersionsSet = HashSet.fromIterable(schemaVersions)
|
253
294
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
if (version === 'default') {
|
260
|
-
defaultDocument = fileContent
|
261
|
-
} else if (version !== null) {
|
262
|
-
// Parse the version string
|
263
|
-
const parsedVersion = Version.decodeSync(version)
|
264
|
-
// Check if this version exists in the schema
|
265
|
-
const versionExists = HashSet.has(schemaVersionsSet, parsedVersion)
|
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)
|
266
299
|
if (options.schemaCatalog && schemaVersions.length > 0 && !versionExists) {
|
267
|
-
unknownVersions.push(
|
300
|
+
unknownVersions.push(versionCoverage)
|
268
301
|
// Create diagnostic for unknown version
|
269
302
|
diagnostics.push(makeDiagnosticUnknownVersion({
|
270
|
-
message: `Example "${name}" specifies version "${
|
303
|
+
message: `Example "${name}" specifies version "${
|
304
|
+
Version.encodeSync(versionCoverage)
|
305
|
+
}" which does not exist in the schema`,
|
271
306
|
example: { name, path: basePath },
|
272
|
-
version:
|
307
|
+
version: versionCoverage,
|
273
308
|
availableVersions: schemaVersions,
|
274
309
|
}))
|
275
310
|
// Skip this version - don't include it in the example
|
276
311
|
continue
|
277
312
|
}
|
278
|
-
|
279
|
-
// We already have parsedVersion from above
|
280
|
-
versionDocuments = HashMap.set(versionDocuments, parsedVersion, fileContent)
|
281
|
-
explicitVersions = HashSet.add(explicitVersions, parsedVersion)
|
282
313
|
}
|
283
|
-
}
|
284
|
-
|
285
|
-
if (defaultDocument) {
|
286
|
-
// If we have a default, determine which versions it applies to
|
287
|
-
const defaultVersions = schemaVersions.filter(v => !HashSet.has(explicitVersions, v))
|
288
314
|
|
289
|
-
|
290
|
-
|
291
|
-
const defaultVersionSet = defaultVersions.length === 1
|
292
|
-
? defaultVersions[0]! // Single version
|
293
|
-
: HashSet.fromIterable(defaultVersions) // Version set
|
315
|
+
const fullPath = Path.join(options.dir, filePath)
|
316
|
+
const fileContent = yield* fs.readFileString(fullPath)
|
294
317
|
|
295
|
-
|
296
|
-
}
|
318
|
+
versionDocuments = HashMap.set(versionDocuments, versionCoverage, fileContent)
|
297
319
|
}
|
298
320
|
|
299
321
|
if (HashMap.size(versionDocuments) > 0) {
|
@@ -308,9 +330,6 @@ export const scan = (
|
|
308
330
|
} else if (unknownVersions.length > 0) {
|
309
331
|
// All versions were unknown, skip this example entirely
|
310
332
|
continue
|
311
|
-
} else {
|
312
|
-
// No versions at all - shouldn't happen
|
313
|
-
continue
|
314
333
|
}
|
315
334
|
}
|
316
335
|
|
@@ -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
|
80
|
-
if (!parentTypeName) return
|
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
|
83
|
+
return Option.none()
|
85
84
|
}
|
86
85
|
|
87
86
|
const field = parentType.getFields()[fieldName]
|
88
|
-
if (!field) return
|
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
|
124
|
-
if (
|
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,29 +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
|
-
// Use HashMap.get for O(1) lookup
|
176
|
-
return HashMap.get(catalog.entries, version).pipe(Option.getOrElse(() => undefined))
|
177
|
-
}
|
178
|
-
// For unversioned catalog, return the single schema if version matches
|
179
|
-
if (Catalog.Unversioned.is(catalog)) {
|
180
|
-
// Unversioned catalogs don't have versions, so we can't match
|
181
|
-
return undefined
|
182
|
-
}
|
183
|
-
return undefined
|
184
|
-
}
|
185
|
-
|
186
163
|
// ============================================================================
|
187
164
|
// Index Creation
|
188
165
|
// ============================================================================
|
@@ -208,7 +185,10 @@ export const createTypeUsageIndex = (
|
|
208
185
|
|
209
186
|
for (const typeName of types) {
|
210
187
|
// For unversioned, use the latest version from the catalog
|
211
|
-
const latestVersion =
|
188
|
+
const latestVersion = Option.getOrElse(
|
189
|
+
Catalog.getLatestVersion(schemasCatalog),
|
190
|
+
() => Version.fromString('1.0.0'),
|
191
|
+
)
|
212
192
|
index = addExampleToIndex(index, UNVERSIONED_KEY, typeName, example, latestVersion)
|
213
193
|
}
|
214
194
|
} else if (Document.Versioned.is(example.document)) {
|
@@ -216,11 +196,19 @@ export const createTypeUsageIndex = (
|
|
216
196
|
const allVersions = Document.Versioned.getAllVersions(example.document)
|
217
197
|
|
218
198
|
for (const version of allVersions) {
|
219
|
-
|
220
|
-
|
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
|
221
208
|
|
222
|
-
const
|
223
|
-
if (
|
209
|
+
const documentStringOption = Document.Versioned.getContentForVersion(example.document, version)
|
210
|
+
if (Option.isNone(documentStringOption)) continue
|
211
|
+
const documentString = documentStringOption.value
|
224
212
|
|
225
213
|
const types = extractTypesFromQuery(documentString, schema.definition)
|
226
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
|
50
|
-
.flat()
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
32
|
-
return
|
32
|
+
const arg = Array.findFirst(field.args, a => a.name === path.argument)
|
33
|
+
return Option.isSome(arg)
|
33
34
|
}
|
34
35
|
|
35
36
|
/**
|
@@ -98,8 +98,8 @@ export const loader = InputSource.createEffect({
|
|
98
98
|
// Check if we have either:
|
99
99
|
// 1. A single schema.graphql file (non-versioned mode)
|
100
100
|
// 2. Any .graphql files with valid date names (versioned mode)
|
101
|
-
const hasSchemaFile =
|
102
|
-
const hasVersionedFiles =
|
101
|
+
const hasSchemaFile = Array.some(files, file => file === 'schema.graphql')
|
102
|
+
const hasVersionedFiles = Array.some(files, file => {
|
103
103
|
if (!file.endsWith('.graphql')) return false
|
104
104
|
const name = Path.basename(file, '.graphql')
|
105
105
|
return /^\d{4}-\d{2}-\d{2}$/.test(name)
|
@@ -10,7 +10,7 @@ import { debugPolen } from '#singletons/debug'
|
|
10
10
|
import { PlatformError } from '@effect/platform/Error'
|
11
11
|
import { FileSystem } from '@effect/platform/FileSystem'
|
12
12
|
import { Arr, Path } from '@wollybeard/kit'
|
13
|
-
import { Effect, HashMap } from 'effect'
|
13
|
+
import { Array, Effect, HashMap } from 'effect'
|
14
14
|
import type { GraphQLSchema } from 'graphql'
|
15
15
|
|
16
16
|
const debug = debugPolen.sub(`schema:data-source-versioned-schema-directory`)
|
@@ -452,9 +452,8 @@ export const loader = InputSource.createEffect({
|
|
452
452
|
// Check for revision files or schema.graphql
|
453
453
|
const dirFiles = yield* Effect.either(fs.readDirectory(versionPath))
|
454
454
|
if (dirFiles._tag === 'Right') {
|
455
|
-
const hasRevisions = dirFiles.right
|
456
|
-
/^\d{4}-\d{2}-\d{2}\.graphql$/.test(file) || file === 'schema.graphql'
|
457
|
-
)
|
455
|
+
const hasRevisions = Array.some(dirFiles.right, file =>
|
456
|
+
/^\d{4}-\d{2}-\d{2}\.graphql$/.test(file) || file === 'schema.graphql')
|
458
457
|
if (hasRevisions) {
|
459
458
|
return true
|
460
459
|
}
|
@@ -520,9 +519,8 @@ export const loader = InputSource.createEffect({
|
|
520
519
|
// Check for schema files
|
521
520
|
const dirFiles = yield* Effect.either(fs.readDirectory(versionPath))
|
522
521
|
if (dirFiles._tag === 'Right') {
|
523
|
-
const hasSchemaFiles = dirFiles.right
|
524
|
-
/^\d{4}-\d{2}-\d{2}\.graphql$/.test(file) || file === 'schema.graphql'
|
525
|
-
)
|
522
|
+
const hasSchemaFiles = Array.some(dirFiles.right, file =>
|
523
|
+
/^\d{4}-\d{2}-\d{2}\.graphql$/.test(file) || file === 'schema.graphql')
|
526
524
|
|
527
525
|
if (hasSchemaFiles) {
|
528
526
|
debug('found valid schema files, proceeding with full read')
|
package/src/api/schema/load.ts
CHANGED
@@ -7,7 +7,7 @@ import { Catalog } from '#lib/catalog/$'
|
|
7
7
|
import type { PlatformError } from '@effect/platform/Error'
|
8
8
|
import type { FileSystem } from '@effect/platform/FileSystem'
|
9
9
|
import { Arr } from '@wollybeard/kit'
|
10
|
-
import { Effect } from 'effect'
|
10
|
+
import { Array, Effect, Option } from 'effect'
|
11
11
|
|
12
12
|
// For now, we'll need a type that accepts both promise and effect sources
|
13
13
|
type AnyInputSource = InputSource | EffectInputSource
|