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.
- 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 +5 -5
- package/build/api/examples/diagnostic/missing-versions.d.ts +5 -4
- package/build/api/examples/diagnostic/missing-versions.d.ts.map +1 -1
- package/build/api/examples/diagnostic/missing-versions.js +3 -2
- package/build/api/examples/diagnostic/missing-versions.js.map +1 -1
- package/build/api/examples/diagnostic/unknown-version.d.ts +5 -4
- package/build/api/examples/diagnostic/unknown-version.d.ts.map +1 -1
- package/build/api/examples/diagnostic/unknown-version.js +3 -2
- package/build/api/examples/diagnostic/unknown-version.js.map +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 -69
- 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 +93 -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 +18 -32
- 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 +3 -3
- package/build/api/schema/input-sources/versioned-directory.d.ts.map +1 -1
- package/build/api/schema/input-sources/versioned-directory.js +6 -4
- 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 +2 -2
- package/build/api/schema/load.js.map +1 -1
- package/build/cli/commands/hero-image.js +1 -1
- package/build/cli/commands/hero-image.js.map +1 -1
- package/build/lib/catalog/catalog.d.ts +65 -24
- package/build/lib/catalog/catalog.d.ts.map +1 -1
- package/build/lib/catalog/catalog.js +72 -16
- package/build/lib/catalog/catalog.js.map +1 -1
- package/build/lib/catalog/versioned.d.ts +46 -26
- package/build/lib/catalog/versioned.d.ts.map +1 -1
- package/build/lib/catalog/versioned.js +44 -7
- package/build/lib/catalog/versioned.js.map +1 -1
- package/build/lib/catalog-statistics/analyze-catalog.js +3 -3
- package/build/lib/catalog-statistics/analyze-catalog.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 +15 -13
- 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/Changelog/Changelog.d.ts.map +1 -1
- package/build/template/components/Changelog/Changelog.js +7 -7
- package/build/template/components/Changelog/Changelog.js.map +1 -1
- 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 -38
- 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/VersionPicker.d.ts.map +1 -1
- package/build/template/components/VersionPicker.js +5 -2
- package/build/template/components/VersionPicker.js.map +1 -1
- package/build/template/components/home/FeaturesGrid.js +1 -1
- package/build/template/components/home/FeaturesGrid.js.map +1 -1
- package/build/template/components/home/HeroSection.js +1 -1
- package/build/template/components/home/HeroSection.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/components/home/RecentChanges.d.ts.map +1 -1
- package/build/template/components/home/RecentChanges.js +2 -1
- package/build/template/components/home/RecentChanges.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/changelog.d.ts +1 -1
- package/build/template/routes/changelog.d.ts.map +1 -1
- package/build/template/routes/changelog.js +7 -4
- package/build/template/routes/changelog.js.map +1 -1
- package/build/template/routes/examples/_index.js +1 -1
- package/build/template/routes/examples/_index.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/routes/reference.js +6 -6
- package/build/template/routes/reference.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/build/vite/plugins/navbar.js +1 -1
- package/build/vite/plugins/navbar.js.map +1 -1
- package/build/vite/plugins/routes-manifest.js +1 -1
- package/build/vite/plugins/routes-manifest.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/missing-versions.ts +3 -2
- package/src/api/examples/diagnostic/unknown-version.ts +3 -2
- package/src/api/examples/diagnostic/validation-error.ts +9 -3
- package/src/api/examples/diagnostic/validator.test.ts +100 -55
- package/src/api/examples/diagnostic/validator.ts +148 -105
- package/src/api/examples/filter.ts +9 -6
- package/src/api/examples/scanner.ts +144 -120
- package/src/api/examples/type-usage-indexer.test.ts +44 -33
- package/src/api/examples/type-usage-indexer.ts +25 -40
- package/src/api/iso/schema/routing.ts +10 -10
- package/src/api/iso/schema/validation.ts +3 -2
- package/src/api/schema/$.test.ts +2 -2
- package/src/api/schema/input-sources/directory.ts +2 -2
- package/src/api/schema/input-sources/versioned-directory.ts +11 -8
- package/src/api/schema/load.ts +2 -2
- package/src/cli/commands/hero-image.ts +1 -1
- package/src/lib/catalog/catalog.ts +93 -16
- package/src/lib/catalog/versioned.ts +57 -7
- package/src/lib/catalog-statistics/$.test.ts +22 -12
- package/src/lib/catalog-statistics/analyze-catalog.ts +3 -3
- package/src/lib/document/document.ts +135 -2
- package/src/lib/document/versioned.ts +8 -8
- package/src/lib/lifecycles/lifecycles.ts +33 -28
- 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/Changelog/Changelog.tsx +10 -6
- package/src/template/components/GraphQLDocument.tsx +11 -68
- package/src/template/components/GraphQLInteractive/lib/parser.ts +81 -29
- package/src/template/components/VersionCoveragePicker.tsx +4 -5
- package/src/template/components/VersionPicker.tsx +9 -2
- package/src/template/components/home/FeaturesGrid.tsx +1 -1
- package/src/template/components/home/HeroSection.tsx +1 -1
- package/src/template/components/home/QuickStart.tsx +16 -7
- package/src/template/components/home/RecentChanges.tsx +3 -1
- package/src/template/hooks/use-highlighted.ts +31 -19
- package/src/template/lib/fetch-text.ts +45 -4
- package/src/template/routes/changelog.tsx +10 -4
- package/src/template/routes/examples/_index.tsx +1 -1
- package/src/template/routes/examples/name.tsx +4 -2
- package/src/template/routes/reference.tsx +6 -6
- package/src/template/stores/toast.ts +6 -3
- package/src/vite/plugins/navbar.ts +1 -1
- package/src/vite/plugins/routes-manifest.ts +1 -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/$.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
@@ -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
|
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(() =>
|
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
|
76
|
-
if (
|
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
|
104
|
-
if (
|
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
|
}
|
@@ -119,7 +121,7 @@ export const create = (catalog: Catalog.Catalog): Lifecycles => {
|
|
119
121
|
Catalog.fold(
|
120
122
|
// Versioned catalog - process each versioned schema
|
121
123
|
(versioned) => {
|
122
|
-
for (const schema of versioned
|
124
|
+
for (const schema of Catalog.Versioned.getAll(versioned)) {
|
123
125
|
processSchema(schema)
|
124
126
|
}
|
125
127
|
},
|
@@ -477,9 +479,9 @@ export const getFieldLifecycle = (
|
|
477
479
|
lifecycles: Lifecycles,
|
478
480
|
typeName: string,
|
479
481
|
fieldName: string,
|
480
|
-
): { events: ChangeEntry[] }
|
482
|
+
): Option.Option<{ events: ChangeEntry[] }> => {
|
481
483
|
const entries = lifecycles[typeName]
|
482
|
-
if (!entries) return
|
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
|
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 = (
|
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
|
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
|
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'
|
package/src/lib/{version-selection/version-selection.ts → version-coverage/version-coverage.ts}
RENAMED
@@ -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
|
/**
|
@@ -4,6 +4,7 @@ import { DateOnly } from '#lib/date-only/$'
|
|
4
4
|
import { Revision } from '#lib/revision/$'
|
5
5
|
import { Schema } from '#lib/schema/$'
|
6
6
|
import { Version } from '#lib/version/$'
|
7
|
+
import { HashMap, Option } from 'effect'
|
7
8
|
const CRITICALITY_LEVELS = ['BREAKING', 'DANGEROUS', 'NON_BREAKING'] as const
|
8
9
|
import type { CriticalityLevel } from '@graphql-inspector/core'
|
9
10
|
import { Box, Heading } from '@radix-ui/themes'
|
@@ -35,8 +36,7 @@ export const Changelog: React.FC<{ catalog: Catalog.Catalog }> = ({ catalog }) =
|
|
35
36
|
useEffect(() => {
|
36
37
|
if (urlVersion) return
|
37
38
|
if (Catalog.Unversioned.is(catalog)) return
|
38
|
-
const latestSchema = catalog
|
39
|
-
if (!latestSchema) return
|
39
|
+
const latestSchema = Catalog.Versioned.getLatestOrThrow(catalog)
|
40
40
|
const latestVersion = Version.encodeSync(latestSchema.version)
|
41
41
|
navigate(`/changelog/version/${latestVersion}`, { replace: true })
|
42
42
|
}, [catalog, urlVersion, navigate])
|
@@ -51,10 +51,14 @@ export const Changelog: React.FC<{ catalog: Catalog.Catalog }> = ({ catalog }) =
|
|
51
51
|
} else {
|
52
52
|
// For versioned catalogs, always show specific version (never all)
|
53
53
|
if (urlVersion) {
|
54
|
-
const
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
const entryOption = Option.map(
|
55
|
+
HashMap.findFirst(catalog.entries, (_, key) => Version.encodeSync(key) === urlVersion),
|
56
|
+
([, value]) => value,
|
57
|
+
)
|
58
|
+
return Option.match(entryOption, {
|
59
|
+
onNone: () => ({ revisions: [], schema: null }),
|
60
|
+
onSome: (entry) => ({ revisions: entry.revisions, schema: entry }),
|
61
|
+
})
|
58
62
|
}
|
59
63
|
// This shouldn't happen due to redirect above, but return empty as fallback
|
60
64
|
return { revisions: [], schema: null }
|
@@ -1,12 +1,7 @@
|
|
1
1
|
import { Catalog } from '#lib/catalog/$'
|
2
2
|
import { Document } from '#lib/document/$'
|
3
|
-
import {
|
4
|
-
import
|
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 } 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.
|
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,59 +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.getLatest(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 schema = schemaCatalog.entries.find(e => Version.equivalence(e.version, version))
|
138
|
-
if (!schema) {
|
139
|
-
throw new Error(`Version ${Version.encodeSync(version)} not found in catalog`)
|
140
|
-
}
|
141
|
-
|
142
|
-
return { content, schema: schema }
|
143
|
-
}),
|
144
|
-
)
|
145
|
-
}
|
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
import { Api } from '#api/iso'
|
9
9
|
import type { CodeAnnotation } from 'codehike/code'
|
10
|
+
import { Either } from 'effect'
|
10
11
|
import {
|
11
12
|
getNamedType,
|
12
13
|
type GraphQLArgument,
|
@@ -504,41 +505,65 @@ class SemanticContext {
|
|
504
505
|
}
|
505
506
|
|
506
507
|
/**
|
507
|
-
*
|
508
|
+
* Error types for GraphQL parsing
|
509
|
+
*/
|
510
|
+
export type ParseError =
|
511
|
+
| { readonly _tag: 'InvalidInput'; readonly message: string }
|
512
|
+
| { readonly _tag: 'DocumentTooLarge'; readonly maxSize: number; readonly actualSize: number }
|
513
|
+
| { readonly _tag: 'TreeSitterError'; readonly message: string }
|
514
|
+
| { readonly _tag: 'ParserInitError'; readonly message: string }
|
515
|
+
|
516
|
+
const makeParseError = {
|
517
|
+
invalidInput: (message: string): ParseError => ({ _tag: 'InvalidInput', message }),
|
518
|
+
documentTooLarge: (maxSize: number, actualSize: number): ParseError => ({
|
519
|
+
_tag: 'DocumentTooLarge',
|
520
|
+
maxSize,
|
521
|
+
actualSize,
|
522
|
+
}),
|
523
|
+
treeSitterError: (message: string): ParseError => ({ _tag: 'TreeSitterError', message }),
|
524
|
+
parserInitError: (message: string): ParseError => ({ _tag: 'ParserInitError', message }),
|
525
|
+
}
|
526
|
+
|
527
|
+
/**
|
528
|
+
* Parse GraphQL code into interactive tokens with semantic information (Either version)
|
508
529
|
*
|
509
530
|
* @param code - The raw GraphQL code to parse
|
510
531
|
* @param annotations - CodeHike annotations that might affect rendering
|
511
532
|
* @param schema - Optional GraphQL schema for semantic analysis
|
512
|
-
* @returns
|
533
|
+
* @returns Either with array of tokens on right or ParseError on left
|
513
534
|
*/
|
514
|
-
export async function
|
535
|
+
export async function parseGraphQLWithTreeSitterEither(
|
515
536
|
code: string,
|
516
537
|
annotations: CodeAnnotation[] = [],
|
517
538
|
schema?: GraphQLSchema,
|
518
|
-
): Promise<GraphQLToken[]
|
539
|
+
): Promise<Either.Either<GraphQLToken[], ParseError>> {
|
519
540
|
// Validate input
|
520
541
|
if (!code || typeof code !== 'string') {
|
521
|
-
|
542
|
+
return Either.left(makeParseError.invalidInput('Invalid GraphQL code: code must be a non-empty string'))
|
522
543
|
}
|
523
544
|
|
524
545
|
// Prevent parsing extremely large documents that could cause performance issues
|
525
|
-
|
526
|
-
|
546
|
+
const maxSize = 100_000
|
547
|
+
if (code.length > maxSize) {
|
548
|
+
return Either.left(makeParseError.documentTooLarge(maxSize, code.length))
|
527
549
|
}
|
528
550
|
|
529
551
|
// Step 1: Parse with tree-sitter
|
530
|
-
|
552
|
+
let parser: WebTreeSitter.Parser
|
553
|
+
try {
|
554
|
+
parser = await getParser()
|
555
|
+
} catch (error) {
|
556
|
+
return Either.left(makeParseError.parserInitError(
|
557
|
+
error instanceof Error ? error.message : 'Failed to initialize parser',
|
558
|
+
))
|
559
|
+
}
|
560
|
+
|
531
561
|
const tree = parser.parse(code)
|
532
562
|
|
533
563
|
if (!tree) {
|
534
|
-
|
564
|
+
return Either.left(makeParseError.treeSitterError('Tree-sitter failed to parse GraphQL code'))
|
535
565
|
}
|
536
566
|
|
537
|
-
// Check if tree-sitter found syntax errors (disabled for now as it may be too strict)
|
538
|
-
// if (tree.rootNode.hasError) {
|
539
|
-
// throw new Error('GraphQL syntax error detected by tree-sitter parser')
|
540
|
-
// }
|
541
|
-
|
542
567
|
try {
|
543
568
|
// Step 2: Walk tree and attach semantics
|
544
569
|
const tokens = collectTokensWithSemantics(tree, code, schema, annotations)
|
@@ -546,26 +571,53 @@ export async function parseGraphQLWithTreeSitter(
|
|
546
571
|
// Step 3: Add error hint tokens after invalid fields
|
547
572
|
const tokensWithHints = addErrorHintTokens(tokens, code, annotations)
|
548
573
|
|
549
|
-
return tokensWithHints
|
574
|
+
return Either.right(tokensWithHints)
|
575
|
+
} catch (error) {
|
576
|
+
return Either.left(makeParseError.treeSitterError(
|
577
|
+
error instanceof Error ? error.message : 'Failed to process tokens',
|
578
|
+
))
|
550
579
|
} finally {
|
551
|
-
//
|
552
|
-
//
|
553
|
-
// Tree-sitter creates native WASM objects that must be explicitly freed to prevent memory leaks.
|
554
|
-
// The tree object holds references to parsed nodes and internal parser state that won't be
|
555
|
-
// garbage collected automatically by JavaScript.
|
556
|
-
//
|
557
|
-
// Critical cleanup points:
|
558
|
-
// 1. Always call tree.delete() in a finally block to ensure cleanup even on errors
|
559
|
-
// 2. Do not access tree or any of its nodes after calling delete()
|
560
|
-
// 3. The parser instance is cached globally and reused across multiple parsing calls
|
561
|
-
//
|
562
|
-
// Memory safety: Once tree.delete() is called, all WebTreeSitter.Node references become invalid.
|
563
|
-
// Our tokens hold references to these nodes, but only use their text and position properties
|
564
|
-
// which are copied during token creation, so the nodes can be safely deleted.
|
580
|
+
// Tree-sitter Resource Lifecycle Management
|
565
581
|
tree.delete()
|
566
582
|
}
|
567
583
|
}
|
568
584
|
|
585
|
+
/**
|
586
|
+
* Parse GraphQL code into interactive tokens with semantic information
|
587
|
+
*
|
588
|
+
* @param code - The raw GraphQL code to parse
|
589
|
+
* @param annotations - CodeHike annotations that might affect rendering
|
590
|
+
* @param schema - Optional GraphQL schema for semantic analysis
|
591
|
+
* @returns Array of tokens representing the parsed code
|
592
|
+
* @deprecated Use parseGraphQLWithTreeSitterEither for better error handling
|
593
|
+
*/
|
594
|
+
export async function parseGraphQLWithTreeSitter(
|
595
|
+
code: string,
|
596
|
+
annotations: CodeAnnotation[] = [],
|
597
|
+
schema?: GraphQLSchema,
|
598
|
+
): Promise<GraphQLToken[]> {
|
599
|
+
const result = await parseGraphQLWithTreeSitterEither(code, annotations, schema)
|
600
|
+
|
601
|
+
if (Either.isLeft(result)) {
|
602
|
+
const error = result.left
|
603
|
+
switch (error._tag) {
|
604
|
+
case 'InvalidInput':
|
605
|
+
throw new Error(error.message)
|
606
|
+
case 'DocumentTooLarge':
|
607
|
+
throw new Error(`GraphQL document too large: maximum ${error.maxSize} characters allowed`)
|
608
|
+
case 'TreeSitterError':
|
609
|
+
case 'ParserInitError':
|
610
|
+
throw new Error(error.message)
|
611
|
+
default: {
|
612
|
+
const exhaustiveCheck: never = error
|
613
|
+
throw new Error(`Unhandled parse error: ${JSON.stringify(exhaustiveCheck)}`)
|
614
|
+
}
|
615
|
+
}
|
616
|
+
}
|
617
|
+
|
618
|
+
return result.right
|
619
|
+
}
|
620
|
+
|
569
621
|
/**
|
570
622
|
* Get or create the tree-sitter parser instance
|
571
623
|
*/
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Catalog } from '#lib/catalog/$'
|
2
2
|
import { Document } from '#lib/document/$'
|
3
|
-
import { VersionCoverage } from '#lib/version-
|
3
|
+
import { VersionCoverage } from '#lib/version-coverage'
|
4
4
|
import { Select } from '@radix-ui/themes'
|
5
5
|
import { HashMap } from 'effect'
|
6
6
|
import type { FC } from 'react'
|
@@ -30,12 +30,11 @@ export const VersionCoveragePicker: FC<Props> = ({
|
|
30
30
|
<Select.Root
|
31
31
|
value={VersionCoverage.toLabel(current)}
|
32
32
|
onValueChange={(label) => {
|
33
|
-
// Find
|
33
|
+
// Find the full version coverage by label and pass it entirely
|
34
34
|
const selection = options.find(s => VersionCoverage.toLabel(s) === label)
|
35
35
|
if (selection) {
|
36
|
-
|
37
|
-
|
38
|
-
if (version) onChange(version)
|
36
|
+
// Pass the entire VersionCoverage, not just the first version
|
37
|
+
onChange(selection)
|
39
38
|
}
|
40
39
|
}}
|
41
40
|
>
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { Api } from '#api/iso'
|
2
2
|
import type { React } from '#dep/react/index'
|
3
|
+
import { Catalog } from '#lib/catalog/$'
|
3
4
|
import { Version } from '#lib/version/$'
|
5
|
+
import { HashMap, Option } from 'effect'
|
4
6
|
import { useNavigate } from 'react-router'
|
5
7
|
import { schemasCatalog } from 'virtual:polen/project/schemas'
|
6
8
|
import { useReferencePath } from '../hooks/useReferencePath.js'
|
@@ -33,12 +35,17 @@ export const VersionPicker: React.FC<Props> = ({ data, current }) => {
|
|
33
35
|
|
34
36
|
// Find the schema for the target version
|
35
37
|
// Note: newVersion is a string that we need to parse
|
36
|
-
const
|
38
|
+
const targetSchemaOption = Option.map(
|
39
|
+
HashMap.findFirst(catalog.entries, (_, key) => Version.encodeSync(key) === newVersion),
|
40
|
+
([, value]) => value,
|
41
|
+
)
|
37
42
|
|
38
|
-
if (
|
43
|
+
if (Option.isNone(targetSchemaOption)) {
|
39
44
|
throw new Error(`Version ${newVersion} not found`)
|
40
45
|
}
|
41
46
|
|
47
|
+
const targetSchema = Option.getOrThrow(targetSchemaOption)
|
48
|
+
|
42
49
|
// Find fallback path if needed
|
43
50
|
const fallbackPath = Api.Schema.Validation.findFallbackPath(targetSchema.definition, currentPath)
|
44
51
|
// Get redirect description if path changed
|
@@ -80,7 +80,7 @@ function getDefaultFeatures(): Feature[] {
|
|
80
80
|
if (schemasCatalog) {
|
81
81
|
try {
|
82
82
|
// Get the latest schema from the catalog
|
83
|
-
const latestSchema = Catalog.
|
83
|
+
const latestSchema = Catalog.getLatest(schemasCatalog)
|
84
84
|
|
85
85
|
if (latestSchema && latestSchema.definition) {
|
86
86
|
// Build stats from the schema definition
|
@@ -84,7 +84,7 @@ export const Hero: React.FC<HeroProps> = ({
|
|
84
84
|
let schemaStats = null
|
85
85
|
if (schemasCatalog) {
|
86
86
|
try {
|
87
|
-
const latestSchema = Catalog.
|
87
|
+
const latestSchema = Catalog.getLatest(schemasCatalog)
|
88
88
|
if (latestSchema && latestSchema.definition) {
|
89
89
|
const versionStats = CatalogStatistics.analyzeSchema(latestSchema.definition, 'current')
|
90
90
|
schemaStats = {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Box, Card, Heading, Section, Tabs, Text } from '@radix-ui/themes'
|
2
2
|
import { highlight } from 'codehike/code'
|
3
|
+
import { Effect } from 'effect'
|
3
4
|
import * as React from 'react'
|
4
5
|
import { CodeBlock } from '../CodeBlock.js'
|
5
6
|
|
@@ -73,14 +74,22 @@ export const QuickStartSection: React.FC<Props> = ({ examples = defaultExamples
|
|
73
74
|
|
74
75
|
React.useEffect(() => {
|
75
76
|
const highlightExamples = async () => {
|
76
|
-
const highlighted = await
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
const highlighted = await Effect.runPromise(
|
78
|
+
Effect.all(
|
79
|
+
examples.map((example) =>
|
80
|
+
Effect.tryPromise({
|
81
|
+
try: async () => ({
|
82
|
+
label: example.label,
|
83
|
+
codeblock: await highlight(
|
84
|
+
{ value: example.code, lang: example.language, meta: '' },
|
85
|
+
{ theme: 'github-light' },
|
86
|
+
),
|
87
|
+
}),
|
88
|
+
catch: (error) => new Error(`Failed to highlight ${example.label}: ${error}`),
|
89
|
+
})
|
82
90
|
),
|
83
|
-
|
91
|
+
{ concurrency: 'unbounded' },
|
92
|
+
),
|
84
93
|
)
|
85
94
|
setHighlightedExamples(highlighted)
|
86
95
|
}
|
@@ -3,6 +3,8 @@ import * as React from 'react'
|
|
3
3
|
import { Link } from 'react-router'
|
4
4
|
import { schemasCatalog } from 'virtual:polen/project/schemas'
|
5
5
|
|
6
|
+
import { Catalog } from '#lib/catalog'
|
7
|
+
|
6
8
|
interface RecentChangesProps {
|
7
9
|
limit?: number
|
8
10
|
showVersions?: boolean
|
@@ -30,7 +32,7 @@ export const RecentChangesSection: React.FC<RecentChangesProps> = ({
|
|
30
32
|
|
31
33
|
// For versioned catalogs, we look at entries
|
32
34
|
if (schemasCatalog._tag === 'CatalogVersioned') {
|
33
|
-
const entries = schemasCatalog
|
35
|
+
const entries = Catalog.Versioned.getAll(schemasCatalog)
|
34
36
|
const recentEntries = entries.slice(0, limit)
|
35
37
|
|
36
38
|
return recentEntries.flatMap(entry =>
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import type { HighlightedCode } from 'codehike/code'
|
2
2
|
import { highlight } from 'codehike/code'
|
3
|
+
import { Duration, Effect } from 'effect'
|
3
4
|
import * as React from 'react'
|
4
5
|
|
5
6
|
/**
|
@@ -29,26 +30,37 @@ export const useHighlighted = (
|
|
29
30
|
const [highlightedCode, setHighlightedCode] = React.useState<HighlightedCode | null>(null)
|
30
31
|
|
31
32
|
React.useEffect(() => {
|
32
|
-
const
|
33
|
-
// Add a timeout to detect if highlight is hanging
|
34
|
-
const timeoutPromise = new Promise((_, reject) => {
|
35
|
-
setTimeout(() => reject(new Error('Highlight timeout after 5 seconds')), 5000)
|
36
|
-
})
|
37
|
-
|
38
|
-
const highlightPromise = highlight(
|
39
|
-
{
|
40
|
-
value: content,
|
41
|
-
lang: config.lang,
|
42
|
-
meta: metaString,
|
43
|
-
},
|
44
|
-
{
|
45
|
-
theme: 'github-light',
|
46
|
-
},
|
47
|
-
)
|
33
|
+
const HIGHLIGHT_TIMEOUT = Duration.seconds(5)
|
48
34
|
|
49
|
-
|
50
|
-
|
51
|
-
|
35
|
+
const highlightContent = async () => {
|
36
|
+
try {
|
37
|
+
const highlighted = await Effect.runPromise(
|
38
|
+
Effect.tryPromise({
|
39
|
+
try: () =>
|
40
|
+
highlight(
|
41
|
+
{
|
42
|
+
value: content,
|
43
|
+
lang: config.lang,
|
44
|
+
meta: metaString,
|
45
|
+
},
|
46
|
+
{
|
47
|
+
theme: 'github-light',
|
48
|
+
},
|
49
|
+
),
|
50
|
+
catch: (error) => new Error(`Highlight failed: ${error}`),
|
51
|
+
}).pipe(
|
52
|
+
Effect.timeout(HIGHLIGHT_TIMEOUT),
|
53
|
+
Effect.catchTag(
|
54
|
+
'TimeoutException',
|
55
|
+
() => Effect.fail(new Error(`Highlight timeout after ${Duration.toSeconds(HIGHLIGHT_TIMEOUT)} seconds`)),
|
56
|
+
),
|
57
|
+
),
|
58
|
+
)
|
59
|
+
setHighlightedCode(highlighted)
|
60
|
+
} catch (error) {
|
61
|
+
console.error('Failed to highlight code:', error)
|
62
|
+
setHighlightedCode(null)
|
63
|
+
}
|
52
64
|
}
|
53
65
|
highlightContent()
|
54
66
|
}, [content, config.lang, config.interactive])
|