ofd-validator 0.5.2__tar.gz → 0.5.4__tar.gz

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 (29) hide show
  1. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/Cargo.lock +3 -3
  2. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/PKG-INFO +4 -9
  3. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/README.md +3 -8
  4. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/Cargo.toml +1 -1
  5. ofd_validator-0.5.4/crates/ofd-validator-core/src/schema_cache.rs +288 -0
  6. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-python/Cargo.toml +1 -1
  7. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/pyproject.toml +1 -1
  8. ofd_validator-0.5.2/crates/ofd-validator-core/src/schema_cache.rs +0 -107
  9. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/Cargo.toml +0 -0
  10. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/lib.rs +0 -0
  11. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/orchestrator.rs +0 -0
  12. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/types.rs +0 -0
  13. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/util.rs +0 -0
  14. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/duplicate_link.rs +0 -0
  15. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/folder_name.rs +0 -0
  16. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/gtin.rs +0 -0
  17. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/json_validator.rs +0 -0
  18. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/logo_validator.rs +0 -0
  19. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/missing_files.rs +0 -0
  20. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/mod.rs +0 -0
  21. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/store_host.rs +0 -0
  22. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/store_id.rs +0 -0
  23. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/url_tracker.rs +0 -0
  24. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-core/src/validators/variant_material.rs +0 -0
  25. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-python/src/lib.rs +0 -0
  26. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-python/src/orchestrator.rs +0 -0
  27. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-python/src/types.rs +0 -0
  28. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-python/src/util.rs +0 -0
  29. {ofd_validator-0.5.2 → ofd_validator-0.5.4}/crates/ofd-validator-python/src/validators.rs +0 -0
@@ -805,7 +805,7 @@ dependencies = [
805
805
 
806
806
  [[package]]
807
807
  name = "ofd-validator-core"
808
- version = "0.5.2"
808
+ version = "0.5.4"
809
809
  dependencies = [
810
810
  "image",
811
811
  "jsonschema",
@@ -819,7 +819,7 @@ dependencies = [
819
819
 
820
820
  [[package]]
821
821
  name = "ofd-validator-js"
822
- version = "0.5.2"
822
+ version = "0.5.4"
823
823
  dependencies = [
824
824
  "napi",
825
825
  "napi-build",
@@ -832,7 +832,7 @@ dependencies = [
832
832
 
833
833
  [[package]]
834
834
  name = "ofd-validator-python"
835
- version = "0.5.2"
835
+ version = "0.5.4"
836
836
  dependencies = [
837
837
  "ofd-validator-core",
838
838
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ofd-validator
3
- Version: 0.5.2
3
+ Version: 0.5.4
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -51,19 +51,14 @@ Requires Python 3.10+. No additional Python dependencies needed (self-contained
51
51
 
52
52
  ### Node.js
53
53
 
54
- Published to [GitHub Packages](https://github.com/OpenFilamentCollective/ofd-validator/packages). Add a `.npmrc` in your project root:
55
-
56
- ```
57
- @openfilamentcollective:registry=https://npm.pkg.github.com
58
- ```
59
-
60
- Then install:
54
+ Published to [npm](https://www.npmjs.com/package/@openfilamentcollective/ofd-validator). Install it like any public package — the matching prebuilt binary is pulled in automatically, **no Rust toolchain required**:
61
55
 
62
56
  ```bash
63
57
  npm install @openfilamentcollective/ofd-validator
64
58
  ```
65
59
 
66
- Prebuilt binaries included for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64).
60
+ Prebuilt binaries included for Linux (x64, arm64 — glibc), macOS (x64, arm64), and Windows (x64).
61
+ (No prebuilt for musl/Alpine yet — those would need to build from source.)
67
62
 
68
63
  ## Python Usage
69
64
 
@@ -24,19 +24,14 @@ Requires Python 3.10+. No additional Python dependencies needed (self-contained
24
24
 
25
25
  ### Node.js
26
26
 
27
- Published to [GitHub Packages](https://github.com/OpenFilamentCollective/ofd-validator/packages). Add a `.npmrc` in your project root:
28
-
29
- ```
30
- @openfilamentcollective:registry=https://npm.pkg.github.com
31
- ```
32
-
33
- Then install:
27
+ Published to [npm](https://www.npmjs.com/package/@openfilamentcollective/ofd-validator). Install it like any public package — the matching prebuilt binary is pulled in automatically, **no Rust toolchain required**:
34
28
 
35
29
  ```bash
36
30
  npm install @openfilamentcollective/ofd-validator
37
31
  ```
38
32
 
39
- Prebuilt binaries included for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64).
33
+ Prebuilt binaries included for Linux (x64, arm64 — glibc), macOS (x64, arm64), and Windows (x64).
34
+ (No prebuilt for musl/Alpine yet — those would need to build from source.)
40
35
 
41
36
  ## Python Usage
42
37
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ofd-validator-core"
3
- version = "0.5.2"
3
+ version = "0.5.4"
4
4
  edition = "2021"
5
5
  authors = ["Open Filament Collective"]
6
6
  license = "MIT"
@@ -0,0 +1,288 @@
1
+ use serde_json::Value;
2
+ use std::collections::HashMap;
3
+ use std::sync::Arc;
4
+
5
+ /// Maps schema names (e.g. "brand", "material") to their filenames.
6
+ pub const SCHEMA_FILES: &[(&str, &str)] = &[
7
+ ("store", "store_schema.json"),
8
+ ("brand", "brand_schema.json"),
9
+ ("material", "material_schema.json"),
10
+ ("material_types", "material_types_schema.json"),
11
+ ("filament", "filament_schema.json"),
12
+ ("variant", "variant_schema.json"),
13
+ ("sizes", "sizes_schema.json"),
14
+ ];
15
+
16
+ /// Schema name for a `*_schema.json` filename, e.g. "sizes_schema.json" -> "sizes".
17
+ fn name_from_filename(filename: &str) -> Option<&str> {
18
+ filename.strip_suffix("_schema.json").filter(|n| is_schema_name(n))
19
+ }
20
+
21
+ /// Schema names are plain identifiers (e.g. "material_types"), never paths or URIs.
22
+ fn is_schema_name(name: &str) -> bool {
23
+ !name.is_empty() && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
24
+ }
25
+
26
+ /// Filename for a schema name, e.g. "sizes" -> "sizes_schema.json".
27
+ fn filename_for(name: &str) -> String {
28
+ SCHEMA_FILES
29
+ .iter()
30
+ .find(|(n, _)| *n == name)
31
+ .map(|(_, f)| f.to_string())
32
+ .unwrap_or_else(|| format!("{}_schema.json", name))
33
+ }
34
+
35
+ /// Register a schema under every key a `$ref` might use to reach it.
36
+ /// A `$id` never replaces an already-registered key, so callers must register
37
+ /// known schemas before extra ones.
38
+ fn register_uris(
39
+ schemas_by_uri: &mut HashMap<String, Arc<Value>>,
40
+ filename: &str,
41
+ schema: &Arc<Value>,
42
+ ) {
43
+ schemas_by_uri.insert(format!("./{}", filename), Arc::clone(schema));
44
+ schemas_by_uri.insert(filename.to_string(), Arc::clone(schema));
45
+ if let Some(id) = schema.get("$id").and_then(|v| v.as_str()) {
46
+ schemas_by_uri
47
+ .entry(id.to_string())
48
+ .or_insert_with(|| Arc::clone(schema));
49
+ }
50
+ }
51
+
52
+ #[derive(Clone)]
53
+ pub struct SchemaCache {
54
+ /// Schemas indexed by name (e.g. "brand", "material")
55
+ schemas_by_name: HashMap<String, Arc<Value>>,
56
+ /// All schemas indexed by various URI keys for $ref resolution
57
+ schemas_by_uri: HashMap<String, Arc<Value>>,
58
+ }
59
+
60
+ impl SchemaCache {
61
+ /// Create a schema cache from a directory on the filesystem.
62
+ #[cfg(feature = "filesystem")]
63
+ pub fn from_directory(schemas_dir: &std::path::Path) -> Self {
64
+ let mut schemas_by_name = HashMap::new();
65
+ let mut schemas_by_uri = HashMap::new();
66
+
67
+ // Known schemas first, then any other `*_schema.json` in the directory so that a
68
+ // new cross-file `$ref` (e.g. "./sustainability_schema.json") resolves without a release.
69
+ let mut files: Vec<(String, String)> = SCHEMA_FILES
70
+ .iter()
71
+ .map(|(n, f)| (n.to_string(), f.to_string()))
72
+ .collect();
73
+ match std::fs::read_dir(schemas_dir) {
74
+ Ok(entries) => {
75
+ let mut extra: Vec<(String, String)> = entries
76
+ .filter_map(|e| e.ok())
77
+ .filter_map(|e| e.file_name().into_string().ok())
78
+ .filter(|f| !files.iter().any(|(_, known)| known == f))
79
+ .filter_map(|f| name_from_filename(&f).map(|n| (n.to_string(), f.clone())))
80
+ .collect();
81
+ extra.sort();
82
+ files.extend(extra);
83
+ }
84
+ Err(e) => eprintln!(
85
+ "Warning: failed to read schema directory {}: {}",
86
+ schemas_dir.display(),
87
+ e
88
+ ),
89
+ }
90
+
91
+ for (name, filename) in &files {
92
+ let path = schemas_dir.join(filename);
93
+ let content = match std::fs::read_to_string(&path) {
94
+ Ok(c) => c,
95
+ // A missing known schema is reported when something validates against it.
96
+ Err(e) if e.kind() == std::io::ErrorKind::NotFound => continue,
97
+ Err(e) => {
98
+ eprintln!("Warning: failed to read schema {}: {}", path.display(), e);
99
+ continue;
100
+ }
101
+ };
102
+ match serde_json::from_str::<Value>(&content) {
103
+ Ok(schema) => {
104
+ let schema = Arc::new(schema);
105
+
106
+ schemas_by_name.insert(name.clone(), Arc::clone(&schema));
107
+
108
+ let relpath = format!("{}/{}", schemas_dir.display(), filename);
109
+ schemas_by_uri.insert(relpath, Arc::clone(&schema));
110
+ register_uris(&mut schemas_by_uri, filename, &schema);
111
+ }
112
+ Err(e) => eprintln!("Warning: invalid JSON in schema {}: {}", path.display(), e),
113
+ }
114
+ }
115
+
116
+ Self {
117
+ schemas_by_name,
118
+ schemas_by_uri,
119
+ }
120
+ }
121
+
122
+ /// Create a schema cache from pre-loaded schema values.
123
+ /// Keys in the map should be schema names (e.g. "brand", "material"); a name outside
124
+ /// `SCHEMA_FILES` is registered as `<name>_schema.json` for `$ref` resolution.
125
+ /// Keys that are not plain names (paths, URIs) are ignored.
126
+ pub fn from_map(schemas: HashMap<String, Value>) -> Self {
127
+ let mut schemas_by_name = HashMap::new();
128
+ let mut schemas_by_uri = HashMap::new();
129
+
130
+ // Known schemas first, then the rest in a stable order, so `$id`s resolve deterministically.
131
+ let mut names: Vec<&String> = schemas.keys().filter(|n| is_schema_name(n)).collect();
132
+ names.sort_by_key(|n| {
133
+ let known = SCHEMA_FILES.iter().position(|(k, _)| k == n);
134
+ (known.unwrap_or(usize::MAX), n.as_str())
135
+ });
136
+
137
+ for name in names {
138
+ let filename = filename_for(name);
139
+ let schema = Arc::new(schemas[name].clone());
140
+
141
+ schemas_by_name.insert(name.clone(), Arc::clone(&schema));
142
+ register_uris(&mut schemas_by_uri, &filename, &schema);
143
+ }
144
+
145
+ Self {
146
+ schemas_by_name,
147
+ schemas_by_uri,
148
+ }
149
+ }
150
+
151
+ pub fn get(&self, schema_name: &str) -> Option<&Value> {
152
+ self.schemas_by_name.get(schema_name).map(|v| v.as_ref())
153
+ }
154
+
155
+ pub fn resolve_ref(&self, uri: &str) -> Option<Value> {
156
+ if let Some(schema) = self.schemas_by_uri.get(uri) {
157
+ return Some((**schema).clone());
158
+ }
159
+
160
+ let stripped = uri.strip_prefix("./").unwrap_or(uri);
161
+ if let Some(schema) = self.schemas_by_uri.get(stripped) {
162
+ return Some((**schema).clone());
163
+ }
164
+
165
+ for (key, schema) in &self.schemas_by_uri {
166
+ if key.ends_with(stripped) {
167
+ return Some((**schema).clone());
168
+ }
169
+ }
170
+
171
+ None
172
+ }
173
+ }
174
+
175
+ #[cfg(test)]
176
+ mod tests {
177
+ use super::*;
178
+ use crate::validators::validate_json;
179
+ use serde_json::json;
180
+
181
+ fn schemas() -> HashMap<String, Value> {
182
+ let mut m = HashMap::new();
183
+ m.insert(
184
+ "filament".to_string(),
185
+ json!({
186
+ "type": "object",
187
+ "properties": {
188
+ "name": {"type": "string"},
189
+ "sustainability": {"$ref": "./sustainability_schema.json"}
190
+ },
191
+ "additionalProperties": false
192
+ }),
193
+ );
194
+ m.insert(
195
+ "sustainability".to_string(),
196
+ json!({
197
+ "$id": "./sustainability_schema.json",
198
+ "type": "object",
199
+ "properties": {"note": {"type": "string"}},
200
+ "additionalProperties": false
201
+ }),
202
+ );
203
+ m
204
+ }
205
+
206
+ #[test]
207
+ fn name_from_filename_strips_suffix() {
208
+ assert_eq!(name_from_filename("sizes_schema.json"), Some("sizes"));
209
+ assert_eq!(name_from_filename("_schema.json"), None);
210
+ assert_eq!(name_from_filename("trait_rules.json"), None);
211
+ }
212
+
213
+ #[test]
214
+ fn from_map_resolves_cross_file_ref() {
215
+ let cache = SchemaCache::from_map(schemas());
216
+ let ok = validate_json(&json!({"name": "x", "sustainability": {"note": "y"}}), "filament", &cache, None);
217
+ assert!(ok.errors.is_empty(), "{:?}", ok.errors);
218
+
219
+ let bad = validate_json(&json!({"name": "x", "sustainability": {"bogus": 1}}), "filament", &cache, None);
220
+ assert!(!bad.errors.is_empty());
221
+ }
222
+
223
+ #[test]
224
+ fn from_map_ignores_non_name_keys() {
225
+ let mut m = schemas();
226
+ m.insert("./sustainability_schema.json".to_string(), json!({"type": "string"}));
227
+ let cache = SchemaCache::from_map(m);
228
+ assert!(cache.get("./sustainability_schema.json").is_none());
229
+ let ok = validate_json(&json!({"sustainability": {"note": "y"}}), "filament", &cache, None);
230
+ assert!(ok.errors.is_empty(), "{:?}", ok.errors);
231
+ }
232
+
233
+ #[test]
234
+ fn extra_schema_id_does_not_shadow_known_schema() {
235
+ let mut m = schemas();
236
+ m.insert("material_types".to_string(), json!({"$id": "./material_types_schema.json", "type": "string"}));
237
+ // A stray copy claiming the same `$id` must not replace the real schema.
238
+ m.insert("aaa_copy".to_string(), json!({"$id": "./material_types_schema.json", "type": "number"}));
239
+ let cache = SchemaCache::from_map(m);
240
+ assert_eq!(
241
+ cache.resolve_ref("./material_types_schema.json"),
242
+ Some(json!({"$id": "./material_types_schema.json", "type": "string"}))
243
+ );
244
+ }
245
+
246
+ /// Temp directory removed on drop, so a failed assertion doesn't leave files behind.
247
+ #[cfg(feature = "filesystem")]
248
+ struct TempDir(std::path::PathBuf);
249
+
250
+ #[cfg(feature = "filesystem")]
251
+ impl TempDir {
252
+ fn new(label: &str) -> Self {
253
+ let dir = std::env::temp_dir().join(format!("ofd-schema-cache-{}-{}", label, std::process::id()));
254
+ std::fs::remove_dir_all(&dir).ok();
255
+ std::fs::create_dir_all(&dir).unwrap();
256
+ Self(dir)
257
+ }
258
+ }
259
+
260
+ #[cfg(feature = "filesystem")]
261
+ impl Drop for TempDir {
262
+ fn drop(&mut self) {
263
+ std::fs::remove_dir_all(&self.0).ok();
264
+ }
265
+ }
266
+
267
+ #[cfg(feature = "filesystem")]
268
+ #[test]
269
+ fn from_directory_loads_unlisted_schema_files() {
270
+ let dir = TempDir::new("unlisted");
271
+ // sustainability_schema.json is not in SCHEMA_FILES, so this exercises the directory scan.
272
+ for (name, schema) in schemas() {
273
+ std::fs::write(dir.0.join(format!("{}_schema.json", name)), schema.to_string()).unwrap();
274
+ }
275
+ std::fs::write(dir.0.join("extra_schema.json"), json!({"type": "string"}).to_string()).unwrap();
276
+ // A malformed extra schema is skipped (with a warning) rather than breaking the cache.
277
+ std::fs::write(dir.0.join("broken_schema.json"), "{").unwrap();
278
+
279
+ let cache = SchemaCache::from_directory(&dir.0);
280
+ assert!(cache.get("extra").is_some());
281
+ assert!(cache.get("sustainability").is_some());
282
+ assert!(cache.get("broken").is_none());
283
+ let bad = validate_json(&json!({"sustainability": {"bogus": 1}}), "filament", &cache, None);
284
+ assert!(!bad.errors.is_empty());
285
+ let ok = validate_json(&json!({"sustainability": {"note": "y"}}), "filament", &cache, None);
286
+ assert!(ok.errors.is_empty(), "{:?}", ok.errors);
287
+ }
288
+ }
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ofd-validator-python"
3
- version = "0.5.2"
3
+ version = "0.5.4"
4
4
  edition = "2021"
5
5
  authors = ["Open Filament Collective"]
6
6
  license = "MIT"
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "ofd-validator"
7
- version = "0.5.2"
7
+ version = "0.5.4"
8
8
  description = "High-performance validation library for the Open Filament Database"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,107 +0,0 @@
1
- use serde_json::Value;
2
- use std::collections::HashMap;
3
- use std::sync::Arc;
4
-
5
- /// Maps schema names (e.g. "brand", "material") to their filenames.
6
- pub const SCHEMA_FILES: &[(&str, &str)] = &[
7
- ("store", "store_schema.json"),
8
- ("brand", "brand_schema.json"),
9
- ("material", "material_schema.json"),
10
- ("material_types", "material_types_schema.json"),
11
- ("filament", "filament_schema.json"),
12
- ("variant", "variant_schema.json"),
13
- ("sizes", "sizes_schema.json"),
14
- ];
15
-
16
- #[derive(Clone)]
17
- pub struct SchemaCache {
18
- /// Schemas indexed by name (e.g. "brand", "material")
19
- schemas_by_name: HashMap<String, Arc<Value>>,
20
- /// All schemas indexed by various URI keys for $ref resolution
21
- schemas_by_uri: HashMap<String, Arc<Value>>,
22
- }
23
-
24
- impl SchemaCache {
25
- /// Create a schema cache from a directory on the filesystem.
26
- #[cfg(feature = "filesystem")]
27
- pub fn from_directory(schemas_dir: &std::path::Path) -> Self {
28
- use crate::util::load_json;
29
-
30
- let mut schemas_by_name = HashMap::new();
31
- let mut schemas_by_uri = HashMap::new();
32
-
33
- for (name, filename) in SCHEMA_FILES {
34
- let path = schemas_dir.join(filename);
35
- if let Some(schema) = load_json(&path) {
36
- let schema = Arc::new(schema);
37
-
38
- schemas_by_name.insert(name.to_string(), Arc::clone(&schema));
39
-
40
- let relpath = format!("{}/{}", schemas_dir.display(), filename);
41
- schemas_by_uri.insert(relpath, Arc::clone(&schema));
42
- schemas_by_uri.insert(format!("./{}", filename), Arc::clone(&schema));
43
- schemas_by_uri.insert(filename.to_string(), Arc::clone(&schema));
44
-
45
- if let Some(id) = schema.get("$id").and_then(|v| v.as_str()) {
46
- schemas_by_uri.insert(id.to_string(), Arc::clone(&schema));
47
- }
48
- }
49
- }
50
-
51
- Self {
52
- schemas_by_name,
53
- schemas_by_uri,
54
- }
55
- }
56
-
57
- /// Create a schema cache from pre-loaded schema values.
58
- /// Keys in the map should be schema names (e.g. "brand", "material").
59
- pub fn from_map(schemas: HashMap<String, Value>) -> Self {
60
- let mut schemas_by_name = HashMap::new();
61
- let mut schemas_by_uri = HashMap::new();
62
-
63
- for (name, filename) in SCHEMA_FILES {
64
- if let Some(schema_value) = schemas.get(*name) {
65
- let schema = Arc::new(schema_value.clone());
66
-
67
- schemas_by_name.insert(name.to_string(), Arc::clone(&schema));
68
-
69
- // Register by filename variants for $ref resolution
70
- schemas_by_uri.insert(format!("./{}", filename), Arc::clone(&schema));
71
- schemas_by_uri.insert(filename.to_string(), Arc::clone(&schema));
72
-
73
- if let Some(id) = schema.get("$id").and_then(|v| v.as_str()) {
74
- schemas_by_uri.insert(id.to_string(), Arc::clone(&schema));
75
- }
76
- }
77
- }
78
-
79
- Self {
80
- schemas_by_name,
81
- schemas_by_uri,
82
- }
83
- }
84
-
85
- pub fn get(&self, schema_name: &str) -> Option<&Value> {
86
- self.schemas_by_name.get(schema_name).map(|v| v.as_ref())
87
- }
88
-
89
- pub fn resolve_ref(&self, uri: &str) -> Option<Value> {
90
- if let Some(schema) = self.schemas_by_uri.get(uri) {
91
- return Some((**schema).clone());
92
- }
93
-
94
- let stripped = uri.strip_prefix("./").unwrap_or(uri);
95
- if let Some(schema) = self.schemas_by_uri.get(stripped) {
96
- return Some((**schema).clone());
97
- }
98
-
99
- for (key, schema) in &self.schemas_by_uri {
100
- if key.ends_with(stripped) {
101
- return Some((**schema).clone());
102
- }
103
- }
104
-
105
- None
106
- }
107
- }
File without changes