ofd-validator 0.3.0__tar.gz → 0.5.0__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 (25) hide show
  1. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/Cargo.lock +3 -3
  2. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/PKG-INFO +13 -5
  3. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/README.md +12 -4
  4. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/Cargo.toml +1 -1
  5. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/logo_validator.rs +8 -1
  6. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-python/Cargo.toml +1 -1
  7. ofd_validator-0.5.0/crates/ofd-validator-python/src/orchestrator.rs +171 -0
  8. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/pyproject.toml +1 -1
  9. ofd_validator-0.3.0/crates/ofd-validator-python/src/orchestrator.rs +0 -139
  10. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/Cargo.toml +0 -0
  11. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/lib.rs +0 -0
  12. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/orchestrator.rs +0 -0
  13. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/schema_cache.rs +0 -0
  14. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/types.rs +0 -0
  15. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/util.rs +0 -0
  16. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/folder_name.rs +0 -0
  17. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/gtin.rs +0 -0
  18. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/json_validator.rs +0 -0
  19. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/missing_files.rs +0 -0
  20. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/mod.rs +0 -0
  21. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-core/src/validators/store_id.rs +0 -0
  22. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-python/src/lib.rs +0 -0
  23. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-python/src/types.rs +0 -0
  24. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/crates/ofd-validator-python/src/util.rs +0 -0
  25. {ofd_validator-0.3.0 → ofd_validator-0.5.0}/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.3.0"
808
+ version = "0.5.0"
809
809
  dependencies = [
810
810
  "image",
811
811
  "jsonschema",
@@ -818,7 +818,7 @@ dependencies = [
818
818
 
819
819
  [[package]]
820
820
  name = "ofd-validator-js"
821
- version = "0.3.0"
821
+ version = "0.5.0"
822
822
  dependencies = [
823
823
  "napi",
824
824
  "napi-build",
@@ -831,7 +831,7 @@ dependencies = [
831
831
 
832
832
  [[package]]
833
833
  name = "ofd-validator-python"
834
- version = "0.3.0"
834
+ version = "0.5.0"
835
835
  dependencies = [
836
836
  "ofd-validator-core",
837
837
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ofd-validator
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -51,8 +51,16 @@ 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:
61
+
54
62
  ```bash
55
- npm install ofd-validator
63
+ npm install @openfilamentcollective/ofd-validator
56
64
  ```
57
65
 
58
66
  Prebuilt binaries included for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64).
@@ -132,7 +140,7 @@ for error in result.errors:
132
140
  ### Path mode (filesystem-based)
133
141
 
134
142
  ```javascript
135
- const { validateAll, validateJsonFiles } = require('ofd-validator');
143
+ const { validateAll, validateJsonFiles } = require('@openfilamentcollective/ofd-validator');
136
144
 
137
145
  const result = validateAll('./data', './stores', './schemas');
138
146
  console.log(result.isValid); // boolean
@@ -148,7 +156,7 @@ for (const err of result.errors) {
148
156
  Pass file contents directly as strings or Buffers. Useful for CI pipelines, API-fetched data, or server-side validation.
149
157
 
150
158
  ```javascript
151
- const { validateJsonContent, validateAllContent } = require('ofd-validator');
159
+ const { validateJsonContent, validateAllContent } = require('@openfilamentcollective/ofd-validator');
152
160
  const fs = require('fs');
153
161
 
154
162
  // Single JSON validation
@@ -244,7 +252,7 @@ MIT
244
252
  ## Links
245
253
 
246
254
  - [PyPI](https://pypi.org/project/ofd-validator/)
247
- - [npm](https://www.npmjs.com/package/ofd-validator)
255
+ - [npm (GitHub Packages)](https://github.com/OpenFilamentCollective/ofd-validator/packages)
248
256
  - [Repository](https://github.com/OpenFilamentCollective/ofd-validator)
249
257
  - [Open Filament Database](https://github.com/OpenFilamentCollective/open-filament-database)
250
258
 
@@ -24,8 +24,16 @@ 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:
34
+
27
35
  ```bash
28
- npm install ofd-validator
36
+ npm install @openfilamentcollective/ofd-validator
29
37
  ```
30
38
 
31
39
  Prebuilt binaries included for Linux (x64, arm64), macOS (x64, arm64), and Windows (x64).
@@ -105,7 +113,7 @@ for error in result.errors:
105
113
  ### Path mode (filesystem-based)
106
114
 
107
115
  ```javascript
108
- const { validateAll, validateJsonFiles } = require('ofd-validator');
116
+ const { validateAll, validateJsonFiles } = require('@openfilamentcollective/ofd-validator');
109
117
 
110
118
  const result = validateAll('./data', './stores', './schemas');
111
119
  console.log(result.isValid); // boolean
@@ -121,7 +129,7 @@ for (const err of result.errors) {
121
129
  Pass file contents directly as strings or Buffers. Useful for CI pipelines, API-fetched data, or server-side validation.
122
130
 
123
131
  ```javascript
124
- const { validateJsonContent, validateAllContent } = require('ofd-validator');
132
+ const { validateJsonContent, validateAllContent } = require('@openfilamentcollective/ofd-validator');
125
133
  const fs = require('fs');
126
134
 
127
135
  // Single JSON validation
@@ -217,6 +225,6 @@ MIT
217
225
  ## Links
218
226
 
219
227
  - [PyPI](https://pypi.org/project/ofd-validator/)
220
- - [npm](https://www.npmjs.com/package/ofd-validator)
228
+ - [npm (GitHub Packages)](https://github.com/OpenFilamentCollective/ofd-validator/packages)
221
229
  - [Repository](https://github.com/OpenFilamentCollective/ofd-validator)
222
230
  - [Open Filament Database](https://github.com/OpenFilamentCollective/open-filament-database)
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ofd-validator-core"
3
- version = "0.3.0"
3
+ version = "0.5.0"
4
4
  edition = "2021"
5
5
  authors = ["Open Filament Collective"]
6
6
  license = "MIT"
@@ -69,7 +69,14 @@ pub fn validate_logo(
69
69
  } else {
70
70
  after_decl
71
71
  };
72
- if !after_doctype.to_lowercase().starts_with("<svg") {
72
+ // Skip XML comments (<!-- ... -->)
73
+ let mut after_comments = after_doctype;
74
+ while after_comments.starts_with("<!--") {
75
+ after_comments = after_comments.find("-->")
76
+ .map(|i| after_comments[i + 3..].trim_start())
77
+ .unwrap_or(after_comments);
78
+ }
79
+ if !after_comments.to_lowercase().starts_with("<svg") {
73
80
  result.add(ValidationError::error(
74
81
  "Logo",
75
82
  "File has .svg extension but is not a valid SVG (root element is not <svg>)",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ofd-validator-python"
3
- version = "0.3.0"
3
+ version = "0.5.0"
4
4
  edition = "2021"
5
5
  authors = ["Open Filament Collective"]
6
6
  license = "MIT"
@@ -0,0 +1,171 @@
1
+ use std::path::PathBuf;
2
+
3
+ use pyo3::prelude::*;
4
+ use rayon::ThreadPoolBuilder;
5
+
6
+ use ofd_validator_core as core;
7
+
8
+ use crate::types::ValidationResult;
9
+ use crate::util::log_step;
10
+
11
+ /// Run the closure on a custom Rayon thread pool when `max_workers` is set,
12
+ /// otherwise use the global pool (default Rayon behaviour).
13
+ fn with_thread_pool<F, R>(max_workers: Option<usize>, f: F) -> R
14
+ where
15
+ F: FnOnce() -> R + Send,
16
+ R: Send,
17
+ {
18
+ match max_workers {
19
+ Some(n) if n > 0 => {
20
+ let pool = ThreadPoolBuilder::new()
21
+ .num_threads(n)
22
+ .build()
23
+ .expect("failed to build Rayon thread pool");
24
+ pool.install(f)
25
+ }
26
+ _ => f(),
27
+ }
28
+ }
29
+
30
+ #[pyfunction]
31
+ #[pyo3(signature = (data_dir, stores_dir, schemas_dir=None, max_workers=None))]
32
+ pub fn validate_all(
33
+ py: Python<'_>,
34
+ data_dir: &str,
35
+ stores_dir: &str,
36
+ schemas_dir: Option<&str>,
37
+ max_workers: Option<usize>,
38
+ ) -> ValidationResult {
39
+ let data_dir = PathBuf::from(data_dir);
40
+ let stores_dir = PathBuf::from(stores_dir);
41
+ let schemas_dir = PathBuf::from(schemas_dir.unwrap_or("schemas"));
42
+
43
+ py.allow_threads(|| {
44
+ with_thread_pool(max_workers, || {
45
+ log_step("Loading dataset", None);
46
+ let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
47
+
48
+ log_step("Checking required files", None);
49
+ log_step("Validating JSON schemas", Some(dataset.json_entries.len()));
50
+ log_step("Validating logos", Some(dataset.logo_entries.len()));
51
+ log_step("Validating folder names", Some(dataset.folder_entries.len()));
52
+ log_step("Validating store IDs", None);
53
+ log_step("Validating GTIN/EAN codes", None);
54
+
55
+ core::validate_dataset(&dataset).into()
56
+ })
57
+ })
58
+ }
59
+
60
+ #[pyfunction]
61
+ #[pyo3(signature = (data_dir, stores_dir, schemas_dir=None, max_workers=None))]
62
+ pub fn validate_json_files(
63
+ py: Python<'_>,
64
+ data_dir: &str,
65
+ stores_dir: &str,
66
+ schemas_dir: Option<&str>,
67
+ max_workers: Option<usize>,
68
+ ) -> ValidationResult {
69
+ let data_dir = PathBuf::from(data_dir);
70
+ let stores_dir = PathBuf::from(stores_dir);
71
+ let schemas_dir = PathBuf::from(schemas_dir.unwrap_or("schemas"));
72
+
73
+ py.allow_threads(|| {
74
+ with_thread_pool(max_workers, || {
75
+ let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
76
+ log_step("Validating JSON schemas", Some(dataset.json_entries.len()));
77
+
78
+ use rayon::prelude::*;
79
+ let results: Vec<core::ValidationResult> = dataset.json_entries
80
+ .par_iter()
81
+ .map(|(path, schema_name, data)| {
82
+ core::validators::validate_json(data, schema_name, &dataset.schema_cache, Some(path))
83
+ })
84
+ .collect();
85
+
86
+ let mut result = core::ValidationResult::default();
87
+ for r in results {
88
+ result.merge_from(&r);
89
+ }
90
+ result.into()
91
+ })
92
+ })
93
+ }
94
+
95
+ #[pyfunction]
96
+ #[pyo3(signature = (data_dir, stores_dir, max_workers=None))]
97
+ pub fn validate_logo_files(
98
+ py: Python<'_>,
99
+ data_dir: &str,
100
+ stores_dir: &str,
101
+ max_workers: Option<usize>,
102
+ ) -> ValidationResult {
103
+ let data_dir = PathBuf::from(data_dir);
104
+ let stores_dir = PathBuf::from(stores_dir);
105
+ let schemas_dir = PathBuf::from("schemas");
106
+
107
+ py.allow_threads(|| {
108
+ with_thread_pool(max_workers, || {
109
+ let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
110
+ log_step("Validating logos", Some(dataset.logo_entries.len()));
111
+
112
+ use rayon::prelude::*;
113
+ let results: Vec<core::ValidationResult> = dataset.logo_entries
114
+ .par_iter()
115
+ .map(|(path, filename, bytes, logo_name)| {
116
+ if bytes.is_empty() {
117
+ let mut r = core::ValidationResult::default();
118
+ r.add(core::ValidationError::error(
119
+ "Logo",
120
+ "Logo file not found",
121
+ Some(path.clone()),
122
+ ));
123
+ r
124
+ } else {
125
+ core::validators::validate_logo(bytes, filename, logo_name.as_deref(), Some(path))
126
+ }
127
+ })
128
+ .collect();
129
+
130
+ let mut result = core::ValidationResult::default();
131
+ for r in results {
132
+ result.merge_from(&r);
133
+ }
134
+ result.into()
135
+ })
136
+ })
137
+ }
138
+
139
+ #[pyfunction]
140
+ #[pyo3(signature = (data_dir, stores_dir, max_workers=None))]
141
+ pub fn validate_folder_names(
142
+ py: Python<'_>,
143
+ data_dir: &str,
144
+ stores_dir: &str,
145
+ max_workers: Option<usize>,
146
+ ) -> ValidationResult {
147
+ let data_dir = PathBuf::from(data_dir);
148
+ let stores_dir = PathBuf::from(stores_dir);
149
+ let schemas_dir = PathBuf::from("schemas");
150
+
151
+ py.allow_threads(|| {
152
+ with_thread_pool(max_workers, || {
153
+ let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
154
+ log_step("Validating folder names", Some(dataset.folder_entries.len()));
155
+
156
+ use rayon::prelude::*;
157
+ let results: Vec<core::ValidationResult> = dataset.folder_entries
158
+ .par_iter()
159
+ .map(|(path, folder_name, json_data, json_key)| {
160
+ core::validators::validate_folder_name(folder_name, json_data, json_key, Some(path))
161
+ })
162
+ .collect();
163
+
164
+ let mut result = core::ValidationResult::default();
165
+ for r in results {
166
+ result.merge_from(&r);
167
+ }
168
+ result.into()
169
+ })
170
+ })
171
+ }
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "ofd-validator"
7
- version = "0.3.0"
7
+ version = "0.5.0"
8
8
  description = "High-performance validation library for the Open Filament Database"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,139 +0,0 @@
1
- use std::path::PathBuf;
2
-
3
- use pyo3::prelude::*;
4
-
5
- use ofd_validator_core as core;
6
-
7
- use crate::types::ValidationResult;
8
- use crate::util::log_step;
9
-
10
- #[pyfunction]
11
- #[pyo3(signature = (data_dir, stores_dir, schemas_dir=None))]
12
- pub fn validate_all(
13
- py: Python<'_>,
14
- data_dir: &str,
15
- stores_dir: &str,
16
- schemas_dir: Option<&str>,
17
- ) -> ValidationResult {
18
- let data_dir = PathBuf::from(data_dir);
19
- let stores_dir = PathBuf::from(stores_dir);
20
- let schemas_dir = PathBuf::from(schemas_dir.unwrap_or("schemas"));
21
-
22
- py.allow_threads(|| {
23
- log_step("Loading dataset", None);
24
- let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
25
-
26
- log_step("Checking required files", None);
27
- log_step("Validating JSON schemas", Some(dataset.json_entries.len()));
28
- log_step("Validating logos", Some(dataset.logo_entries.len()));
29
- log_step("Validating folder names", Some(dataset.folder_entries.len()));
30
- log_step("Validating store IDs", None);
31
- log_step("Validating GTIN/EAN codes", None);
32
-
33
- core::validate_dataset(&dataset).into()
34
- })
35
- }
36
-
37
- #[pyfunction]
38
- #[pyo3(signature = (data_dir, stores_dir, schemas_dir=None))]
39
- pub fn validate_json_files(
40
- py: Python<'_>,
41
- data_dir: &str,
42
- stores_dir: &str,
43
- schemas_dir: Option<&str>,
44
- ) -> ValidationResult {
45
- let data_dir = PathBuf::from(data_dir);
46
- let stores_dir = PathBuf::from(stores_dir);
47
- let schemas_dir = PathBuf::from(schemas_dir.unwrap_or("schemas"));
48
-
49
- py.allow_threads(|| {
50
- let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
51
- log_step("Validating JSON schemas", Some(dataset.json_entries.len()));
52
-
53
- use rayon::prelude::*;
54
- let results: Vec<core::ValidationResult> = dataset.json_entries
55
- .par_iter()
56
- .map(|(path, schema_name, data)| {
57
- core::validators::validate_json(data, schema_name, &dataset.schema_cache, Some(path))
58
- })
59
- .collect();
60
-
61
- let mut result = core::ValidationResult::default();
62
- for r in results {
63
- result.merge_from(&r);
64
- }
65
- result.into()
66
- })
67
- }
68
-
69
- #[pyfunction]
70
- #[pyo3(signature = (data_dir, stores_dir))]
71
- pub fn validate_logo_files(
72
- py: Python<'_>,
73
- data_dir: &str,
74
- stores_dir: &str,
75
- ) -> ValidationResult {
76
- let data_dir = PathBuf::from(data_dir);
77
- let stores_dir = PathBuf::from(stores_dir);
78
- let schemas_dir = PathBuf::from("schemas");
79
-
80
- py.allow_threads(|| {
81
- let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
82
- log_step("Validating logos", Some(dataset.logo_entries.len()));
83
-
84
- use rayon::prelude::*;
85
- let results: Vec<core::ValidationResult> = dataset.logo_entries
86
- .par_iter()
87
- .map(|(path, filename, bytes, logo_name)| {
88
- if bytes.is_empty() {
89
- let mut r = core::ValidationResult::default();
90
- r.add(core::ValidationError::error(
91
- "Logo",
92
- "Logo file not found",
93
- Some(path.clone()),
94
- ));
95
- r
96
- } else {
97
- core::validators::validate_logo(bytes, filename, logo_name.as_deref(), Some(path))
98
- }
99
- })
100
- .collect();
101
-
102
- let mut result = core::ValidationResult::default();
103
- for r in results {
104
- result.merge_from(&r);
105
- }
106
- result.into()
107
- })
108
- }
109
-
110
- #[pyfunction]
111
- #[pyo3(signature = (data_dir, stores_dir))]
112
- pub fn validate_folder_names(
113
- py: Python<'_>,
114
- data_dir: &str,
115
- stores_dir: &str,
116
- ) -> ValidationResult {
117
- let data_dir = PathBuf::from(data_dir);
118
- let stores_dir = PathBuf::from(stores_dir);
119
- let schemas_dir = PathBuf::from("schemas");
120
-
121
- py.allow_threads(|| {
122
- let dataset = core::DataSet::from_directories(&data_dir, &stores_dir, &schemas_dir);
123
- log_step("Validating folder names", Some(dataset.folder_entries.len()));
124
-
125
- use rayon::prelude::*;
126
- let results: Vec<core::ValidationResult> = dataset.folder_entries
127
- .par_iter()
128
- .map(|(path, folder_name, json_data, json_key)| {
129
- core::validators::validate_folder_name(folder_name, json_data, json_key, Some(path))
130
- })
131
- .collect();
132
-
133
- let mut result = core::ValidationResult::default();
134
- for r in results {
135
- result.merge_from(&r);
136
- }
137
- result.into()
138
- })
139
- }
File without changes