commonmeta-schema 1.0.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 (131) hide show
  1. commonmeta_schema-1.0.0/.gitignore +18 -0
  2. commonmeta_schema-1.0.0/LICENSE +21 -0
  3. commonmeta_schema-1.0.0/PKG-INFO +324 -0
  4. commonmeta_schema-1.0.0/README.md +297 -0
  5. commonmeta_schema-1.0.0/fixtures/bibtex/crossref.bib +14 -0
  6. commonmeta_schema-1.0.0/fixtures/bibtex/journal_article.bib +14 -0
  7. commonmeta_schema-1.0.0/fixtures/bibtex/pure.bib +14 -0
  8. commonmeta_schema-1.0.0/fixtures/bibtex_commonmeta/crossref.json +86 -0
  9. commonmeta_schema-1.0.0/fixtures/bibtex_commonmeta/journal_article.json +46 -0
  10. commonmeta_schema-1.0.0/fixtures/bibtex_out/journal_article.bib +17 -0
  11. commonmeta_schema-1.0.0/fixtures/cff/CITATION.cff +83 -0
  12. commonmeta_schema-1.0.0/fixtures/cff_commonmeta/CITATION.json +76 -0
  13. commonmeta_schema-1.0.0/fixtures/codemeta/codemeta.json +86 -0
  14. commonmeta_schema-1.0.0/fixtures/commonmeta/0000-0002-0068-716X.json +78 -0
  15. commonmeta_schema-1.0.0/fixtures/commonmeta/blog_post_1.json +44 -0
  16. commonmeta_schema-1.0.0/fixtures/commonmeta/citeproc.json +51 -0
  17. commonmeta_schema-1.0.0/fixtures/commonmeta/citeproc_no_author.json +39 -0
  18. commonmeta_schema-1.0.0/fixtures/commonmeta/codemeta.json +65 -0
  19. commonmeta_schema-1.0.0/fixtures/commonmeta/crossref_journal_article.json +68 -0
  20. commonmeta_schema-1.0.0/fixtures/commonmeta/csl_journal_article.json +59 -0
  21. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_blog_post.json +54 -0
  22. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_blog_post_citeproc.json +106 -0
  23. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_client_zenodo.json +21 -0
  24. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_dataset.json +184 -0
  25. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_date.json +92 -0
  26. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_dryad.json +87 -0
  27. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_multiple_identifiers.json +56 -0
  28. commonmeta_schema-1.0.0/fixtures/commonmeta/datacite_subject_scheme_for.json +87 -0
  29. commonmeta_schema-1.0.0/fixtures/commonmeta/dataset_geo.json +43 -0
  30. commonmeta_schema-1.0.0/fixtures/commonmeta/inveniordm_blog_post.json +54 -0
  31. commonmeta_schema-1.0.0/fixtures/commonmeta/inveniordm_blog_versioned.json +56 -0
  32. commonmeta_schema-1.0.0/fixtures/commonmeta/inveniordm_software.json +88 -0
  33. commonmeta_schema-1.0.0/fixtures/commonmeta/journal_article.json +58 -0
  34. commonmeta_schema-1.0.0/fixtures/commonmeta/journal_article_datacite_reader.json +45 -0
  35. commonmeta_schema-1.0.0/fixtures/commonmeta/openalex_source_blog_front_matter.json +24 -0
  36. commonmeta_schema-1.0.0/fixtures/commonmeta/openalex_source_journal.json +32 -0
  37. commonmeta_schema-1.0.0/fixtures/commonmeta/openalex_source_repository_zenodo.json +24 -0
  38. commonmeta_schema-1.0.0/fixtures/commonmeta/organization.json +47 -0
  39. commonmeta_schema-1.0.0/fixtures/commonmeta/person.json +28 -0
  40. commonmeta_schema-1.0.0/fixtures/commonmeta/ror_cambridge_university.json +210 -0
  41. commonmeta_schema-1.0.0/fixtures/commonmeta/ror_nsf.json +231 -0
  42. commonmeta_schema-1.0.0/fixtures/commonmeta/schemaorg_blog_posting.json +55 -0
  43. commonmeta_schema-1.0.0/fixtures/commonmeta/schemaorg_geolocation.json +127 -0
  44. commonmeta_schema-1.0.0/fixtures/commonmeta/schemaorg_gtex.json +69 -0
  45. commonmeta_schema-1.0.0/fixtures/commonmeta/schemaorg_journal_article.json +48 -0
  46. commonmeta_schema-1.0.0/fixtures/commonmeta_list/orcid_person_with_works.json +138 -0
  47. commonmeta_schema-1.0.0/fixtures/commonmeta_list/ror_org_with_works.json +291 -0
  48. commonmeta_schema-1.0.0/fixtures/crossref/crossref_journal_article.json +102 -0
  49. commonmeta_schema-1.0.0/fixtures/crossref_out/crossref_journal_article.json +77 -0
  50. commonmeta_schema-1.0.0/fixtures/crossref_xml/crossref_elife_01567.xml +606 -0
  51. commonmeta_schema-1.0.0/fixtures/crossref_xml/journal_article.xml +75 -0
  52. commonmeta_schema-1.0.0/fixtures/crossref_xml_commonmeta/crossref_elife_01567.json +299 -0
  53. commonmeta_schema-1.0.0/fixtures/csl/citeproc.json +28 -0
  54. commonmeta_schema-1.0.0/fixtures/csl/citeproc_no_author.json +22 -0
  55. commonmeta_schema-1.0.0/fixtures/csl/csl_journal_article.json +22 -0
  56. commonmeta_schema-1.0.0/fixtures/datacite/journal_article.json +77 -0
  57. commonmeta_schema-1.0.0/fixtures/datacite_client/datacite_client_zenodo.json +16 -0
  58. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_blog_post.json +116 -0
  59. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_blog_post_citeproc.json +1 -0
  60. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_dataset.json +848 -0
  61. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_date.json +318 -0
  62. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_dryad.json +249 -0
  63. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_multiple_identifiers.json +192 -0
  64. commonmeta_schema-1.0.0/fixtures/datacite_reader/datacite_subject_scheme_for.json +249 -0
  65. commonmeta_schema-1.0.0/fixtures/datacite_reader/journal_article_datacite_reader.json +63 -0
  66. commonmeta_schema-1.0.0/fixtures/datacite_xml/full_v4_4.xml +114 -0
  67. commonmeta_schema-1.0.0/fixtures/datacite_xml/geolocation.xml +66 -0
  68. commonmeta_schema-1.0.0/fixtures/datacite_xml/schema_4_0.xml +140 -0
  69. commonmeta_schema-1.0.0/fixtures/datacite_xml_commonmeta/full_v4_4.json +115 -0
  70. commonmeta_schema-1.0.0/fixtures/datacite_xml_commonmeta/geolocation.json +70 -0
  71. commonmeta_schema-1.0.0/fixtures/datacite_xml_commonmeta/schema_4_0.json +222 -0
  72. commonmeta_schema-1.0.0/fixtures/inveniordm/inveniordm_blog_post.json +63 -0
  73. commonmeta_schema-1.0.0/fixtures/inveniordm/inveniordm_blog_versioned.json +56 -0
  74. commonmeta_schema-1.0.0/fixtures/inveniordm/inveniordm_software.json +83 -0
  75. commonmeta_schema-1.0.0/fixtures/openalex_source/README.md +39 -0
  76. commonmeta_schema-1.0.0/fixtures/openalex_source/openalex_source_blog_front_matter.json +21 -0
  77. commonmeta_schema-1.0.0/fixtures/openalex_source/openalex_source_journal.json +25 -0
  78. commonmeta_schema-1.0.0/fixtures/openalex_source/openalex_source_repository_zenodo.json +21 -0
  79. commonmeta_schema-1.0.0/fixtures/orcid/0000-0002-0068-716X.json +4352 -0
  80. commonmeta_schema-1.0.0/fixtures/orcid_commonmeta/0000-0002-0068-716X.json +78 -0
  81. commonmeta_schema-1.0.0/fixtures/orcid_xml/0000-0002-0068-716X.xml +2231 -0
  82. commonmeta_schema-1.0.0/fixtures/orcid_xml/0000-0003-1419-2405.xml +971 -0
  83. commonmeta_schema-1.0.0/fixtures/orcid_xml_commonmeta/0000-0002-0068-716X.json +68 -0
  84. commonmeta_schema-1.0.0/fixtures/orcid_xml_commonmeta/0000-0003-1419-2405.json +66 -0
  85. commonmeta_schema-1.0.0/fixtures/ris/crossref.ris +15 -0
  86. commonmeta_schema-1.0.0/fixtures/ris/pure.ris +15 -0
  87. commonmeta_schema-1.0.0/fixtures/ris_commonmeta/crossref.json +67 -0
  88. commonmeta_schema-1.0.0/fixtures/ror/ror_cambridge_university.json +308 -0
  89. commonmeta_schema-1.0.0/fixtures/ror/ror_nsf.json +288 -0
  90. commonmeta_schema-1.0.0/fixtures/ror_commonmeta/ror_cambridge_university.json +210 -0
  91. commonmeta_schema-1.0.0/fixtures/ror_commonmeta/ror_nsf.json +231 -0
  92. commonmeta_schema-1.0.0/fixtures/schemaorg/schemaorg_blog_posting.json +49 -0
  93. commonmeta_schema-1.0.0/fixtures/schemaorg/schemaorg_geolocation.json +82 -0
  94. commonmeta_schema-1.0.0/fixtures/schemaorg/schemaorg_gtex.json +75 -0
  95. commonmeta_schema-1.0.0/fixtures/schemaorg/schemaorg_journal_article.json +29 -0
  96. commonmeta_schema-1.0.0/fixtures/schemaorg_out/journal_article.json +48 -0
  97. commonmeta_schema-1.0.0/fixtures/utils/README.md +26 -0
  98. commonmeta_schema-1.0.0/fixtures/utils/decode_doi_cases.json +38 -0
  99. commonmeta_schema-1.0.0/fixtures/utils/encode_doi_cases.json +18 -0
  100. commonmeta_schema-1.0.0/pyproject.toml +49 -0
  101. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0.json +1224 -0
  102. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc1.json +1133 -0
  103. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc10.json +1166 -0
  104. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc11.json +1166 -0
  105. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc12.json +1166 -0
  106. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc13.json +1166 -0
  107. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc14.json +1166 -0
  108. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc15.json +1265 -0
  109. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc16.json +1273 -0
  110. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc17.json +1284 -0
  111. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc18.json +1284 -0
  112. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc19.json +1227 -0
  113. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc2.json +1129 -0
  114. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc20.json +1227 -0
  115. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc21.json +1224 -0
  116. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc22.json +1224 -0
  117. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc23.json +1224 -0
  118. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc24.json +1224 -0
  119. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc25.json +1224 -0
  120. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc26.json +1224 -0
  121. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc27.json +1224 -0
  122. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc28.json +1224 -0
  123. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc3.json +1151 -0
  124. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc4.json +1151 -0
  125. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc5.json +1166 -0
  126. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc6.json +1166 -0
  127. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc7.json +1166 -0
  128. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc8.json +1166 -0
  129. commonmeta_schema-1.0.0/schemas/commonmeta_v1.0rc9.json +1166 -0
  130. commonmeta_schema-1.0.0/src/commonmeta_schema/__init__.py +15 -0
  131. commonmeta_schema-1.0.0/src/commonmeta_schema/resources.py +41 -0
@@ -0,0 +1,18 @@
1
+ # macOS
2
+ .DS_Store
3
+
4
+ # Editor
5
+ .vscode/
6
+ .idea/
7
+ *.swp
8
+
9
+ # Python build artifacts
10
+ dist/
11
+ build/
12
+ *.egg-info/
13
+
14
+ # Rust build artifacts
15
+ target/
16
+ rust/target/
17
+
18
+ notes.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Front Matter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,324 @@
1
+ Metadata-Version: 2.5
2
+ Name: commonmeta-schema
3
+ Version: 1.0.0
4
+ Summary: Commonmeta JSON Schemas and conformance fixtures
5
+ Project-URL: Homepage, https://github.com/front-matter/commonmeta-schema
6
+ Project-URL: Repository, https://github.com/front-matter/commonmeta-schema
7
+ Project-URL: Issues, https://github.com/front-matter/commonmeta-schema/issues
8
+ Author: Front Matter
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: commonmeta,fixtures,json-schema,metadata,schema
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Software Development :: Libraries
24
+ Classifier: Topic :: Text Processing
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+
28
+ # commonmeta-schema
29
+
30
+ Language-neutral JSON Schema definitions and conformance fixtures for
31
+ [Commonmeta](https://commonmeta.org), the scholarly metadata interchange format.
32
+
33
+ This repository is the shared source of truth consumed by the following Commonmeta
34
+ implementations:
35
+
36
+ - [commonmeta-rs](https://github.com/front-matter/commonmeta-rs) (Rust)
37
+ - [commonmeta-py](https://github.com/front-matter/commonmeta-py) (Python)
38
+
39
+ Keeping the schema and the golden fixtures in one place lets every
40
+ implementation validate against the same contract and run the same
41
+ cross-format conformance tests.
42
+
43
+ ## Layout
44
+
45
+ ```
46
+ schemas/
47
+ commonmeta_v1.0.json # the Commonmeta JSON Schema (current)
48
+ commonmeta_v1.0rc*.json # earlier release candidates, retained but not exported
49
+ fixtures/
50
+ commonmeta/ # canonical Commonmeta records (round-trip + expected output)
51
+ <format>/ # input fixtures in a given source format
52
+ <format>_out/ # expected writer output (Commonmeta -> format)
53
+ <format>_commonmeta/ # expected reader output for non-JSON inputs
54
+ utils/ # shared utility fixtures for helpers outside format conversion
55
+ ```
56
+
57
+ ## Schema versions
58
+
59
+ Schemas are versioned by filename. The current version is `commonmeta_v1.0.json`,
60
+ and the `schema_version` field of a Commonmeta record is the URL
61
+ `https://commonmeta.org/commonmeta_v1.0.json`.
62
+
63
+ Earlier release candidates (`commonmeta_v1.0rc1`…`rc31`) are kept in `schemas/`
64
+ for reference, but the packages export only `v1.0` — new versions are added
65
+ alongside existing files rather than replacing them, so implementations can pin
66
+ a version.
67
+
68
+ ## Fixture conventions
69
+
70
+ The conformance harness in each implementation follows these naming rules
71
+ (a missing pair is skipped, so partial coverage is fine):
72
+
73
+ | Test kind | Input | Expected |
74
+ |----------------------|----------------------------------------|---------------------------------------------|
75
+ | Round-trip | `fixtures/commonmeta/<name>.json` | itself (re-serialized, semantically equal) |
76
+ | Reader (JSON input) | `fixtures/<format>/<name>.json` | `fixtures/commonmeta/<name>.json` |
77
+ | Reader (text input) | `fixtures/<format>/<name>.<ext>` | `fixtures/<format>_commonmeta/<name>.json` |
78
+ | Writer | `fixtures/commonmeta/<name>.json` | `fixtures/<format>_out/<name>.<ext>` |
79
+
80
+ Formats currently covered: `crossref`, `crossref_xml`, `datacite`,
81
+ `datacite_xml`, `schemaorg`, `csl`, `bibtex`, `cff`, `ris`,
82
+ `inveniordm`, `codemeta`, `orcid`, `orcid_xml`, `openalex_source`.
83
+
84
+ ### OpenAlex scope
85
+
86
+ The `openalex_source` fixtures cover OpenAlex **sources/containers** (for
87
+ example journal, repository, and blog containers), not OpenAlex works.
88
+
89
+ - `fixtures/openalex_source/*.json` are OpenAlex source records (`S...` IDs).
90
+ - `fixtures/commonmeta/openalex_source_*.json` are the expected Commonmeta
91
+ container entities.
92
+
93
+ OpenAlex works should be added under a separate format namespace (for example
94
+ `openalex_work`) to keep reader and writer behavior unambiguous.
95
+
96
+ Most fixtures are `work` entities; `orcid` and `orcid_xml` cover `person`
97
+ instead. Both read a full ORCID record — with employments and educations as
98
+ affiliations — from two different sources:
99
+
100
+ - `orcid/<id>.json` is the ORCID REST API `/record` response (JSON). Because it
101
+ carries the full person, its commonmeta output also has `description` and
102
+ `urls`. → `commonmeta/<id>.json`
103
+ - `orcid_xml/<id>.xml` is the ORCID Public Data File record (XML), a summary
104
+ that omits biography and researcher URLs. → `orcid_xml_commonmeta/<id>.json`
105
+
106
+ Both fixtures trim the record's works list to the 10 most recent (the readers
107
+ convert person identity and affiliations, not works).
108
+
109
+ ### Semantic comparison
110
+
111
+ Fixtures are compared as parsed JSON trees, not as strings, using an
112
+ omitempty-aware and numeric-aware diff: key order and whitespace are
113
+ irrelevant, an absent field equals an empty/zero/null value, and `52`
114
+ equals `52.0`. This keeps hand-authored fixtures robust across
115
+ implementations.
116
+
117
+ ### Utility fixtures
118
+
119
+ `fixtures/utils/` is reserved for shared cross-implementation test data for
120
+ helper functions outside reader/writer format conversion. The first use is DOI
121
+ helper coverage for `encode_doi` and `decode_doi`. These fixtures are not
122
+ reader/writer conformance cases; they exist so `commonmeta-py` and
123
+ `commonmeta-rs` can assert the same normalization, checksum, and error
124
+ handling behavior from one canonical source.
125
+
126
+ ## Using this repository
127
+
128
+ Each implementation vendors (copies) the schema and fixtures it needs from
129
+ here. Update the canonical files in this repository first, then sync them
130
+ into `commonmeta-rs` and `commonmeta-py`.
131
+
132
+ ## Packaging and publishing
133
+
134
+ This repository can be published as both:
135
+
136
+ - a Python package on PyPI (`commonmeta-schema`)
137
+ - a Rust crate on crates.io (`commonmeta-schema`)
138
+ - a JavaScript package on npm (`commonmeta-schema`)
139
+
140
+ Publishing is done explicitly via CLI (no automated release pipeline in this repo).
141
+
142
+ The packages are released as `1.0.0`; both ship the `v1.0` schema:
143
+
144
+ - PyPI uses PEP 440 form: `1.0.0`
145
+ - crates.io uses SemVer form: `1.0.0`
146
+ - npm uses SemVer form: `1.0.0`
147
+
148
+ `scripts/sync_versions.py` is the single entry point for preparing a release. It
149
+ does three things, in this order:
150
+
151
+ 1. Rewrites `schemas/commonmeta_v1.0.json` from the newest `commonmeta_v1.0rc*.json`,
152
+ resetting `$id`, `title`, and the `schema_version` const to the stable v1.0 URL.
153
+ 2. Mirrors the canonical `schemas/` and `fixtures/` into `rust/schemas/` and
154
+ `rust/fixtures/` (the crate can only package files under `rust/`).
155
+ 3. Syncs `rust/Cargo.toml`'s version with `pyproject.toml`'s.
156
+ 4. Syncs `package.json`'s version with `pyproject.toml`'s.
157
+
158
+ ```bash
159
+ python scripts/sync_versions.py
160
+ ```
161
+
162
+ The ordering matters and is why the mirror lives in the script rather than in a
163
+ separate `rsync` step: mirroring before step 1 ships a crate whose
164
+ `commonmeta_v1.0.json` still carries the previous rc's `schema_version` const,
165
+ which then rejects the crate's own v1.0-stamped fixtures.
166
+
167
+ To verify sync in CI/local checks without changing files:
168
+
169
+ ```bash
170
+ python scripts/sync_versions.py --check
171
+ ```
172
+
173
+ Recommended pre-release checks:
174
+
175
+ ```bash
176
+ python scripts/sync_versions.py --check
177
+ uv build
178
+ cargo test --manifest-path rust/Cargo.toml
179
+ cargo package --manifest-path rust/Cargo.toml
180
+ npm pack --dry-run
181
+ ```
182
+
183
+ ### JavaScript / TypeScript (npm)
184
+
185
+ Install:
186
+
187
+ ```bash
188
+ npm install commonmeta-schema
189
+ ```
190
+
191
+ Read packaged assets by path:
192
+
193
+ ```js
194
+ import { readFileSync } from "node:fs";
195
+ import { fixturesPath, schemaPath } from "commonmeta-schema";
196
+
197
+ const schema = JSON.parse(readFileSync(schemaPath("1.0"), "utf8"));
198
+ const fixture = JSON.parse(
199
+ readFileSync(`${fixturesPath("commonmeta")}/journal_article.json`, "utf8")
200
+ );
201
+ ```
202
+
203
+ Or import JSON files directly from subpath exports:
204
+
205
+ ```js
206
+ import schema from "commonmeta-schema/schemas/commonmeta_v1.0.json" with { type: "json" };
207
+ ```
208
+
209
+ The helper API mirrors the Python package and exports `packageRoot`,
210
+ `schemaPath(version)`, `fixturesPath(formatName)`, and
211
+ `availableSchemaVersions()`.
212
+
213
+ ### Python (PyPI) via `uv publish`
214
+
215
+ 1. Ensure you are authenticated for PyPI (recommended: trusted publisher or API token).
216
+ 2. Build distribution artifacts:
217
+
218
+ ```bash
219
+ uv build
220
+ ```
221
+
222
+ 3. Optionally validate the build metadata:
223
+
224
+ ```bash
225
+ uvx twine check dist/*
226
+ ```
227
+
228
+ 4. Publish to PyPI:
229
+
230
+ ```bash
231
+ uv publish
232
+ ```
233
+
234
+ ### Rust (crates.io) via `cargo publish`
235
+
236
+ 1. Log in once with a crates.io token:
237
+
238
+ ```bash
239
+ cargo login
240
+ ```
241
+
242
+ 2. Validate package contents:
243
+
244
+ ```bash
245
+ cargo package --manifest-path rust/Cargo.toml --allow-dirty
246
+ ```
247
+
248
+ 3. Publish:
249
+
250
+ ```bash
251
+ cargo publish --manifest-path rust/Cargo.toml
252
+ ```
253
+
254
+ ### JavaScript / TypeScript (npm) via `npm publish`
255
+
256
+ 1. Authenticate with npm (once per environment):
257
+
258
+ ```bash
259
+ npm login
260
+ npm whoami
261
+ ```
262
+
263
+ 2. Validate package contents:
264
+
265
+ ```bash
266
+ npm pack --dry-run
267
+ ```
268
+
269
+ 3. Publish the version from `package.json`:
270
+
271
+ ```bash
272
+ npm publish
273
+ ```
274
+
275
+ The package is public and its version must not already exist on npm. Verify the
276
+ published version after npm completes:
277
+
278
+ ```bash
279
+ npm view commonmeta-schema version
280
+ ```
281
+
282
+ ### Recommended release order
283
+
284
+ 1. Publish `1.0.0` to PyPI with `uv publish`.
285
+ 2. Publish `1.0.0` to crates.io with `cargo publish`.
286
+ 3. Publish `1.0.0` to npm with `npm publish`.
287
+ 4. Create a git tag `v1.0.0` after all uploads succeed.
288
+
289
+ ### Copy-paste release run
290
+
291
+ Run this from the repository root:
292
+
293
+ ```bash
294
+ set -euo pipefail
295
+
296
+ # 1) Regenerate the v1.0 alias, mirror assets into rust/, sync the crate version
297
+ python scripts/sync_versions.py
298
+
299
+ # 2) Fail the release if anything is still out of sync
300
+ python scripts/sync_versions.py --check
301
+
302
+ # 3) Validate both package builds
303
+ uv build
304
+ cargo test --manifest-path rust/Cargo.toml
305
+ cargo package --manifest-path rust/Cargo.toml
306
+ npm pack --dry-run
307
+
308
+ # 4) Publish Python package
309
+ uv publish
310
+
311
+ # 5) Publish Rust crate
312
+ cargo publish --manifest-path rust/Cargo.toml
313
+
314
+ # 6) Publish npm package
315
+ npm publish
316
+
317
+ # 7) Tag release (replace with the release version)
318
+ git tag v1.0.0
319
+ git push origin v1.0.0
320
+ ```
321
+
322
+ ## License
323
+
324
+ [MIT](LICENSE) © 2026 Front Matter
@@ -0,0 +1,297 @@
1
+ # commonmeta-schema
2
+
3
+ Language-neutral JSON Schema definitions and conformance fixtures for
4
+ [Commonmeta](https://commonmeta.org), the scholarly metadata interchange format.
5
+
6
+ This repository is the shared source of truth consumed by the following Commonmeta
7
+ implementations:
8
+
9
+ - [commonmeta-rs](https://github.com/front-matter/commonmeta-rs) (Rust)
10
+ - [commonmeta-py](https://github.com/front-matter/commonmeta-py) (Python)
11
+
12
+ Keeping the schema and the golden fixtures in one place lets every
13
+ implementation validate against the same contract and run the same
14
+ cross-format conformance tests.
15
+
16
+ ## Layout
17
+
18
+ ```
19
+ schemas/
20
+ commonmeta_v1.0.json # the Commonmeta JSON Schema (current)
21
+ commonmeta_v1.0rc*.json # earlier release candidates, retained but not exported
22
+ fixtures/
23
+ commonmeta/ # canonical Commonmeta records (round-trip + expected output)
24
+ <format>/ # input fixtures in a given source format
25
+ <format>_out/ # expected writer output (Commonmeta -> format)
26
+ <format>_commonmeta/ # expected reader output for non-JSON inputs
27
+ utils/ # shared utility fixtures for helpers outside format conversion
28
+ ```
29
+
30
+ ## Schema versions
31
+
32
+ Schemas are versioned by filename. The current version is `commonmeta_v1.0.json`,
33
+ and the `schema_version` field of a Commonmeta record is the URL
34
+ `https://commonmeta.org/commonmeta_v1.0.json`.
35
+
36
+ Earlier release candidates (`commonmeta_v1.0rc1`…`rc31`) are kept in `schemas/`
37
+ for reference, but the packages export only `v1.0` — new versions are added
38
+ alongside existing files rather than replacing them, so implementations can pin
39
+ a version.
40
+
41
+ ## Fixture conventions
42
+
43
+ The conformance harness in each implementation follows these naming rules
44
+ (a missing pair is skipped, so partial coverage is fine):
45
+
46
+ | Test kind | Input | Expected |
47
+ |----------------------|----------------------------------------|---------------------------------------------|
48
+ | Round-trip | `fixtures/commonmeta/<name>.json` | itself (re-serialized, semantically equal) |
49
+ | Reader (JSON input) | `fixtures/<format>/<name>.json` | `fixtures/commonmeta/<name>.json` |
50
+ | Reader (text input) | `fixtures/<format>/<name>.<ext>` | `fixtures/<format>_commonmeta/<name>.json` |
51
+ | Writer | `fixtures/commonmeta/<name>.json` | `fixtures/<format>_out/<name>.<ext>` |
52
+
53
+ Formats currently covered: `crossref`, `crossref_xml`, `datacite`,
54
+ `datacite_xml`, `schemaorg`, `csl`, `bibtex`, `cff`, `ris`,
55
+ `inveniordm`, `codemeta`, `orcid`, `orcid_xml`, `openalex_source`.
56
+
57
+ ### OpenAlex scope
58
+
59
+ The `openalex_source` fixtures cover OpenAlex **sources/containers** (for
60
+ example journal, repository, and blog containers), not OpenAlex works.
61
+
62
+ - `fixtures/openalex_source/*.json` are OpenAlex source records (`S...` IDs).
63
+ - `fixtures/commonmeta/openalex_source_*.json` are the expected Commonmeta
64
+ container entities.
65
+
66
+ OpenAlex works should be added under a separate format namespace (for example
67
+ `openalex_work`) to keep reader and writer behavior unambiguous.
68
+
69
+ Most fixtures are `work` entities; `orcid` and `orcid_xml` cover `person`
70
+ instead. Both read a full ORCID record — with employments and educations as
71
+ affiliations — from two different sources:
72
+
73
+ - `orcid/<id>.json` is the ORCID REST API `/record` response (JSON). Because it
74
+ carries the full person, its commonmeta output also has `description` and
75
+ `urls`. → `commonmeta/<id>.json`
76
+ - `orcid_xml/<id>.xml` is the ORCID Public Data File record (XML), a summary
77
+ that omits biography and researcher URLs. → `orcid_xml_commonmeta/<id>.json`
78
+
79
+ Both fixtures trim the record's works list to the 10 most recent (the readers
80
+ convert person identity and affiliations, not works).
81
+
82
+ ### Semantic comparison
83
+
84
+ Fixtures are compared as parsed JSON trees, not as strings, using an
85
+ omitempty-aware and numeric-aware diff: key order and whitespace are
86
+ irrelevant, an absent field equals an empty/zero/null value, and `52`
87
+ equals `52.0`. This keeps hand-authored fixtures robust across
88
+ implementations.
89
+
90
+ ### Utility fixtures
91
+
92
+ `fixtures/utils/` is reserved for shared cross-implementation test data for
93
+ helper functions outside reader/writer format conversion. The first use is DOI
94
+ helper coverage for `encode_doi` and `decode_doi`. These fixtures are not
95
+ reader/writer conformance cases; they exist so `commonmeta-py` and
96
+ `commonmeta-rs` can assert the same normalization, checksum, and error
97
+ handling behavior from one canonical source.
98
+
99
+ ## Using this repository
100
+
101
+ Each implementation vendors (copies) the schema and fixtures it needs from
102
+ here. Update the canonical files in this repository first, then sync them
103
+ into `commonmeta-rs` and `commonmeta-py`.
104
+
105
+ ## Packaging and publishing
106
+
107
+ This repository can be published as both:
108
+
109
+ - a Python package on PyPI (`commonmeta-schema`)
110
+ - a Rust crate on crates.io (`commonmeta-schema`)
111
+ - a JavaScript package on npm (`commonmeta-schema`)
112
+
113
+ Publishing is done explicitly via CLI (no automated release pipeline in this repo).
114
+
115
+ The packages are released as `1.0.0`; both ship the `v1.0` schema:
116
+
117
+ - PyPI uses PEP 440 form: `1.0.0`
118
+ - crates.io uses SemVer form: `1.0.0`
119
+ - npm uses SemVer form: `1.0.0`
120
+
121
+ `scripts/sync_versions.py` is the single entry point for preparing a release. It
122
+ does three things, in this order:
123
+
124
+ 1. Rewrites `schemas/commonmeta_v1.0.json` from the newest `commonmeta_v1.0rc*.json`,
125
+ resetting `$id`, `title`, and the `schema_version` const to the stable v1.0 URL.
126
+ 2. Mirrors the canonical `schemas/` and `fixtures/` into `rust/schemas/` and
127
+ `rust/fixtures/` (the crate can only package files under `rust/`).
128
+ 3. Syncs `rust/Cargo.toml`'s version with `pyproject.toml`'s.
129
+ 4. Syncs `package.json`'s version with `pyproject.toml`'s.
130
+
131
+ ```bash
132
+ python scripts/sync_versions.py
133
+ ```
134
+
135
+ The ordering matters and is why the mirror lives in the script rather than in a
136
+ separate `rsync` step: mirroring before step 1 ships a crate whose
137
+ `commonmeta_v1.0.json` still carries the previous rc's `schema_version` const,
138
+ which then rejects the crate's own v1.0-stamped fixtures.
139
+
140
+ To verify sync in CI/local checks without changing files:
141
+
142
+ ```bash
143
+ python scripts/sync_versions.py --check
144
+ ```
145
+
146
+ Recommended pre-release checks:
147
+
148
+ ```bash
149
+ python scripts/sync_versions.py --check
150
+ uv build
151
+ cargo test --manifest-path rust/Cargo.toml
152
+ cargo package --manifest-path rust/Cargo.toml
153
+ npm pack --dry-run
154
+ ```
155
+
156
+ ### JavaScript / TypeScript (npm)
157
+
158
+ Install:
159
+
160
+ ```bash
161
+ npm install commonmeta-schema
162
+ ```
163
+
164
+ Read packaged assets by path:
165
+
166
+ ```js
167
+ import { readFileSync } from "node:fs";
168
+ import { fixturesPath, schemaPath } from "commonmeta-schema";
169
+
170
+ const schema = JSON.parse(readFileSync(schemaPath("1.0"), "utf8"));
171
+ const fixture = JSON.parse(
172
+ readFileSync(`${fixturesPath("commonmeta")}/journal_article.json`, "utf8")
173
+ );
174
+ ```
175
+
176
+ Or import JSON files directly from subpath exports:
177
+
178
+ ```js
179
+ import schema from "commonmeta-schema/schemas/commonmeta_v1.0.json" with { type: "json" };
180
+ ```
181
+
182
+ The helper API mirrors the Python package and exports `packageRoot`,
183
+ `schemaPath(version)`, `fixturesPath(formatName)`, and
184
+ `availableSchemaVersions()`.
185
+
186
+ ### Python (PyPI) via `uv publish`
187
+
188
+ 1. Ensure you are authenticated for PyPI (recommended: trusted publisher or API token).
189
+ 2. Build distribution artifacts:
190
+
191
+ ```bash
192
+ uv build
193
+ ```
194
+
195
+ 3. Optionally validate the build metadata:
196
+
197
+ ```bash
198
+ uvx twine check dist/*
199
+ ```
200
+
201
+ 4. Publish to PyPI:
202
+
203
+ ```bash
204
+ uv publish
205
+ ```
206
+
207
+ ### Rust (crates.io) via `cargo publish`
208
+
209
+ 1. Log in once with a crates.io token:
210
+
211
+ ```bash
212
+ cargo login
213
+ ```
214
+
215
+ 2. Validate package contents:
216
+
217
+ ```bash
218
+ cargo package --manifest-path rust/Cargo.toml --allow-dirty
219
+ ```
220
+
221
+ 3. Publish:
222
+
223
+ ```bash
224
+ cargo publish --manifest-path rust/Cargo.toml
225
+ ```
226
+
227
+ ### JavaScript / TypeScript (npm) via `npm publish`
228
+
229
+ 1. Authenticate with npm (once per environment):
230
+
231
+ ```bash
232
+ npm login
233
+ npm whoami
234
+ ```
235
+
236
+ 2. Validate package contents:
237
+
238
+ ```bash
239
+ npm pack --dry-run
240
+ ```
241
+
242
+ 3. Publish the version from `package.json`:
243
+
244
+ ```bash
245
+ npm publish
246
+ ```
247
+
248
+ The package is public and its version must not already exist on npm. Verify the
249
+ published version after npm completes:
250
+
251
+ ```bash
252
+ npm view commonmeta-schema version
253
+ ```
254
+
255
+ ### Recommended release order
256
+
257
+ 1. Publish `1.0.0` to PyPI with `uv publish`.
258
+ 2. Publish `1.0.0` to crates.io with `cargo publish`.
259
+ 3. Publish `1.0.0` to npm with `npm publish`.
260
+ 4. Create a git tag `v1.0.0` after all uploads succeed.
261
+
262
+ ### Copy-paste release run
263
+
264
+ Run this from the repository root:
265
+
266
+ ```bash
267
+ set -euo pipefail
268
+
269
+ # 1) Regenerate the v1.0 alias, mirror assets into rust/, sync the crate version
270
+ python scripts/sync_versions.py
271
+
272
+ # 2) Fail the release if anything is still out of sync
273
+ python scripts/sync_versions.py --check
274
+
275
+ # 3) Validate both package builds
276
+ uv build
277
+ cargo test --manifest-path rust/Cargo.toml
278
+ cargo package --manifest-path rust/Cargo.toml
279
+ npm pack --dry-run
280
+
281
+ # 4) Publish Python package
282
+ uv publish
283
+
284
+ # 5) Publish Rust crate
285
+ cargo publish --manifest-path rust/Cargo.toml
286
+
287
+ # 6) Publish npm package
288
+ npm publish
289
+
290
+ # 7) Tag release (replace with the release version)
291
+ git tag v1.0.0
292
+ git push origin v1.0.0
293
+ ```
294
+
295
+ ## License
296
+
297
+ [MIT](LICENSE) © 2026 Front Matter
@@ -0,0 +1,14 @@
1
+ @article{Sankar_2014,
2
+ doi = {10.7554/elife.01567},
3
+ url = {http://elifesciences.org/lookup/doi/10.7554/eLife.01567},
4
+ year = 2014,
5
+ month = {feb},
6
+ publisher = {{eLife} Sciences Organisation, Ltd.},
7
+ volume = {3},
8
+ author = {Martial Sankar and Kaisa Nieminen and Laura Ragni and Ioannis Xenarios and Christian S Hardtke},
9
+ title = {Automated quantitative histology reveals vascular morphodynamics during Arabidopsis hypocotyl secondary growth},
10
+ abstract = {Among various advantages, their small size makes model organisms preferred subjects of investigation. Yet, even in model systems detailed analysis of numerous developmental processes at cellular level is severely hampered by their scale.},
11
+ journal = {eLife},
12
+ issn = {2050-084X},
13
+ copyright = {http://creativecommons.org/licenses/by/3.0/}
14
+ }
@@ -0,0 +1,14 @@
1
+ @article{10.5555/12345678,
2
+ author = {Lovelace, Ada},
3
+ copyright = {https://creativecommons.org/licenses/by/4.0/legalcode},
4
+ date = {2024-03-15},
5
+ doi = {10.5555/12345678},
6
+ issn = {1234-5678},
7
+ issue = {3},
8
+ journal = {Journal of Examples},
9
+ language = {English},
10
+ pages = {100--110},
11
+ title = {A Study of Things},
12
+ url = {https://example.org/article/1},
13
+ volume = {12},
14
+ }