Skip to content

Commit f8d7dcb

Browse files
[feat] Add JSONSchemas (#3)
### TL;DR Added JSON schema definitions for the Component Gallery registry system. ### What changed? - Created `compiled.schema.json` which defines the structure for the compiled components catalog - Created `component.schema.json` which defines the structure for individual component submissions - Both schemas include detailed validation rules for component metadata including: - Required fields (title, author, links, categories) - Format validation for URLs, dates, and other fields - Constraints on field lengths and content patterns - Predefined category options for components ### Why make this change? These schema definitions provide a standardized structure for component submissions and the compiled catalog, ensuring: 1. Consistent data format for all components in the gallery 2. Proper validation of component metadata 3. Clear requirements for contributors submitting new components 4. Structured format for metrics and ranking data 5. Foundation for automated validation in the submission process
1 parent 30c00ae commit f8d7dcb

3 files changed

Lines changed: 285 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,6 @@ __marimo__/
214214

215215
# Streamlit
216216
.streamlit/secrets.toml
217+
218+
# MacOS
219+
.DS_Store
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://raw.githubusercontent.com/streamlit/gallery/main/components/registry/schemas/compiled.schema.json",
4+
"title": "Component Gallery compiled catalog (compiled/components.json)",
5+
"type": "object",
6+
"additionalProperties": false,
7+
"required": ["generatedAt", "schemaVersion", "categories", "components"],
8+
"properties": {
9+
"generatedAt": { "type": "string", "format": "date-time" },
10+
"schemaVersion": { "type": "integer", "const": 1 },
11+
"categories": {
12+
"type": "array",
13+
"minItems": 1,
14+
"uniqueItems": true,
15+
"items": { "type": "string" }
16+
},
17+
"components": {
18+
"type": "array",
19+
"items": {
20+
"type": "object",
21+
"additionalProperties": false,
22+
"required": [
23+
"title",
24+
"author",
25+
"socialUrl",
26+
"pipLink",
27+
"categories",
28+
"image",
29+
"gitHubUrl",
30+
"enabled",
31+
"appUrl"
32+
],
33+
"properties": {
34+
"title": { "type": "string", "minLength": 1 },
35+
"author": { "type": "string", "minLength": 1 },
36+
"pipLink": {
37+
"oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }]
38+
},
39+
"pypi": {
40+
"oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }]
41+
},
42+
"categories": {
43+
"type": "array",
44+
"minItems": 1,
45+
"uniqueItems": true,
46+
"items": { "type": "string" }
47+
},
48+
"image": { "type": ["string", "null"], "format": "uri" },
49+
"gitHubUrl": { "type": "string", "format": "uri" },
50+
"enabled": { "type": "boolean" },
51+
"appUrl": { "type": ["string", "null"], "format": "uri" },
52+
"socialUrl": { "type": ["string", "null"], "format": "uri" },
53+
"metrics": {
54+
"type": ["object", "null"],
55+
"additionalProperties": false,
56+
"properties": {
57+
"github": {
58+
"type": ["object", "null"],
59+
"additionalProperties": false,
60+
"properties": {
61+
"stars": { "type": ["integer", "null"], "minimum": 0 },
62+
"forks": { "type": ["integer", "null"], "minimum": 0 },
63+
"contributorsCount": {
64+
"type": ["integer", "null"],
65+
"minimum": 0
66+
},
67+
"openIssues": { "type": ["integer", "null"], "minimum": 0 },
68+
"lastPushAt": {
69+
"type": ["string", "null"],
70+
"format": "date-time"
71+
},
72+
"fetchedAt": {
73+
"type": ["string", "null"],
74+
"format": "date-time"
75+
},
76+
"isStale": { "type": ["boolean", "null"] }
77+
}
78+
},
79+
"pypi": {
80+
"type": ["object", "null"],
81+
"additionalProperties": false,
82+
"properties": {
83+
"latestVersion": {
84+
"oneOf": [
85+
{ "type": "string", "minLength": 1 },
86+
{ "type": "null" }
87+
]
88+
},
89+
"latestReleaseAt": {
90+
"type": ["string", "null"],
91+
"format": "date-time"
92+
},
93+
"fetchedAt": {
94+
"type": ["string", "null"],
95+
"format": "date-time"
96+
},
97+
"isStale": { "type": ["boolean", "null"] }
98+
}
99+
},
100+
"pypistats": {
101+
"type": ["object", "null"],
102+
"additionalProperties": false,
103+
"properties": {
104+
"lastDay": { "type": ["integer", "null"], "minimum": 0 },
105+
"lastWeek": { "type": ["integer", "null"], "minimum": 0 },
106+
"lastMonth": { "type": ["integer", "null"], "minimum": 0 },
107+
"fetchedAt": {
108+
"type": ["string", "null"],
109+
"format": "date-time"
110+
},
111+
"isStale": { "type": ["boolean", "null"] }
112+
}
113+
}
114+
}
115+
},
116+
"ranking": {
117+
"type": ["object", "null"],
118+
"additionalProperties": false,
119+
"required": ["score", "signals", "computedAt"],
120+
"properties": {
121+
"score": { "type": "number" },
122+
"computedAt": { "type": "string", "format": "date-time" },
123+
"signals": {
124+
"type": "object",
125+
"additionalProperties": false,
126+
"properties": {
127+
"starsScore": { "type": ["number", "null"] },
128+
"recencyScore": { "type": ["number", "null"] },
129+
"daysSinceUpdate": {
130+
"type": ["number", "null"],
131+
"minimum": 0
132+
},
133+
"contributorsScore": { "type": ["number", "null"] },
134+
"daysSinceGithubPush": {
135+
"type": ["number", "null"],
136+
"minimum": 0
137+
},
138+
"daysSincePypiRelease": {
139+
"type": ["number", "null"],
140+
"minimum": 0
141+
},
142+
"downloadsScore": { "type": ["number", "null"] }
143+
}
144+
}
145+
}
146+
}
147+
}
148+
}
149+
}
150+
}
151+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://raw.githubusercontent.com/streamlit/gallery/main/components/registry/schemas/component.schema.json",
4+
"title": "Component Gallery submission (source-of-truth)",
5+
"type": "object",
6+
"additionalProperties": false,
7+
"required": [
8+
"schemaVersion",
9+
"title",
10+
"author",
11+
"links",
12+
"governance",
13+
"categories"
14+
],
15+
"properties": {
16+
"schemaVersion": {
17+
"type": "integer",
18+
"const": 1
19+
},
20+
"title": {
21+
"type": "string",
22+
"minLength": 1,
23+
"maxLength": 80
24+
},
25+
"author": {
26+
"type": "object",
27+
"additionalProperties": false,
28+
"required": ["github"],
29+
"properties": {
30+
"github": {
31+
"type": "string",
32+
"minLength": 1,
33+
"maxLength": 39,
34+
"pattern": "^[A-Za-z0-9_]+(?:-[A-Za-z0-9_]+)*$",
35+
"description": "GitHub username (no @)."
36+
},
37+
"displayName": {
38+
"type": "string",
39+
"minLength": 1,
40+
"maxLength": 80
41+
}
42+
}
43+
},
44+
"links": {
45+
"type": "object",
46+
"additionalProperties": false,
47+
"required": ["github"],
48+
"properties": {
49+
"github": {
50+
"type": "string",
51+
"format": "uri",
52+
"pattern": "^https://github\\.com/[^/]+/[^/]+/?$"
53+
},
54+
"pypi": {
55+
"type": ["string", "null"],
56+
"pattern": "^[A-Za-z0-9_.-]+$",
57+
"description": "PyPI project name (not a URL)."
58+
},
59+
"demo": {
60+
"type": ["string", "null"],
61+
"format": "uri"
62+
},
63+
"docs": {
64+
"type": ["string", "null"],
65+
"format": "uri"
66+
}
67+
}
68+
},
69+
"media": {
70+
"type": "object",
71+
"additionalProperties": false,
72+
"properties": {
73+
"image": {
74+
"type": ["string", "null"],
75+
"format": "uri"
76+
}
77+
}
78+
},
79+
"install": {
80+
"type": "object",
81+
"additionalProperties": false,
82+
"properties": {
83+
"pip": {
84+
"type": ["string", "null"],
85+
"minLength": 1,
86+
"maxLength": 200
87+
}
88+
}
89+
},
90+
"governance": {
91+
"type": "object",
92+
"additionalProperties": false,
93+
"required": ["enabled"],
94+
"properties": {
95+
"enabled": {
96+
"type": "boolean"
97+
},
98+
"notes": {
99+
"type": ["string", "null"],
100+
"maxLength": 500
101+
}
102+
}
103+
},
104+
"categories": {
105+
"type": "array",
106+
"minItems": 1,
107+
"uniqueItems": true,
108+
"items": {
109+
"type": "string",
110+
"enum": [
111+
"LLMs",
112+
"Widgets",
113+
"Charts",
114+
"Authentication",
115+
"Connections",
116+
"Images & video",
117+
"Audio",
118+
"Text",
119+
"Maps",
120+
"Dataframes",
121+
"Graphs",
122+
"Molecules & genes",
123+
"Code editors",
124+
"Page navigation",
125+
"Developer tools",
126+
"Integrations"
127+
]
128+
}
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)