From ab504a4be845703c41be5e230c8a711480505ac1 Mon Sep 17 00:00:00 2001 From: Maciej Lamberski Date: Mon, 27 Oct 2025 12:20:20 +0100 Subject: [PATCH 1/2] feat: Add plural variants for DC Terms fields and deprecate singular --- src/feeds/atom/parse/utils.test.ts | 4 + src/feeds/atom/references/atom-ns.json | 132 +++++++-- src/feeds/rdf/parse/utils.test.ts | 4 + src/feeds/rdf/references/rdf-ns.json | 132 +++++++-- src/feeds/rss/parse/utils.test.ts | 4 + src/feeds/rss/references/rss-ns.json | 132 +++++++-- src/namespaces/dcterms/common/types.ts | 111 ++++++- src/namespaces/dcterms/generate/utils.test.ts | 270 +++++++++++++----- src/namespaces/dcterms/generate/utils.ts | 267 +++++++++++++---- src/namespaces/dcterms/parse/utils.test.ts | 185 +++++++++++- src/namespaces/dcterms/parse/utils.ts | 129 +++++++-- 11 files changed, 1173 insertions(+), 197 deletions(-) diff --git a/src/feeds/atom/parse/utils.test.ts b/src/feeds/atom/parse/utils.test.ts index 0e79d027..aeed6fd2 100644 --- a/src/feeds/atom/parse/utils.test.ts +++ b/src/feeds/atom/parse/utils.test.ts @@ -1046,6 +1046,8 @@ describe('parseEntry', () => { id: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', title: 'Example Entry', dcterms: { + createds: ['2023-02-01T00:00:00Z'], + licenses: ['MIT License'], created: '2023-02-01T00:00:00Z', license: 'MIT License', }, @@ -1525,6 +1527,8 @@ describe('parseFeed', () => { id: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', title: 'Example Feed', dcterms: { + createds: ['2023-01-01T00:00:00Z'], + licenses: ['Creative Commons Attribution 4.0'], created: '2023-01-01T00:00:00Z', license: 'Creative Commons Attribution 4.0', }, diff --git a/src/feeds/atom/references/atom-ns.json b/src/feeds/atom/references/atom-ns.json index ac235cc4..b7da33a0 100644 --- a/src/feeds/atom/references/atom-ns.json +++ b/src/feeds/atom/references/atom-ns.json @@ -23,10 +23,64 @@ "rights": "Copyright 2025 Example News Organization" }, "dcterms": { - "created": "2022-01-01T12:00:00.000Z", - "license": "Creative Commons Attribution 4.0", + "abstracts": ["This article explores advanced concepts in technology"], + "accessRights": ["Public access with attribution required"], + "accrualMethods": ["Single publication"], + "accrualPeriodicities": ["One-time"], + "accrualPolicies": ["Editorial review required"], + "alternatives": ["Alternative Item Title"], + "audiences": ["Technical professionals"], + "availables": ["2022-01-01T12:00:00.000Z"], + "bibliographicCitations": [ + "Smith, J. (2022). Example Item. Retrieved from https://example.org/item/1" + ], + "conformsTos": ["HTML5 standard"], + "contributors": ["Assistant Editor Mike Thompson"], + "coverages": ["United States technology sector"], + "createds": ["2022-01-01T12:00:00.000Z"], + "creators": ["Jack Jackson"], + "dates": ["2022-01-01T12:00:00.000Z"], + "dateAccepteds": ["2022-01-01T12:00:00.000Z"], + "dateCopyrighteds": ["2022-01-01T12:00:00.000Z"], + "dateSubmitteds": ["2022-01-01T12:00:00.000Z"], + "descriptions": ["Detailed description of the example item content and its significance"], + "educationLevels": ["Advanced"], + "extents": ["Approximately 2500 words"], + "formats": ["text/html"], + "hasFormats": ["https://example.org/item/1.pdf"], + "hasParts": ["https://example.org/item/1/section1"], + "hasVersions": ["1.1"], + "identifiers": ["urn:uuid:item-98765432-9876-9876-9876-987654321def"], + "instructionalMethods": ["Step-by-step tutorial"], + "isFormatOfs": ["https://example.org/item-source"], + "isPartOfs": ["Example Article Series"], + "isReferencedBys": ["https://example.org/item/1/citations"], + "isReplacedBys": ["https://example.org/item/1/updated"], + "isRequiredBys": ["https://example.org/item/1/prerequisites"], + "issueds": ["2022-01-01T12:00:00.000Z"], + "isVersionOfs": ["https://example.org/item/1/original"], + "languages": ["en-US"], + "licenses": ["Creative Commons Attribution 4.0"], + "mediators": ["Editorial Team"], + "mediums": ["Digital"], + "modifieds": ["2022-06-01T12:00:00.000Z"], + "provenances": ["Originally published by Example News Organization"], + "publishers": ["Example News Organization"], + "references": ["https://example.org/item/1/references"], + "relations": ["https://example.org/related-article"], + "replaces": ["https://example.org/item/1/previous"], + "requires": ["Basic understanding of web technologies"], + "rights": ["Copyright 2025 Example News Organization"], + "rightsHolders": ["Example News Organization"], + "sources": ["https://example.org/item-source"], + "spatials": ["United States"], + "subjects": ["Article, Tutorial, Example"], + "tableOfContents": ["Introduction, Main Content, Conclusion"], + "temporals": ["2022"], + "titles": ["Dublin Core Terms Enhanced Item Title"], + "types": ["Article"], + "valids": ["2025-12-31T23:59:59.000Z"], "abstract": "This article explores advanced concepts in technology", - "accessRights": "Public access with attribution required", "accrualMethod": "Single publication", "accrualPeriodicity": "One-time", "accrualPolicy": "Editorial review required", @@ -37,6 +91,7 @@ "conformsTo": "HTML5 standard", "contributor": "Assistant Editor Mike Thompson", "coverage": "United States technology sector", + "created": "2022-01-01T12:00:00.000Z", "creator": "Jack Jackson", "date": "2022-01-01T12:00:00.000Z", "dateAccepted": "2022-01-01T12:00:00.000Z", @@ -59,21 +114,17 @@ "issued": "2022-01-01T12:00:00.000Z", "isVersionOf": "https://example.org/item/1/original", "language": "en-US", + "license": "Creative Commons Attribution 4.0", "mediator": "Editorial Team", "medium": "Digital", "modified": "2022-06-01T12:00:00.000Z", "provenance": "Originally published by Example News Organization", "publisher": "Example News Organization", - "references": "https://example.org/item/1/references", "relation": "https://example.org/related-article", - "replaces": "https://example.org/item/1/previous", - "requires": "Basic understanding of web technologies", - "rights": "Copyright 2025 Example News Organization", "rightsHolder": "Example News Organization", "source": "https://example.org/item-source", "spatial": "United States", "subject": "Article, Tutorial, Example", - "tableOfContents": "Introduction, Main Content, Conclusion", "temporal": "2022", "title": "Dublin Core Terms Enhanced Item Title", "type": "Article", @@ -712,10 +763,62 @@ "rights": "Copyright 2025 Example Publishing Company" }, "dcterms": { - "created": "2022-01-01T12:00:00.000Z", - "license": "Creative Commons Attribution 4.0", + "abstracts": ["This is an abstract of the feed content"], + "accessRights": ["Public access with attribution required"], + "accrualMethods": ["Regular updates"], + "accrualPeriodicities": ["Daily"], + "accrualPolicies": ["Content added based on editorial calendar"], + "alternatives": ["Alternative Feed Title"], + "audiences": ["General technology audience"], + "availables": ["2022-01-01T12:00:00.000Z"], + "bibliographicCitations": ["Example Feed. (2022). Retrieved from https://example.org"], + "conformsTos": ["RSS 2.0 Specification"], + "contributors": ["Jane Smith"], + "coverages": ["Global technology topics"], + "createds": ["2022-01-01T12:00:00.000Z"], + "creators": ["John Doe"], + "dates": ["2022-01-01T12:00:00.000Z"], + "dateAccepteds": ["2022-01-01T12:00:00.000Z"], + "dateCopyrighteds": ["2022-01-01T12:00:00.000Z"], + "dateSubmitteds": ["2022-01-01T12:00:00.000Z"], + "descriptions": ["Detailed description of the feed content and purpose"], + "educationLevels": ["Intermediate to advanced"], + "extents": ["Approximately 1000 words per article"], + "formats": ["application/atom+xml"], + "hasFormats": ["https://example.org/feed.atom"], + "hasParts": ["https://example.org/category/tutorials"], + "hasVersions": ["2.0"], + "identifiers": ["urn:uuid:feed-12345678-1234-1234-1234-123456789abc"], + "instructionalMethods": ["Practical examples and tutorials"], + "isFormatOfs": ["https://example.org/original-content"], + "isPartOfs": ["Example Media Network"], + "isReferencedBys": ["https://example.org/references"], + "isReplacedBys": ["https://example.org/new-feed"], + "isRequiredBys": ["https://example.org/dependent-feeds"], + "issueds": ["2022-01-01T12:00:00.000Z"], + "isVersionOfs": ["https://example.org/original-feed"], + "languages": ["en-US"], + "licenses": ["Creative Commons Attribution 4.0"], + "mediators": ["Content Management System"], + "mediums": ["Digital"], + "modifieds": ["2023-01-01T12:00:00.000Z"], + "provenances": ["Originally created by Example Publishing Company"], + "publishers": ["Example Publishing Company"], + "references": ["https://example.org/referenced-sources"], + "relations": ["https://example.org/related-feeds"], + "replaces": ["https://example.org/old-feed"], + "requires": ["RSS 2.0 compatible reader"], + "rights": ["Copyright 2025 Example Publishing Company"], + "rightsHolders": ["Example Publishing Company"], + "sources": ["https://example.org/original-source"], + "spatials": ["Global"], + "subjects": ["Technology, Programming, Web Development"], + "tableOfContents": ["Latest articles, tutorials, and news"], + "temporals": ["2022-present"], + "titles": ["Dublin Core Terms Enhanced Feed Title"], + "types": ["Text"], + "valids": ["2025-12-31T23:59:59.000Z"], "abstract": "This is an abstract of the feed content", - "accessRights": "Public access with attribution required", "accrualMethod": "Regular updates", "accrualPeriodicity": "Daily", "accrualPolicy": "Content added based on editorial calendar", @@ -726,6 +829,7 @@ "conformsTo": "RSS 2.0 Specification", "contributor": "Jane Smith", "coverage": "Global technology topics", + "created": "2022-01-01T12:00:00.000Z", "creator": "John Doe", "date": "2022-01-01T12:00:00.000Z", "dateAccepted": "2022-01-01T12:00:00.000Z", @@ -748,21 +852,17 @@ "issued": "2022-01-01T12:00:00.000Z", "isVersionOf": "https://example.org/original-feed", "language": "en-US", + "license": "Creative Commons Attribution 4.0", "mediator": "Content Management System", "medium": "Digital", "modified": "2023-01-01T12:00:00.000Z", "provenance": "Originally created by Example Publishing Company", "publisher": "Example Publishing Company", - "references": "https://example.org/referenced-sources", "relation": "https://example.org/related-feeds", - "replaces": "https://example.org/old-feed", - "requires": "RSS 2.0 compatible reader", - "rights": "Copyright 2025 Example Publishing Company", "rightsHolder": "Example Publishing Company", "source": "https://example.org/original-source", "spatial": "Global", "subject": "Technology, Programming, Web Development", - "tableOfContents": "Latest articles, tutorials, and news", "temporal": "2022-present", "title": "Dublin Core Terms Enhanced Feed Title", "type": "Text", diff --git a/src/feeds/rdf/parse/utils.test.ts b/src/feeds/rdf/parse/utils.test.ts index be7e84b4..0386be86 100644 --- a/src/feeds/rdf/parse/utils.test.ts +++ b/src/feeds/rdf/parse/utils.test.ts @@ -443,6 +443,8 @@ describe('parseItem', () => { title: 'Example Entry', link: 'http://example.com', dcterms: { + createds: ['2023-02-01T00:00:00Z'], + licenses: ['MIT License'], created: '2023-02-01T00:00:00Z', license: 'MIT License', }, @@ -1016,6 +1018,8 @@ describe('parseFeed', () => { }, ], dcterms: { + createds: ['2023-01-01T00:00:00Z'], + licenses: ['Creative Commons Attribution 4.0'], created: '2023-01-01T00:00:00Z', license: 'Creative Commons Attribution 4.0', }, diff --git a/src/feeds/rdf/references/rdf-ns.json b/src/feeds/rdf/references/rdf-ns.json index f18f7e5c..c1dbce47 100644 --- a/src/feeds/rdf/references/rdf-ns.json +++ b/src/feeds/rdf/references/rdf-ns.json @@ -26,10 +26,64 @@ "rights": "Copyright 2025 Example News Organization" }, "dcterms": { - "created": "2022-01-01T12:00+00:00", - "license": "Creative Commons Attribution 4.0", + "abstracts": ["This article explores advanced concepts in technology"], + "accessRights": ["Public access with attribution required"], + "accrualMethods": ["Single publication"], + "accrualPeriodicities": ["One-time"], + "accrualPolicies": ["Editorial review required"], + "alternatives": ["Alternative Item Title"], + "audiences": ["Technical professionals"], + "availables": ["2022-01-01T12:00+00:00"], + "bibliographicCitations": [ + "Smith, J. (2022). Example Item. Retrieved from https://example.org/item/1" + ], + "conformsTos": ["HTML5 standard"], + "contributors": ["Assistant Editor Mike Thompson"], + "coverages": ["United States technology sector"], + "createds": ["2022-01-01T12:00+00:00"], + "creators": ["Jack Jackson"], + "dateAccepteds": ["2022-01-01T12:00+00:00"], + "dateCopyrighteds": ["2022-01-01T12:00+00:00"], + "dateSubmitteds": ["2022-01-01T12:00+00:00"], + "dates": ["2022-01-01T12:00+00:00"], + "descriptions": ["Detailed description of the example item content and its significance"], + "educationLevels": ["Advanced"], + "extents": ["Approximately 2500 words"], + "formats": ["text/html"], + "hasFormats": ["https://example.org/item/1.pdf"], + "hasParts": ["https://example.org/item/1/section1"], + "hasVersions": ["1.1"], + "identifiers": ["urn:uuid:item-98765432-9876-9876-9876-987654321def"], + "instructionalMethods": ["Step-by-step tutorial"], + "isFormatOfs": ["https://example.org/item-source"], + "isPartOfs": ["Example Article Series"], + "isReferencedBys": ["https://example.org/item/1/citations"], + "isReplacedBys": ["https://example.org/item/1/updated"], + "isRequiredBys": ["https://example.org/item/1/prerequisites"], + "issueds": ["2022-01-01T12:00+00:00"], + "isVersionOfs": ["https://example.org/item/1/original"], + "languages": ["en-US"], + "licenses": ["Creative Commons Attribution 4.0"], + "mediators": ["Editorial Team"], + "mediums": ["Digital"], + "modifieds": ["2022-06-01T12:00+00:00"], + "provenances": ["Originally published by Example News Organization"], + "publishers": ["Example News Organization"], + "references": ["https://example.org/item/1/references"], + "relations": ["https://example.org/related-article"], + "replaces": ["https://example.org/item/1/previous"], + "requires": ["Basic understanding of web technologies"], + "rights": ["Copyright 2025 Example News Organization"], + "rightsHolders": ["Example News Organization"], + "sources": ["https://example.org/item-source"], + "spatials": ["United States"], + "subjects": ["Article, Tutorial, Example"], + "tableOfContents": ["Introduction, Main Content, Conclusion"], + "temporals": ["2022"], + "titles": ["Dublin Core Terms Enhanced Item Title"], + "types": ["Article"], + "valids": ["2025-12-31T23:59:59+00:00"], "abstract": "This article explores advanced concepts in technology", - "accessRights": "Public access with attribution required", "accrualMethod": "Single publication", "accrualPeriodicity": "One-time", "accrualPolicy": "Editorial review required", @@ -40,6 +94,7 @@ "conformsTo": "HTML5 standard", "contributor": "Assistant Editor Mike Thompson", "coverage": "United States technology sector", + "created": "2022-01-01T12:00+00:00", "creator": "Jack Jackson", "date": "2022-01-01T12:00+00:00", "dateAccepted": "2022-01-01T12:00+00:00", @@ -62,21 +117,17 @@ "issued": "2022-01-01T12:00+00:00", "isVersionOf": "https://example.org/item/1/original", "language": "en-US", + "license": "Creative Commons Attribution 4.0", "mediator": "Editorial Team", "medium": "Digital", "modified": "2022-06-01T12:00+00:00", "provenance": "Originally published by Example News Organization", "publisher": "Example News Organization", - "references": "https://example.org/item/1/references", "relation": "https://example.org/related-article", - "replaces": "https://example.org/item/1/previous", - "requires": "Basic understanding of web technologies", - "rights": "Copyright 2025 Example News Organization", "rightsHolder": "Example News Organization", "source": "https://example.org/item-source", "spatial": "United States", "subject": "Article, Tutorial, Example", - "tableOfContents": "Introduction, Main Content, Conclusion", "temporal": "2022", "title": "Dublin Core Terms Enhanced Item Title", "type": "Article", @@ -640,10 +691,62 @@ "rights": "Copyright 2025 Example Publishing Company" }, "dcterms": { - "created": "2022-01-01T12:00+00:00", - "license": "Creative Commons Attribution 4.0", + "abstracts": ["This is an abstract of the feed content"], + "accessRights": ["Public access with attribution required"], + "accrualMethods": ["Regular updates"], + "accrualPeriodicities": ["Daily"], + "accrualPolicies": ["Content added based on editorial calendar"], + "alternatives": ["Alternative Feed Title"], + "audiences": ["General technology audience"], + "availables": ["2022-01-01T12:00+00:00"], + "bibliographicCitations": ["Example Feed. (2022). Retrieved from https://example.org"], + "conformsTos": ["RSS 2.0 Specification"], + "contributors": ["Jane Smith"], + "coverages": ["Global technology topics"], + "createds": ["2022-01-01T12:00+00:00"], + "creators": ["John Doe"], + "dateAccepteds": ["2022-01-01T12:00+00:00"], + "dateCopyrighteds": ["2022-01-01T12:00+00:00"], + "dateSubmitteds": ["2022-01-01T12:00+00:00"], + "dates": ["2022-01-01T12:00+00:00"], + "descriptions": ["Detailed description of the feed content and purpose"], + "educationLevels": ["Intermediate to advanced"], + "extents": ["Approximately 1000 words per article"], + "formats": ["application/rdf+xml"], + "hasFormats": ["https://example.org/feed.atom"], + "hasParts": ["https://example.org/category/tutorials"], + "hasVersions": ["2.0"], + "identifiers": ["urn:uuid:feed-12345678-1234-1234-1234-123456789abc"], + "instructionalMethods": ["Practical examples and tutorials"], + "isFormatOfs": ["https://example.org/original-content"], + "isPartOfs": ["Example Media Network"], + "isReferencedBys": ["https://example.org/references"], + "isReplacedBys": ["https://example.org/new-feed"], + "isRequiredBys": ["https://example.org/dependent-feeds"], + "isVersionOfs": ["https://example.org/original-feed"], + "issueds": ["2022-01-01T12:00+00:00"], + "languages": ["en-US"], + "licenses": ["Creative Commons Attribution 4.0"], + "mediators": ["Content Management System"], + "mediums": ["Digital"], + "modifieds": ["2023-01-01T12:00+00:00"], + "provenances": ["Originally created by Example Publishing Company"], + "publishers": ["Example Publishing Company"], + "references": ["https://example.org/referenced-sources"], + "relations": ["https://example.org/related-feeds"], + "replaces": ["https://example.org/old-feed"], + "requires": ["RSS 2.0 compatible reader"], + "rights": ["Copyright 2025 Example Publishing Company"], + "rightsHolders": ["Example Publishing Company"], + "sources": ["https://example.org/original-source"], + "spatials": ["Global"], + "subjects": ["Technology, Programming, Web Development"], + "tableOfContents": ["Latest articles, tutorials, and news"], + "temporals": ["2022-present"], + "titles": ["Dublin Core Terms Enhanced Feed Title"], + "types": ["Text"], + "valids": ["2025-12-31T23:59:59+00:00"], "abstract": "This is an abstract of the feed content", - "accessRights": "Public access with attribution required", "accrualMethod": "Regular updates", "accrualPeriodicity": "Daily", "accrualPolicy": "Content added based on editorial calendar", @@ -654,6 +757,7 @@ "conformsTo": "RSS 2.0 Specification", "contributor": "Jane Smith", "coverage": "Global technology topics", + "created": "2022-01-01T12:00+00:00", "creator": "John Doe", "date": "2022-01-01T12:00+00:00", "dateAccepted": "2022-01-01T12:00+00:00", @@ -676,21 +780,17 @@ "issued": "2022-01-01T12:00+00:00", "isVersionOf": "https://example.org/original-feed", "language": "en-US", + "license": "Creative Commons Attribution 4.0", "mediator": "Content Management System", "medium": "Digital", "modified": "2023-01-01T12:00+00:00", "provenance": "Originally created by Example Publishing Company", "publisher": "Example Publishing Company", - "references": "https://example.org/referenced-sources", "relation": "https://example.org/related-feeds", - "replaces": "https://example.org/old-feed", - "requires": "RSS 2.0 compatible reader", - "rights": "Copyright 2025 Example Publishing Company", "rightsHolder": "Example Publishing Company", "source": "https://example.org/original-source", "spatial": "Global", "subject": "Technology, Programming, Web Development", - "tableOfContents": "Latest articles, tutorials, and news", "temporal": "2022-present", "title": "Dublin Core Terms Enhanced Feed Title", "type": "Text", diff --git a/src/feeds/rss/parse/utils.test.ts b/src/feeds/rss/parse/utils.test.ts index e99ecd3e..6a81f28c 100644 --- a/src/feeds/rss/parse/utils.test.ts +++ b/src/feeds/rss/parse/utils.test.ts @@ -861,6 +861,8 @@ describe('parseItem', () => { const expected = { title: 'Example Entry', dcterms: { + createds: ['2023-02-01T00:00:00Z'], + licenses: ['MIT License'], created: '2023-02-01T00:00:00Z', license: 'MIT License', }, @@ -1423,6 +1425,8 @@ describe('parseFeed', () => { title: 'Example Feed', link: 'https://example.com', dcterms: { + createds: ['2023-01-01T00:00:00Z'], + licenses: ['Creative Commons Attribution 4.0'], created: '2023-01-01T00:00:00Z', license: 'Creative Commons Attribution 4.0', }, diff --git a/src/feeds/rss/references/rss-ns.json b/src/feeds/rss/references/rss-ns.json index 17427235..f393f34e 100644 --- a/src/feeds/rss/references/rss-ns.json +++ b/src/feeds/rss/references/rss-ns.json @@ -27,10 +27,64 @@ "rights": "Copyright 2025 Example News Organization" }, "dcterms": { - "created": "2022-01-01T12:00:00.000Z", - "license": "Creative Commons Attribution 4.0", + "abstracts": ["This article explores advanced concepts in technology"], + "accessRights": ["Public access with attribution required"], + "accrualMethods": ["Single publication"], + "accrualPeriodicities": ["One-time"], + "accrualPolicies": ["Editorial review required"], + "alternatives": ["Alternative Item Title"], + "audiences": ["Technical professionals"], + "availables": ["2022-01-01T12:00:00.000Z"], + "bibliographicCitations": [ + "Smith, J. (2022). Example Item. Retrieved from https://example.org/item/1" + ], + "conformsTos": ["HTML5 standard"], + "contributors": ["Assistant Editor Mike Thompson"], + "coverages": ["United States technology sector"], + "createds": ["2022-01-01T12:00:00.000Z"], + "creators": ["Jack Jackson"], + "dates": ["2022-01-01T12:00:00.000Z"], + "dateAccepteds": ["2022-01-01T12:00:00.000Z"], + "dateCopyrighteds": ["2022-01-01T12:00:00.000Z"], + "dateSubmitteds": ["2022-01-01T12:00:00.000Z"], + "descriptions": ["Detailed description of the example item content and its significance"], + "educationLevels": ["Advanced"], + "extents": ["Approximately 2500 words"], + "formats": ["text/html"], + "hasFormats": ["https://example.org/item/1.pdf"], + "hasParts": ["https://example.org/item/1/section1"], + "hasVersions": ["1.1"], + "identifiers": ["urn:uuid:item-98765432-9876-9876-9876-987654321def"], + "instructionalMethods": ["Step-by-step tutorial"], + "isFormatOfs": ["https://example.org/item-source"], + "isPartOfs": ["Example Article Series"], + "isReferencedBys": ["https://example.org/item/1/citations"], + "isReplacedBys": ["https://example.org/item/1/updated"], + "isRequiredBys": ["https://example.org/item/1/prerequisites"], + "issueds": ["2022-01-01T12:00:00.000Z"], + "isVersionOfs": ["https://example.org/item/1/original"], + "languages": ["en-US"], + "licenses": ["Creative Commons Attribution 4.0"], + "mediators": ["Editorial Team"], + "mediums": ["Digital"], + "modifieds": ["2022-06-01T12:00:00.000Z"], + "provenances": ["Originally published by Example News Organization"], + "publishers": ["Example News Organization"], + "references": ["https://example.org/item/1/references"], + "relations": ["https://example.org/related-article"], + "replaces": ["https://example.org/item/1/previous"], + "requires": ["Basic understanding of web technologies"], + "rights": ["Copyright 2025 Example News Organization"], + "rightsHolders": ["Example News Organization"], + "sources": ["https://example.org/item-source"], + "spatials": ["United States"], + "subjects": ["Article, Tutorial, Example"], + "tableOfContents": ["Introduction, Main Content, Conclusion"], + "temporals": ["2022"], + "titles": ["Dublin Core Terms Enhanced Item Title"], + "types": ["Article"], + "valids": ["2025-12-31T23:59:59.000Z"], "abstract": "This article explores advanced concepts in technology", - "accessRights": "Public access with attribution required", "accrualMethod": "Single publication", "accrualPeriodicity": "One-time", "accrualPolicy": "Editorial review required", @@ -41,6 +95,7 @@ "conformsTo": "HTML5 standard", "contributor": "Assistant Editor Mike Thompson", "coverage": "United States technology sector", + "created": "2022-01-01T12:00:00.000Z", "creator": "Jack Jackson", "date": "2022-01-01T12:00:00.000Z", "dateAccepted": "2022-01-01T12:00:00.000Z", @@ -63,21 +118,17 @@ "issued": "2022-01-01T12:00:00.000Z", "isVersionOf": "https://example.org/item/1/original", "language": "en-US", + "license": "Creative Commons Attribution 4.0", "mediator": "Editorial Team", "medium": "Digital", "modified": "2022-06-01T12:00:00.000Z", "provenance": "Originally published by Example News Organization", "publisher": "Example News Organization", - "references": "https://example.org/item/1/references", "relation": "https://example.org/related-article", - "replaces": "https://example.org/item/1/previous", - "requires": "Basic understanding of web technologies", - "rights": "Copyright 2025 Example News Organization", "rightsHolder": "Example News Organization", "source": "https://example.org/item-source", "spatial": "United States", "subject": "Article, Tutorial, Example", - "tableOfContents": "Introduction, Main Content, Conclusion", "temporal": "2022", "title": "Dublin Core Terms Enhanced Item Title", "type": "Article", @@ -944,10 +995,62 @@ "rights": "Copyright 2025 Example Publishing Company" }, "dcterms": { - "created": "2022-01-01T12:00:00.000Z", - "license": "Creative Commons Attribution 4.0", + "abstracts": ["This is an abstract of the feed content"], + "accessRights": ["Public access with attribution required"], + "accrualMethods": ["Regular updates"], + "accrualPeriodicities": ["Daily"], + "accrualPolicies": ["Content added based on editorial calendar"], + "alternatives": ["Alternative Feed Title"], + "audiences": ["General technology audience"], + "availables": ["2022-01-01T12:00:00.000Z"], + "bibliographicCitations": ["Example Feed. (2022). Retrieved from https://example.org"], + "conformsTos": ["RSS 2.0 Specification"], + "contributors": ["Jane Smith"], + "coverages": ["Global technology topics"], + "createds": ["2022-01-01T12:00:00.000Z"], + "creators": ["John Doe"], + "dates": ["2022-01-01T12:00:00.000Z"], + "dateAccepteds": ["2022-01-01T12:00:00.000Z"], + "dateCopyrighteds": ["2022-01-01T12:00:00.000Z"], + "dateSubmitteds": ["2022-01-01T12:00:00.000Z"], + "descriptions": ["Detailed description of the feed content and purpose"], + "educationLevels": ["Intermediate to advanced"], + "extents": ["Approximately 1000 words per article"], + "formats": ["application/rss+xml"], + "hasFormats": ["https://example.org/feed.atom"], + "hasParts": ["https://example.org/category/tutorials"], + "hasVersions": ["2.0"], + "identifiers": ["urn:uuid:feed-12345678-1234-1234-1234-123456789abc"], + "instructionalMethods": ["Practical examples and tutorials"], + "isFormatOfs": ["https://example.org/original-content"], + "isPartOfs": ["Example Media Network"], + "isReferencedBys": ["https://example.org/references"], + "isReplacedBys": ["https://example.org/new-feed"], + "isRequiredBys": ["https://example.org/dependent-feeds"], + "issueds": ["2022-01-01T12:00:00.000Z"], + "isVersionOfs": ["https://example.org/original-feed"], + "languages": ["en-US"], + "licenses": ["Creative Commons Attribution 4.0"], + "mediators": ["Content Management System"], + "mediums": ["Digital"], + "modifieds": ["2023-01-01T12:00:00.000Z"], + "provenances": ["Originally created by Example Publishing Company"], + "publishers": ["Example Publishing Company"], + "references": ["https://example.org/referenced-sources"], + "relations": ["https://example.org/related-feeds"], + "replaces": ["https://example.org/old-feed"], + "requires": ["RSS 2.0 compatible reader"], + "rights": ["Copyright 2025 Example Publishing Company"], + "rightsHolders": ["Example Publishing Company"], + "sources": ["https://example.org/original-source"], + "spatials": ["Global"], + "subjects": ["Technology, Programming, Web Development"], + "tableOfContents": ["Latest articles, tutorials, and news"], + "temporals": ["2022-present"], + "titles": ["Dublin Core Terms Enhanced Feed Title"], + "types": ["Text"], + "valids": ["2025-12-31T23:59:59.000Z"], "abstract": "This is an abstract of the feed content", - "accessRights": "Public access with attribution required", "accrualMethod": "Regular updates", "accrualPeriodicity": "Daily", "accrualPolicy": "Content added based on editorial calendar", @@ -958,6 +1061,7 @@ "conformsTo": "RSS 2.0 Specification", "contributor": "Jane Smith", "coverage": "Global technology topics", + "created": "2022-01-01T12:00:00.000Z", "creator": "John Doe", "date": "2022-01-01T12:00:00.000Z", "dateAccepted": "2022-01-01T12:00:00.000Z", @@ -980,21 +1084,17 @@ "issued": "2022-01-01T12:00:00.000Z", "isVersionOf": "https://example.org/original-feed", "language": "en-US", + "license": "Creative Commons Attribution 4.0", "mediator": "Content Management System", "medium": "Digital", "modified": "2023-01-01T12:00:00.000Z", "provenance": "Originally created by Example Publishing Company", "publisher": "Example Publishing Company", - "references": "https://example.org/referenced-sources", "relation": "https://example.org/related-feeds", - "replaces": "https://example.org/old-feed", - "requires": "RSS 2.0 compatible reader", - "rights": "Copyright 2025 Example Publishing Company", "rightsHolder": "Example Publishing Company", "source": "https://example.org/original-source", "spatial": "Global", "subject": "Technology, Programming, Web Development", - "tableOfContents": "Latest articles, tutorials, and news", "temporal": "2022-present", "title": "Dublin Core Terms Enhanced Feed Title", "type": "Text", diff --git a/src/namespaces/dcterms/common/types.ts b/src/namespaces/dcterms/common/types.ts index 4e67215c..f0e8c049 100644 --- a/src/namespaces/dcterms/common/types.ts +++ b/src/namespaces/dcterms/common/types.ts @@ -3,60 +3,159 @@ import type { DateLike } from '../../../common/types.js' // #region reference export namespace DctermsNs { export type ItemOrFeed = { + abstracts?: Array + accessRights?: Array + accrualMethods?: Array + accrualPeriodicities?: Array + accrualPolicies?: Array + alternatives?: Array + audiences?: Array + availables?: Array + bibliographicCitations?: Array + conformsTos?: Array + contributors?: Array + coverages?: Array + createds?: Array + creators?: Array + dates?: Array + dateAccepteds?: Array + dateCopyrighteds?: Array + dateSubmitteds?: Array + descriptions?: Array + educationLevels?: Array + extents?: Array + formats?: Array + hasFormats?: Array + hasParts?: Array + hasVersions?: Array + identifiers?: Array + instructionalMethods?: Array + isFormatOfs?: Array + isPartOfs?: Array + isReferencedBys?: Array + isReplacedBys?: Array + isRequiredBys?: Array + issueds?: Array + isVersionOfs?: Array + languages?: Array + licenses?: Array + mediators?: Array + mediums?: Array + modifieds?: Array + provenances?: Array + publishers?: Array + references?: Array + relations?: Array + replaces?: Array + requires?: Array + rights?: Array + rightsHolders?: Array + sources?: Array + spatials?: Array + subjects?: Array + tableOfContents?: Array + temporals?: Array + titles?: Array + types?: Array + valids?: Array + + /** @deprecated Use `abstracts` (array) instead. Dublin Core Terms fields are repeatable. */ abstract?: string - accessRights?: string + /** @deprecated Use `accrualMethods` (array) instead. Dublin Core Terms fields are repeatable. */ accrualMethod?: string + /** @deprecated Use `accrualPeriodicities` (array) instead. Dublin Core Terms fields are repeatable. */ accrualPeriodicity?: string + /** @deprecated Use `accrualPolicies` (array) instead. Dublin Core Terms fields are repeatable. */ accrualPolicy?: string + /** @deprecated Use `alternatives` (array) instead. Dublin Core Terms fields are repeatable. */ alternative?: string + /** @deprecated Use `audiences` (array) instead. Dublin Core Terms fields are repeatable. */ audience?: string + /** @deprecated Use `availables` (array) instead. Dublin Core Terms fields are repeatable. */ available?: TDate + /** @deprecated Use `bibliographicCitations` (array) instead. Dublin Core Terms fields are repeatable. */ bibliographicCitation?: string + /** @deprecated Use `conformsTos` (array) instead. Dublin Core Terms fields are repeatable. */ conformsTo?: string + /** @deprecated Use `contributors` (array) instead. Dublin Core Terms fields are repeatable. */ contributor?: string + /** @deprecated Use `coverages` (array) instead. Dublin Core Terms fields are repeatable. */ coverage?: string + /** @deprecated Use `createds` (array) instead. Dublin Core Terms fields are repeatable. */ created?: TDate + /** @deprecated Use `creators` (array) instead. Dublin Core Terms fields are repeatable. */ creator?: string + /** @deprecated Use `dates` (array) instead. Dublin Core Terms fields are repeatable. */ date?: TDate + /** @deprecated Use `dateAccepteds` (array) instead. Dublin Core Terms fields are repeatable. */ dateAccepted?: TDate + /** @deprecated Use `dateCopyrighteds` (array) instead. Dublin Core Terms fields are repeatable. */ dateCopyrighted?: TDate + /** @deprecated Use `dateSubmitteds` (array) instead. Dublin Core Terms fields are repeatable. */ dateSubmitted?: TDate + /** @deprecated Use `descriptions` (array) instead. Dublin Core Terms fields are repeatable. */ description?: string + /** @deprecated Use `educationLevels` (array) instead. Dublin Core Terms fields are repeatable. */ educationLevel?: string + /** @deprecated Use `extents` (array) instead. Dublin Core Terms fields are repeatable. */ extent?: string + /** @deprecated Use `formats` (array) instead. Dublin Core Terms fields are repeatable. */ format?: string + /** @deprecated Use `hasFormats` (array) instead. Dublin Core Terms fields are repeatable. */ hasFormat?: string + /** @deprecated Use `hasParts` (array) instead. Dublin Core Terms fields are repeatable. */ hasPart?: string + /** @deprecated Use `hasVersions` (array) instead. Dublin Core Terms fields are repeatable. */ hasVersion?: string + /** @deprecated Use `identifiers` (array) instead. Dublin Core Terms fields are repeatable. */ identifier?: string + /** @deprecated Use `instructionalMethods` (array) instead. Dublin Core Terms fields are repeatable. */ instructionalMethod?: string + /** @deprecated Use `isFormatOfs` (array) instead. Dublin Core Terms fields are repeatable. */ isFormatOf?: string + /** @deprecated Use `isPartOfs` (array) instead. Dublin Core Terms fields are repeatable. */ isPartOf?: string + /** @deprecated Use `isReferencedBys` (array) instead. Dublin Core Terms fields are repeatable. */ isReferencedBy?: string + /** @deprecated Use `isReplacedBys` (array) instead. Dublin Core Terms fields are repeatable. */ isReplacedBy?: string + /** @deprecated Use `isRequiredBys` (array) instead. Dublin Core Terms fields are repeatable. */ isRequiredBy?: string + /** @deprecated Use `issueds` (array) instead. Dublin Core Terms fields are repeatable. */ issued?: TDate + /** @deprecated Use `isVersionOfs` (array) instead. Dublin Core Terms fields are repeatable. */ isVersionOf?: string + /** @deprecated Use `languages` (array) instead. Dublin Core Terms fields are repeatable. */ language?: string + /** @deprecated Use `licenses` (array) instead. Dublin Core Terms fields are repeatable. */ license?: string + /** @deprecated Use `mediators` (array) instead. Dublin Core Terms fields are repeatable. */ mediator?: string + /** @deprecated Use `mediums` (array) instead. Dublin Core Terms fields are repeatable. */ medium?: string + /** @deprecated Use `modifieds` (array) instead. Dublin Core Terms fields are repeatable. */ modified?: TDate + /** @deprecated Use `provenances` (array) instead. Dublin Core Terms fields are repeatable. */ provenance?: string + /** @deprecated Use `publishers` (array) instead. Dublin Core Terms fields are repeatable. */ publisher?: string - references?: string + /** @deprecated Use `relations` (array) instead. Dublin Core Terms fields are repeatable. */ relation?: string - replaces?: string - requires?: string - rights?: string + /** @deprecated Use `rightsHolders` (array) instead. Dublin Core Terms fields are repeatable. */ rightsHolder?: string + /** @deprecated Use `sources` (array) instead. Dublin Core Terms fields are repeatable. */ source?: string + /** @deprecated Use `spatials` (array) instead. Dublin Core Terms fields are repeatable. */ spatial?: string + /** @deprecated Use `subjects` (array) instead. Dublin Core Terms fields are repeatable. */ subject?: string - tableOfContents?: string + /** @deprecated Use `temporals` (array) instead. Dublin Core Terms fields are repeatable. */ temporal?: string + /** @deprecated Use `titles` (array) instead. Dublin Core Terms fields are repeatable. */ title?: string + /** @deprecated Use `types` (array) instead. Dublin Core Terms fields are repeatable. */ type?: string + /** @deprecated Use `valids` (array) instead. Dublin Core Terms fields are repeatable. */ valid?: TDate } } diff --git a/src/namespaces/dcterms/generate/utils.test.ts b/src/namespaces/dcterms/generate/utils.test.ts index 876a6c47..12378746 100644 --- a/src/namespaces/dcterms/generate/utils.test.ts +++ b/src/namespaces/dcterms/generate/utils.test.ts @@ -2,10 +2,9 @@ import { describe, expect, it } from 'bun:test' import { generateItemOrFeed } from './utils.js' describe('generateItemOrFeed', () => { - it('should generate valid itemOrFeed object with all properties', () => { + it('should generate valid itemOrFeed object with all singular (deprecated) properties', () => { const value = { abstract: 'Sample abstract content', - accessRights: 'Open Access', accrualMethod: 'Manual upload', accrualPeriodicity: 'Annual', accrualPolicy: 'Open submission', @@ -45,16 +44,11 @@ describe('generateItemOrFeed', () => { modified: new Date('2023-05-25T16:45:00Z'), provenance: 'Digitized from original manuscript', publisher: 'Academic Press', - references: 'https://example.org/ref/source1', relation: 'https://example.org/related', - replaces: 'https://example.org/old-version', - requires: 'https://example.org/prerequisite', - rights: 'Copyright 2023', rightsHolder: 'Example University', source: 'https://example.org/source', spatial: 'Boston, MA, USA', subject: 'Academic Research', - tableOfContents: 'Chapter 1, Chapter 2, Chapter 3', temporal: '2023', title: 'Sample Title', type: 'Text', @@ -62,7 +56,6 @@ describe('generateItemOrFeed', () => { } const expected = { 'dcterms:abstract': 'Sample abstract content', - 'dcterms:accessRights': 'Open Access', 'dcterms:accrualMethod': 'Manual upload', 'dcterms:accrualPeriodicity': 'Annual', 'dcterms:accrualPolicy': 'Open submission', @@ -102,16 +95,11 @@ describe('generateItemOrFeed', () => { 'dcterms:modified': '2023-05-25T16:45:00.000Z', 'dcterms:provenance': 'Digitized from original manuscript', 'dcterms:publisher': 'Academic Press', - 'dcterms:references': 'https://example.org/ref/source1', 'dcterms:relation': 'https://example.org/related', - 'dcterms:replaces': 'https://example.org/old-version', - 'dcterms:requires': 'https://example.org/prerequisite', - 'dcterms:rights': 'Copyright 2023', 'dcterms:rightsHolder': 'Example University', 'dcterms:source': 'https://example.org/source', 'dcterms:spatial': 'Boston, MA, USA', 'dcterms:subject': 'Academic Research', - 'dcterms:tableOfContents': 'Chapter 1, Chapter 2, Chapter 3', 'dcterms:temporal': '2023', 'dcterms:title': 'Sample Title', 'dcterms:type': 'Text', @@ -121,6 +109,194 @@ describe('generateItemOrFeed', () => { expect(generateItemOrFeed(value)).toEqual(expected) }) + it('should generate valid itemOrFeed object with all plural properties (single values)', () => { + const value = { + abstracts: ['Sample abstract content'], + accessRights: ['Open Access'], + accrualMethods: ['Manual upload'], + accrualPeriodicities: ['Annual'], + accrualPolicies: ['Open submission'], + alternatives: ['Alternative Title'], + audiences: ['General Public'], + availables: [new Date('2023-06-01T00:00:00Z')], + bibliographicCitations: ['Doe, J. (2023). Sample Work. Publisher.'], + conformsTos: ['Dublin Core Metadata Terms'], + contributors: ['Jane Smith'], + coverages: ['Global'], + createds: [new Date('2023-05-01T12:00:00Z')], + creators: ['John Doe'], + dates: [new Date('2023-05-02T08:30:00Z')], + dateAccepteds: [new Date('2023-05-10T09:00:00Z')], + dateCopyrighteds: [new Date('2023-05-15T00:00:00Z')], + dateSubmitteds: [new Date('2023-05-05T14:30:00Z')], + descriptions: ['A comprehensive description'], + educationLevels: ['Graduate level'], + extents: ['250 pages'], + formats: ['application/pdf'], + hasFormats: ['https://example.org/formats/pdf'], + hasParts: ['https://example.org/parts/chapter1'], + hasVersions: ['https://example.org/versions/v2'], + identifiers: ['ISBN:978-0123456789'], + instructionalMethods: ['Online learning'], + isFormatOfs: ['https://example.org/original'], + isPartOfs: ['https://example.org/collection'], + isReferencedBys: ['https://example.org/references/citation1'], + isReplacedBys: ['https://example.org/replacement'], + isRequiredBys: ['https://example.org/dependent'], + issueds: [new Date('2023-05-20T10:00:00Z')], + isVersionOfs: ['https://example.org/original-work'], + languages: ['en-US'], + licenses: ['Creative Commons Attribution 4.0'], + mediators: ['Library System'], + mediums: ['Digital'], + modifieds: [new Date('2023-05-25T16:45:00Z')], + provenances: ['Digitized from original manuscript'], + publishers: ['Academic Press'], + references: ['https://example.org/ref/source1'], + relations: ['https://example.org/related'], + replaces: ['https://example.org/old-version'], + requires: ['https://example.org/prerequisite'], + rights: ['Copyright 2023'], + rightsHolders: ['Example University'], + sources: ['https://example.org/source'], + spatials: ['Boston, MA, USA'], + subjects: ['Academic Research'], + tableOfContents: ['Chapter 1, Chapter 2, Chapter 3'], + temporals: ['2023'], + titles: ['Sample Title'], + types: ['Text'], + valids: [new Date('2024-05-25T23:59:59Z')], + } + const expected = { + 'dcterms:abstract': ['Sample abstract content'], + 'dcterms:accessRights': ['Open Access'], + 'dcterms:accrualMethod': ['Manual upload'], + 'dcterms:accrualPeriodicity': ['Annual'], + 'dcterms:accrualPolicy': ['Open submission'], + 'dcterms:alternative': ['Alternative Title'], + 'dcterms:audience': ['General Public'], + 'dcterms:available': ['2023-06-01T00:00:00.000Z'], + 'dcterms:bibliographicCitation': ['Doe, J. (2023). Sample Work. Publisher.'], + 'dcterms:conformsTo': ['Dublin Core Metadata Terms'], + 'dcterms:contributor': ['Jane Smith'], + 'dcterms:coverage': ['Global'], + 'dcterms:created': ['2023-05-01T12:00:00.000Z'], + 'dcterms:creator': ['John Doe'], + 'dcterms:date': ['2023-05-02T08:30:00.000Z'], + 'dcterms:dateAccepted': ['2023-05-10T09:00:00.000Z'], + 'dcterms:dateCopyrighted': ['2023-05-15T00:00:00.000Z'], + 'dcterms:dateSubmitted': ['2023-05-05T14:30:00.000Z'], + 'dcterms:description': ['A comprehensive description'], + 'dcterms:educationLevel': ['Graduate level'], + 'dcterms:extent': ['250 pages'], + 'dcterms:format': ['application/pdf'], + 'dcterms:hasFormat': ['https://example.org/formats/pdf'], + 'dcterms:hasPart': ['https://example.org/parts/chapter1'], + 'dcterms:hasVersion': ['https://example.org/versions/v2'], + 'dcterms:identifier': ['ISBN:978-0123456789'], + 'dcterms:instructionalMethod': ['Online learning'], + 'dcterms:isFormatOf': ['https://example.org/original'], + 'dcterms:isPartOf': ['https://example.org/collection'], + 'dcterms:isReferencedBy': ['https://example.org/references/citation1'], + 'dcterms:isReplacedBy': ['https://example.org/replacement'], + 'dcterms:isRequiredBy': ['https://example.org/dependent'], + 'dcterms:issued': ['2023-05-20T10:00:00.000Z'], + 'dcterms:isVersionOf': ['https://example.org/original-work'], + 'dcterms:language': ['en-US'], + 'dcterms:license': ['Creative Commons Attribution 4.0'], + 'dcterms:mediator': ['Library System'], + 'dcterms:medium': ['Digital'], + 'dcterms:modified': ['2023-05-25T16:45:00.000Z'], + 'dcterms:provenance': ['Digitized from original manuscript'], + 'dcterms:publisher': ['Academic Press'], + 'dcterms:references': ['https://example.org/ref/source1'], + 'dcterms:relation': ['https://example.org/related'], + 'dcterms:replaces': ['https://example.org/old-version'], + 'dcterms:requires': ['https://example.org/prerequisite'], + 'dcterms:rights': ['Copyright 2023'], + 'dcterms:rightsHolder': ['Example University'], + 'dcterms:source': ['https://example.org/source'], + 'dcterms:spatial': ['Boston, MA, USA'], + 'dcterms:subject': ['Academic Research'], + 'dcterms:tableOfContents': ['Chapter 1, Chapter 2, Chapter 3'], + 'dcterms:temporal': ['2023'], + 'dcterms:title': ['Sample Title'], + 'dcterms:type': ['Text'], + 'dcterms:valid': ['2024-05-25T23:59:59.000Z'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + + it('should generate valid itemOrFeed object with plural properties (multiple values)', () => { + const value = { + abstracts: ['Sample abstract content', 'Another abstract'], + accessRights: ['Open Access', 'Restricted Access'], + titles: ['Sample Title', 'Alternative Title'], + creators: ['John Doe', 'Jane Doe'], + subjects: ['Academic Research', 'Scientific Study'], + descriptions: ['First description', 'Second description'], + publishers: ['Academic Press', 'University Press'], + contributors: ['Alice', 'Bob'], + dates: [new Date('2023-01-01T00:00:00Z'), new Date('2023-06-15T12:00:00Z')], + types: ['Text', 'Dataset'], + formats: ['application/pdf', 'text/html'], + identifiers: ['ISBN:978-0123456789', 'DOI:10.1234/example'], + sources: ['https://example.org/source1', 'https://example.org/source2'], + languages: ['en-US', 'en-GB'], + relations: ['https://example.org/related1', 'https://example.org/related2'], + coverages: ['Global', 'North America'], + rights: ['Copyright 2023', 'CC BY-NC-SA 4.0'], + references: ['https://example.org/ref1', 'https://example.org/ref2'], + replaces: ['https://example.org/old1', 'https://example.org/old2'], + requires: ['https://example.org/dep1', 'https://example.org/dep2'], + tableOfContents: ['Chapter 1, Chapter 2', 'Section 1, Section 2'], + } + const expected = { + 'dcterms:abstract': ['Sample abstract content', 'Another abstract'], + 'dcterms:accessRights': ['Open Access', 'Restricted Access'], + 'dcterms:title': ['Sample Title', 'Alternative Title'], + 'dcterms:creator': ['John Doe', 'Jane Doe'], + 'dcterms:subject': ['Academic Research', 'Scientific Study'], + 'dcterms:description': ['First description', 'Second description'], + 'dcterms:publisher': ['Academic Press', 'University Press'], + 'dcterms:contributor': ['Alice', 'Bob'], + 'dcterms:date': ['2023-01-01T00:00:00.000Z', '2023-06-15T12:00:00.000Z'], + 'dcterms:type': ['Text', 'Dataset'], + 'dcterms:format': ['application/pdf', 'text/html'], + 'dcterms:identifier': ['ISBN:978-0123456789', 'DOI:10.1234/example'], + 'dcterms:source': ['https://example.org/source1', 'https://example.org/source2'], + 'dcterms:language': ['en-US', 'en-GB'], + 'dcterms:relation': ['https://example.org/related1', 'https://example.org/related2'], + 'dcterms:coverage': ['Global', 'North America'], + 'dcterms:rights': ['Copyright 2023', 'CC BY-NC-SA 4.0'], + 'dcterms:references': ['https://example.org/ref1', 'https://example.org/ref2'], + 'dcterms:replaces': ['https://example.org/old1', 'https://example.org/old2'], + 'dcterms:requires': ['https://example.org/dep1', 'https://example.org/dep2'], + 'dcterms:tableOfContents': ['Chapter 1, Chapter 2', 'Section 1, Section 2'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + + it('should prefer plural fields over singular when both are provided', () => { + const value = { + title: 'Singular Title', + titles: ['Plural Title 1', 'Plural Title 2'], + creator: 'Singular Creator', + creators: ['Plural Creator'], + abstract: 'Singular Abstract', + abstracts: ['Plural Abstract 1', 'Plural Abstract 2'], + } + const expected = { + 'dcterms:title': ['Plural Title 1', 'Plural Title 2'], + 'dcterms:creator': ['Plural Creator'], + 'dcterms:abstract': ['Plural Abstract 1', 'Plural Abstract 2'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + it('should generate itemOrFeed with minimal properties', () => { const value = { title: 'Minimal Title', @@ -135,65 +311,29 @@ describe('generateItemOrFeed', () => { it('should handle object with only undefined/empty properties', () => { const value = { abstract: undefined, - accessRights: undefined, - accrualMethod: undefined, - accrualPeriodicity: undefined, - accrualPolicy: undefined, - alternative: undefined, - audience: undefined, - available: undefined, - bibliographicCitation: undefined, - conformsTo: undefined, - contributor: undefined, - coverage: undefined, - created: undefined, + title: undefined, creator: undefined, - date: undefined, - dateAccepted: undefined, - dateCopyrighted: undefined, - dateSubmitted: undefined, - description: undefined, - educationLevel: undefined, - extent: undefined, - format: undefined, - hasFormat: undefined, - hasPart: undefined, - hasVersion: undefined, - identifier: undefined, - instructionalMethod: undefined, - isFormatOf: undefined, - isPartOf: undefined, - isReferencedBy: undefined, - isReplacedBy: undefined, - isRequiredBy: undefined, - issued: undefined, - isVersionOf: undefined, - language: undefined, - license: undefined, - mediator: undefined, - medium: undefined, - modified: undefined, - provenance: undefined, - publisher: undefined, - references: undefined, - relation: undefined, - replaces: undefined, - requires: undefined, - rights: undefined, - rightsHolder: undefined, - source: undefined, - spatial: undefined, subject: undefined, - tableOfContents: undefined, - temporal: undefined, - title: undefined, - type: undefined, - valid: undefined, } expect(generateItemOrFeed(value)).toBeUndefined() }) + it('should handle empty arrays in plural fields', () => { + const value = { + titles: [], + creators: ['John Doe'], + subjects: [], + abstracts: ['Sample abstract'], + } + const expected = { + 'dcterms:creator': ['John Doe'], + 'dcterms:abstract': ['Sample abstract'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + it('should handle empty object', () => { const value = {} diff --git a/src/namespaces/dcterms/generate/utils.ts b/src/namespaces/dcterms/generate/utils.ts index 0248e470..1bddc99c 100644 --- a/src/namespaces/dcterms/generate/utils.ts +++ b/src/namespaces/dcterms/generate/utils.ts @@ -3,6 +3,8 @@ import { generateCdataString, generateRfc3339Date, isObject, + isPresent, + trimArray, trimObject, } from '../../../common/utils.js' import type { DctermsNs } from '../common/types.js' @@ -12,62 +14,217 @@ export const generateItemOrFeed: GenerateUtil> = return } + // TODO: Remove this once deprecated singular fields are removed in next major version. + const generateArray = ( + pluralValues: Array | undefined, + singularValue: V | undefined, + generator: (value: V) => unknown, + ) => { + if (isPresent(pluralValues)) { + return trimArray(pluralValues.map(generator)) + } + + if (isPresent(singularValue)) { + return generator(singularValue) + } + } + const value = { - 'dcterms:abstract': generateCdataString(itemOrFeed.abstract), - 'dcterms:accessRights': generateCdataString(itemOrFeed.accessRights), - 'dcterms:accrualMethod': generateCdataString(itemOrFeed.accrualMethod), - 'dcterms:accrualPeriodicity': generateCdataString(itemOrFeed.accrualPeriodicity), - 'dcterms:accrualPolicy': generateCdataString(itemOrFeed.accrualPolicy), - 'dcterms:alternative': generateCdataString(itemOrFeed.alternative), - 'dcterms:audience': generateCdataString(itemOrFeed.audience), - 'dcterms:available': generateRfc3339Date(itemOrFeed.available), - 'dcterms:bibliographicCitation': generateCdataString(itemOrFeed.bibliographicCitation), - 'dcterms:conformsTo': generateCdataString(itemOrFeed.conformsTo), - 'dcterms:contributor': generateCdataString(itemOrFeed.contributor), - 'dcterms:coverage': generateCdataString(itemOrFeed.coverage), - 'dcterms:created': generateRfc3339Date(itemOrFeed.created), - 'dcterms:creator': generateCdataString(itemOrFeed.creator), - 'dcterms:date': generateRfc3339Date(itemOrFeed.date), - 'dcterms:dateAccepted': generateRfc3339Date(itemOrFeed.dateAccepted), - 'dcterms:dateCopyrighted': generateRfc3339Date(itemOrFeed.dateCopyrighted), - 'dcterms:dateSubmitted': generateRfc3339Date(itemOrFeed.dateSubmitted), - 'dcterms:description': generateCdataString(itemOrFeed.description), - 'dcterms:educationLevel': generateCdataString(itemOrFeed.educationLevel), - 'dcterms:extent': generateCdataString(itemOrFeed.extent), - 'dcterms:format': generateCdataString(itemOrFeed.format), - 'dcterms:hasFormat': generateCdataString(itemOrFeed.hasFormat), - 'dcterms:hasPart': generateCdataString(itemOrFeed.hasPart), - 'dcterms:hasVersion': generateCdataString(itemOrFeed.hasVersion), - 'dcterms:identifier': generateCdataString(itemOrFeed.identifier), - 'dcterms:instructionalMethod': generateCdataString(itemOrFeed.instructionalMethod), - 'dcterms:isFormatOf': generateCdataString(itemOrFeed.isFormatOf), - 'dcterms:isPartOf': generateCdataString(itemOrFeed.isPartOf), - 'dcterms:isReferencedBy': generateCdataString(itemOrFeed.isReferencedBy), - 'dcterms:isReplacedBy': generateCdataString(itemOrFeed.isReplacedBy), - 'dcterms:isRequiredBy': generateCdataString(itemOrFeed.isRequiredBy), - 'dcterms:issued': generateRfc3339Date(itemOrFeed.issued), - 'dcterms:isVersionOf': generateCdataString(itemOrFeed.isVersionOf), - 'dcterms:language': generateCdataString(itemOrFeed.language), - 'dcterms:license': generateCdataString(itemOrFeed.license), - 'dcterms:mediator': generateCdataString(itemOrFeed.mediator), - 'dcterms:medium': generateCdataString(itemOrFeed.medium), - 'dcterms:modified': generateRfc3339Date(itemOrFeed.modified), - 'dcterms:provenance': generateCdataString(itemOrFeed.provenance), - 'dcterms:publisher': generateCdataString(itemOrFeed.publisher), - 'dcterms:references': generateCdataString(itemOrFeed.references), - 'dcterms:relation': generateCdataString(itemOrFeed.relation), - 'dcterms:replaces': generateCdataString(itemOrFeed.replaces), - 'dcterms:requires': generateCdataString(itemOrFeed.requires), - 'dcterms:rights': generateCdataString(itemOrFeed.rights), - 'dcterms:rightsHolder': generateCdataString(itemOrFeed.rightsHolder), - 'dcterms:source': generateCdataString(itemOrFeed.source), - 'dcterms:spatial': generateCdataString(itemOrFeed.spatial), - 'dcterms:subject': generateCdataString(itemOrFeed.subject), - 'dcterms:tableOfContents': generateCdataString(itemOrFeed.tableOfContents), - 'dcterms:temporal': generateCdataString(itemOrFeed.temporal), - 'dcterms:title': generateCdataString(itemOrFeed.title), - 'dcterms:type': generateCdataString(itemOrFeed.type), - 'dcterms:valid': generateRfc3339Date(itemOrFeed.valid), + 'dcterms:abstract': generateArray( + itemOrFeed.abstracts, + itemOrFeed.abstract, + generateCdataString, + ), + 'dcterms:accessRights': generateArray(itemOrFeed.accessRights, undefined, generateCdataString), + 'dcterms:accrualMethod': generateArray( + itemOrFeed.accrualMethods, + itemOrFeed.accrualMethod, + generateCdataString, + ), + 'dcterms:accrualPeriodicity': generateArray( + itemOrFeed.accrualPeriodicities, + itemOrFeed.accrualPeriodicity, + generateCdataString, + ), + 'dcterms:accrualPolicy': generateArray( + itemOrFeed.accrualPolicies, + itemOrFeed.accrualPolicy, + generateCdataString, + ), + 'dcterms:alternative': generateArray( + itemOrFeed.alternatives, + itemOrFeed.alternative, + generateCdataString, + ), + 'dcterms:audience': generateArray( + itemOrFeed.audiences, + itemOrFeed.audience, + generateCdataString, + ), + 'dcterms:available': generateArray( + itemOrFeed.availables, + itemOrFeed.available, + generateRfc3339Date, + ), + 'dcterms:bibliographicCitation': generateArray( + itemOrFeed.bibliographicCitations, + itemOrFeed.bibliographicCitation, + generateCdataString, + ), + 'dcterms:conformsTo': generateArray( + itemOrFeed.conformsTos, + itemOrFeed.conformsTo, + generateCdataString, + ), + 'dcterms:contributor': generateArray( + itemOrFeed.contributors, + itemOrFeed.contributor, + generateCdataString, + ), + 'dcterms:coverage': generateArray( + itemOrFeed.coverages, + itemOrFeed.coverage, + generateCdataString, + ), + 'dcterms:created': generateArray(itemOrFeed.createds, itemOrFeed.created, generateRfc3339Date), + 'dcterms:creator': generateArray(itemOrFeed.creators, itemOrFeed.creator, generateCdataString), + 'dcterms:date': generateArray(itemOrFeed.dates, itemOrFeed.date, generateRfc3339Date), + 'dcterms:dateAccepted': generateArray( + itemOrFeed.dateAccepteds, + itemOrFeed.dateAccepted, + generateRfc3339Date, + ), + 'dcterms:dateCopyrighted': generateArray( + itemOrFeed.dateCopyrighteds, + itemOrFeed.dateCopyrighted, + generateRfc3339Date, + ), + 'dcterms:dateSubmitted': generateArray( + itemOrFeed.dateSubmitteds, + itemOrFeed.dateSubmitted, + generateRfc3339Date, + ), + 'dcterms:description': generateArray( + itemOrFeed.descriptions, + itemOrFeed.description, + generateCdataString, + ), + 'dcterms:educationLevel': generateArray( + itemOrFeed.educationLevels, + itemOrFeed.educationLevel, + generateCdataString, + ), + 'dcterms:extent': generateArray(itemOrFeed.extents, itemOrFeed.extent, generateCdataString), + 'dcterms:format': generateArray(itemOrFeed.formats, itemOrFeed.format, generateCdataString), + 'dcterms:hasFormat': generateArray( + itemOrFeed.hasFormats, + itemOrFeed.hasFormat, + generateCdataString, + ), + 'dcterms:hasPart': generateArray(itemOrFeed.hasParts, itemOrFeed.hasPart, generateCdataString), + 'dcterms:hasVersion': generateArray( + itemOrFeed.hasVersions, + itemOrFeed.hasVersion, + generateCdataString, + ), + 'dcterms:identifier': generateArray( + itemOrFeed.identifiers, + itemOrFeed.identifier, + generateCdataString, + ), + 'dcterms:instructionalMethod': generateArray( + itemOrFeed.instructionalMethods, + itemOrFeed.instructionalMethod, + generateCdataString, + ), + 'dcterms:isFormatOf': generateArray( + itemOrFeed.isFormatOfs, + itemOrFeed.isFormatOf, + generateCdataString, + ), + 'dcterms:isPartOf': generateArray( + itemOrFeed.isPartOfs, + itemOrFeed.isPartOf, + generateCdataString, + ), + 'dcterms:isReferencedBy': generateArray( + itemOrFeed.isReferencedBys, + itemOrFeed.isReferencedBy, + generateCdataString, + ), + 'dcterms:isReplacedBy': generateArray( + itemOrFeed.isReplacedBys, + itemOrFeed.isReplacedBy, + generateCdataString, + ), + 'dcterms:isRequiredBy': generateArray( + itemOrFeed.isRequiredBys, + itemOrFeed.isRequiredBy, + generateCdataString, + ), + 'dcterms:issued': generateArray(itemOrFeed.issueds, itemOrFeed.issued, generateRfc3339Date), + 'dcterms:isVersionOf': generateArray( + itemOrFeed.isVersionOfs, + itemOrFeed.isVersionOf, + generateCdataString, + ), + 'dcterms:language': generateArray( + itemOrFeed.languages, + itemOrFeed.language, + generateCdataString, + ), + 'dcterms:license': generateArray(itemOrFeed.licenses, itemOrFeed.license, generateCdataString), + 'dcterms:mediator': generateArray( + itemOrFeed.mediators, + itemOrFeed.mediator, + generateCdataString, + ), + 'dcterms:medium': generateArray(itemOrFeed.mediums, itemOrFeed.medium, generateCdataString), + 'dcterms:modified': generateArray( + itemOrFeed.modifieds, + itemOrFeed.modified, + generateRfc3339Date, + ), + 'dcterms:provenance': generateArray( + itemOrFeed.provenances, + itemOrFeed.provenance, + generateCdataString, + ), + 'dcterms:publisher': generateArray( + itemOrFeed.publishers, + itemOrFeed.publisher, + generateCdataString, + ), + 'dcterms:references': generateArray(itemOrFeed.references, undefined, generateCdataString), + 'dcterms:relation': generateArray( + itemOrFeed.relations, + itemOrFeed.relation, + generateCdataString, + ), + 'dcterms:replaces': generateArray(itemOrFeed.replaces, undefined, generateCdataString), + 'dcterms:requires': generateArray(itemOrFeed.requires, undefined, generateCdataString), + 'dcterms:rights': generateArray(itemOrFeed.rights, undefined, generateCdataString), + 'dcterms:rightsHolder': generateArray( + itemOrFeed.rightsHolders, + itemOrFeed.rightsHolder, + generateCdataString, + ), + 'dcterms:source': generateArray(itemOrFeed.sources, itemOrFeed.source, generateCdataString), + 'dcterms:spatial': generateArray(itemOrFeed.spatials, itemOrFeed.spatial, generateCdataString), + 'dcterms:subject': generateArray(itemOrFeed.subjects, itemOrFeed.subject, generateCdataString), + 'dcterms:tableOfContents': generateArray( + itemOrFeed.tableOfContents, + undefined, + generateCdataString, + ), + 'dcterms:temporal': generateArray( + itemOrFeed.temporals, + itemOrFeed.temporal, + generateCdataString, + ), + 'dcterms:title': generateArray(itemOrFeed.titles, itemOrFeed.title, generateCdataString), + 'dcterms:type': generateArray(itemOrFeed.types, itemOrFeed.type, generateCdataString), + 'dcterms:valid': generateArray(itemOrFeed.valids, itemOrFeed.valid, generateRfc3339Date), } return trimObject(value) diff --git a/src/namespaces/dcterms/parse/utils.test.ts b/src/namespaces/dcterms/parse/utils.test.ts index f8c5e66f..0d8451f7 100644 --- a/src/namespaces/dcterms/parse/utils.test.ts +++ b/src/namespaces/dcterms/parse/utils.test.ts @@ -4,7 +4,6 @@ import { retrieveItemOrFeed } from './utils.js' describe('retrieveItemOrFeed', () => { const expectedFull = { abstract: 'Sample abstract content', - accessRights: 'Open Access', accrualMethod: 'Manual upload', accrualPeriodicity: 'Annual', accrualPolicy: 'Open submission', @@ -44,20 +43,70 @@ describe('retrieveItemOrFeed', () => { modified: '2023-05-25T16:45:00Z', provenance: 'Digitized from original manuscript', publisher: 'Academic Press', - references: 'https://example.org/ref/source1', relation: 'https://example.org/related', - replaces: 'https://example.org/old-version', - requires: 'https://example.org/prerequisite', - rights: 'Copyright 2023', rightsHolder: 'Example University', source: 'https://example.org/source', spatial: 'Boston, MA, USA', subject: 'Academic Research', - tableOfContents: 'Chapter 1, Chapter 2, Chapter 3', temporal: '2023', title: 'Sample Title', type: 'Text', valid: '2024-05-25T23:59:59Z', + abstracts: ['Sample abstract content'], + accessRights: ['Open Access'], + accrualMethods: ['Manual upload'], + accrualPeriodicities: ['Annual'], + accrualPolicies: ['Open submission'], + alternatives: ['Alternative Title'], + audiences: ['General Public'], + availables: ['2023-06-01T00:00:00Z'], + bibliographicCitations: ['Doe, J. (2023). Sample Work. Publisher.'], + conformsTos: ['Dublin Core Metadata Terms'], + contributors: ['Jane Smith'], + coverages: ['Global'], + createds: ['2023-05-01T12:00:00Z'], + creators: ['John Doe'], + dates: ['2023-05-02T08:30:00Z'], + dateAccepteds: ['2023-05-10T09:00:00Z'], + dateCopyrighteds: ['2023-05-15T00:00:00Z'], + dateSubmitteds: ['2023-05-05T14:30:00Z'], + descriptions: ['A comprehensive description'], + educationLevels: ['Graduate level'], + extents: ['250 pages'], + formats: ['application/pdf'], + hasFormats: ['https://example.org/formats/pdf'], + hasParts: ['https://example.org/parts/chapter1'], + hasVersions: ['https://example.org/versions/v2'], + identifiers: ['ISBN:978-0123456789'], + instructionalMethods: ['Online learning'], + isFormatOfs: ['https://example.org/original'], + isPartOfs: ['https://example.org/collection'], + isReferencedBys: ['https://example.org/references/citation1'], + isReplacedBys: ['https://example.org/replacement'], + isRequiredBys: ['https://example.org/dependent'], + issueds: ['2023-05-20T10:00:00Z'], + isVersionOfs: ['https://example.org/original-work'], + languages: ['en-US'], + licenses: ['Creative Commons Attribution 4.0'], + mediators: ['Library System'], + mediums: ['Digital'], + modifieds: ['2023-05-25T16:45:00Z'], + provenances: ['Digitized from original manuscript'], + publishers: ['Academic Press'], + references: ['https://example.org/ref/source1'], + relations: ['https://example.org/related'], + replaces: ['https://example.org/old-version'], + requires: ['https://example.org/prerequisite'], + rights: ['Copyright 2023'], + rightsHolders: ['Example University'], + sources: ['https://example.org/source'], + spatials: ['Boston, MA, USA'], + subjects: ['Academic Research'], + tableOfContents: ['Chapter 1, Chapter 2, Chapter 3'], + temporals: ['2023'], + titles: ['Sample Title'], + types: ['Text'], + valids: ['2024-05-25T23:59:59Z'], } it('should parse complete item or feed object with all properties (with #text)', () => { @@ -263,8 +312,120 @@ describe('retrieveItemOrFeed', () => { 'dcterms:type': ['Text', 'Dataset'], 'dcterms:valid': ['2024-05-25T23:59:59Z', '2025-05-25T23:59:59Z'], } + const expectedWithArrays = { + abstracts: ['Sample abstract content', 'Another abstract'], + accessRights: ['Open Access', 'Restricted Access'], + accrualMethods: ['Manual upload', 'Automatic harvest'], + accrualPeriodicities: ['Annual', 'Monthly'], + accrualPolicies: ['Open submission', 'Moderated submission'], + alternatives: ['Alternative Title', 'Secondary Title'], + audiences: ['General Public', 'Researchers'], + availables: ['2023-06-01T00:00:00Z', '2023-07-01T00:00:00Z'], + bibliographicCitations: [ + 'Doe, J. (2023). Sample Work. Publisher.', + 'Smith, J. (2023). Another Work.', + ], + conformsTos: ['Dublin Core Metadata Terms', 'ISO Standard'], + contributors: ['Jane Smith', 'Bob Johnson'], + coverages: ['Global', 'Europe'], + createds: ['2023-05-01T12:00:00Z', '2023-05-02T12:00:00Z'], + creators: ['John Doe', 'Jane Doe'], + dates: ['2023-05-02T08:30:00Z', '2023-05-03T08:30:00Z'], + dateAccepteds: ['2023-05-10T09:00:00Z', '2023-05-11T09:00:00Z'], + dateCopyrighteds: ['2023-05-15T00:00:00Z', '2023-05-16T00:00:00Z'], + dateSubmitteds: ['2023-05-05T14:30:00Z', '2023-05-06T14:30:00Z'], + descriptions: ['A comprehensive description', 'Another description'], + educationLevels: ['Graduate level', 'Undergraduate level'], + extents: ['250 pages', '300 pages'], + formats: ['application/pdf', 'text/html'], + hasFormats: ['https://example.org/formats/pdf', 'https://example.org/formats/html'], + hasParts: ['https://example.org/parts/chapter1', 'https://example.org/parts/chapter2'], + hasVersions: ['https://example.org/versions/v2', 'https://example.org/versions/v3'], + identifiers: ['ISBN:978-0123456789', 'DOI:10.1234/example'], + instructionalMethods: ['Online learning', 'In-person learning'], + isFormatOfs: ['https://example.org/original', 'https://example.org/another-original'], + isPartOfs: ['https://example.org/collection', 'https://example.org/series'], + isReferencedBys: [ + 'https://example.org/references/citation1', + 'https://example.org/references/citation2', + ], + isReplacedBys: ['https://example.org/replacement', 'https://example.org/new-replacement'], + isRequiredBys: ['https://example.org/dependent', 'https://example.org/another-dependent'], + issueds: ['2023-05-20T10:00:00Z', '2023-05-21T10:00:00Z'], + isVersionOfs: ['https://example.org/original-work', 'https://example.org/base-work'], + languages: ['en-US', 'en-GB'], + licenses: ['Creative Commons Attribution 4.0', 'MIT License'], + mediators: ['Library System', 'Archive System'], + mediums: ['Digital', 'Print'], + modifieds: ['2023-05-25T16:45:00Z', '2023-05-26T16:45:00Z'], + provenances: ['Digitized from original manuscript', 'Scanned from print'], + publishers: ['Academic Press', 'University Press'], + references: ['https://example.org/ref/source1', 'https://example.org/ref/source2'], + relations: ['https://example.org/related', 'https://example.org/also-related'], + replaces: ['https://example.org/old-version', 'https://example.org/deprecated-version'], + requires: ['https://example.org/prerequisite', 'https://example.org/dependency'], + rights: ['Copyright 2023', 'All rights reserved'], + rightsHolders: ['Example University', 'Example Foundation'], + sources: ['https://example.org/source', 'https://example.org/origin'], + spatials: ['Boston, MA, USA', 'Cambridge, MA, USA'], + subjects: ['Academic Research', 'Scientific Study'], + tableOfContents: ['Chapter 1, Chapter 2, Chapter 3', 'Section 1, Section 2'], + temporals: ['2023', '2022-2023'], + titles: ['Sample Title', 'Alternative Sample Title'], + types: ['Text', 'Dataset'], + valids: ['2024-05-25T23:59:59Z', '2025-05-25T23:59:59Z'], + abstract: 'Sample abstract content', + accrualMethod: 'Manual upload', + accrualPeriodicity: 'Annual', + accrualPolicy: 'Open submission', + alternative: 'Alternative Title', + audience: 'General Public', + available: '2023-06-01T00:00:00Z', + bibliographicCitation: 'Doe, J. (2023). Sample Work. Publisher.', + conformsTo: 'Dublin Core Metadata Terms', + contributor: 'Jane Smith', + coverage: 'Global', + created: '2023-05-01T12:00:00Z', + creator: 'John Doe', + date: '2023-05-02T08:30:00Z', + dateAccepted: '2023-05-10T09:00:00Z', + dateCopyrighted: '2023-05-15T00:00:00Z', + dateSubmitted: '2023-05-05T14:30:00Z', + description: 'A comprehensive description', + educationLevel: 'Graduate level', + extent: '250 pages', + format: 'application/pdf', + hasFormat: 'https://example.org/formats/pdf', + hasPart: 'https://example.org/parts/chapter1', + hasVersion: 'https://example.org/versions/v2', + identifier: 'ISBN:978-0123456789', + instructionalMethod: 'Online learning', + isFormatOf: 'https://example.org/original', + isPartOf: 'https://example.org/collection', + isReferencedBy: 'https://example.org/references/citation1', + isReplacedBy: 'https://example.org/replacement', + isRequiredBy: 'https://example.org/dependent', + issued: '2023-05-20T10:00:00Z', + isVersionOf: 'https://example.org/original-work', + language: 'en-US', + license: 'Creative Commons Attribution 4.0', + mediator: 'Library System', + medium: 'Digital', + modified: '2023-05-25T16:45:00Z', + provenance: 'Digitized from original manuscript', + publisher: 'Academic Press', + relation: 'https://example.org/related', + rightsHolder: 'Example University', + source: 'https://example.org/source', + spatial: 'Boston, MA, USA', + subject: 'Academic Research', + temporal: '2023', + title: 'Sample Title', + type: 'Text', + valid: '2024-05-25T23:59:59Z', + } - expect(retrieveItemOrFeed(value)).toEqual(expectedFull) + expect(retrieveItemOrFeed(value)).toEqual(expectedWithArrays) }) it('should parse partial item or feed object with some properties', () => { @@ -276,9 +437,13 @@ describe('retrieveItemOrFeed', () => { } const expected = { abstract: 'Partial abstract', + abstracts: ['Partial abstract'], created: '2023-05-01T12:00:00Z', + createds: ['2023-05-01T12:00:00Z'], license: 'MIT License', + licenses: ['MIT License'], spatial: 'New York, NY', + spatials: ['New York, NY'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -291,7 +456,9 @@ describe('retrieveItemOrFeed', () => { } const expected = { abstract: 'First abstract', + abstracts: ['First abstract', 'Second abstract'], license: 'First license', + licenses: ['First license', 'Second license'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -306,6 +473,7 @@ describe('retrieveItemOrFeed', () => { } const expected = { created: '123456789', + createds: ['123456789'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -331,8 +499,11 @@ describe('retrieveItemOrFeed', () => { } const expected = { abstract: 'Valid abstract', + abstracts: ['Valid abstract'], created: 'invalid-date', + createds: ['invalid-date'], license: 'Valid license', + licenses: ['Valid license'], } expect(retrieveItemOrFeed(value)).toEqual(expected) diff --git a/src/namespaces/dcterms/parse/utils.ts b/src/namespaces/dcterms/parse/utils.ts index 2aaf5709..841f5b34 100644 --- a/src/namespaces/dcterms/parse/utils.ts +++ b/src/namespaces/dcterms/parse/utils.ts @@ -1,6 +1,7 @@ import type { ParsePartialUtil } from '../../../common/types.js' import { isObject, + parseArrayOf, parseDate, parseSingularOf, parseString, @@ -15,12 +16,10 @@ export const retrieveItemOrFeed: ParsePartialUtil> } const itemOrFeed = { + // Singular fields (deprecated - kept for backward compatibility, returns first value) abstract: parseSingularOf(value['dcterms:abstract'], (value) => parseString(retrieveText(value)), ), - accessRights: parseSingularOf(value['dcterms:accessrights'], (value) => - parseString(retrieveText(value)), - ), accrualMethod: parseSingularOf(value['dcterms:accrualmethod'], (value) => parseString(retrieveText(value)), ), @@ -118,34 +117,132 @@ export const retrieveItemOrFeed: ParsePartialUtil> publisher: parseSingularOf(value['dcterms:publisher'], (value) => parseString(retrieveText(value)), ), - references: parseSingularOf(value['dcterms:references'], (value) => - parseString(retrieveText(value)), - ), relation: parseSingularOf(value['dcterms:relation'], (value) => parseString(retrieveText(value)), ), - replaces: parseSingularOf(value['dcterms:replaces'], (value) => - parseString(retrieveText(value)), - ), - requires: parseSingularOf(value['dcterms:requires'], (value) => - parseString(retrieveText(value)), - ), - rights: parseSingularOf(value['dcterms:rights'], (value) => parseString(retrieveText(value))), rightsHolder: parseSingularOf(value['dcterms:rightsholder'], (value) => parseString(retrieveText(value)), ), source: parseSingularOf(value['dcterms:source'], (value) => parseString(retrieveText(value))), spatial: parseSingularOf(value['dcterms:spatial'], (value) => parseString(retrieveText(value))), subject: parseSingularOf(value['dcterms:subject'], (value) => parseString(retrieveText(value))), - tableOfContents: parseSingularOf(value['dcterms:tableofcontents'], (value) => - parseString(retrieveText(value)), - ), temporal: parseSingularOf(value['dcterms:temporal'], (value) => parseString(retrieveText(value)), ), title: parseSingularOf(value['dcterms:title'], (value) => parseString(retrieveText(value))), type: parseSingularOf(value['dcterms:type'], (value) => parseString(retrieveText(value))), valid: parseSingularOf(value['dcterms:valid'], (value) => parseDate(retrieveText(value))), + + // Plural fields (correct - all DC Terms properties are repeatable, returns all values) + abstracts: parseArrayOf(value['dcterms:abstract'], (value) => parseString(retrieveText(value))), + accessRights: parseArrayOf(value['dcterms:accessrights'], (value) => + parseString(retrieveText(value)), + ), + accrualMethods: parseArrayOf(value['dcterms:accrualmethod'], (value) => + parseString(retrieveText(value)), + ), + accrualPeriodicities: parseArrayOf(value['dcterms:accrualperiodicity'], (value) => + parseString(retrieveText(value)), + ), + accrualPolicies: parseArrayOf(value['dcterms:accrualpolicy'], (value) => + parseString(retrieveText(value)), + ), + alternatives: parseArrayOf(value['dcterms:alternative'], (value) => + parseString(retrieveText(value)), + ), + audiences: parseArrayOf(value['dcterms:audience'], (value) => parseString(retrieveText(value))), + availables: parseArrayOf(value['dcterms:available'], (value) => parseDate(retrieveText(value))), + bibliographicCitations: parseArrayOf(value['dcterms:bibliographiccitation'], (value) => + parseString(retrieveText(value)), + ), + conformsTos: parseArrayOf(value['dcterms:conformsto'], (value) => + parseString(retrieveText(value)), + ), + contributors: parseArrayOf(value['dcterms:contributor'], (value) => + parseString(retrieveText(value)), + ), + coverages: parseArrayOf(value['dcterms:coverage'], (value) => parseString(retrieveText(value))), + createds: parseArrayOf(value['dcterms:created'], (value) => parseDate(retrieveText(value))), + creators: parseArrayOf(value['dcterms:creator'], (value) => parseString(retrieveText(value))), + dates: parseArrayOf(value['dcterms:date'], (value) => parseDate(retrieveText(value))), + dateAccepteds: parseArrayOf(value['dcterms:dateaccepted'], (value) => + parseDate(retrieveText(value)), + ), + dateCopyrighteds: parseArrayOf(value['dcterms:datecopyrighted'], (value) => + parseDate(retrieveText(value)), + ), + dateSubmitteds: parseArrayOf(value['dcterms:datesubmitted'], (value) => + parseDate(retrieveText(value)), + ), + descriptions: parseArrayOf(value['dcterms:description'], (value) => + parseString(retrieveText(value)), + ), + educationLevels: parseArrayOf(value['dcterms:educationlevel'], (value) => + parseString(retrieveText(value)), + ), + extents: parseArrayOf(value['dcterms:extent'], (value) => parseString(retrieveText(value))), + formats: parseArrayOf(value['dcterms:format'], (value) => parseString(retrieveText(value))), + hasFormats: parseArrayOf(value['dcterms:hasformat'], (value) => + parseString(retrieveText(value)), + ), + hasParts: parseArrayOf(value['dcterms:haspart'], (value) => parseString(retrieveText(value))), + hasVersions: parseArrayOf(value['dcterms:hasversion'], (value) => + parseString(retrieveText(value)), + ), + identifiers: parseArrayOf(value['dcterms:identifier'], (value) => + parseString(retrieveText(value)), + ), + instructionalMethods: parseArrayOf(value['dcterms:instructionalmethod'], (value) => + parseString(retrieveText(value)), + ), + isFormatOfs: parseArrayOf(value['dcterms:isformatof'], (value) => + parseString(retrieveText(value)), + ), + isPartOfs: parseArrayOf(value['dcterms:ispartof'], (value) => parseString(retrieveText(value))), + isReferencedBys: parseArrayOf(value['dcterms:isreferencedby'], (value) => + parseString(retrieveText(value)), + ), + isReplacedBys: parseArrayOf(value['dcterms:isreplacedby'], (value) => + parseString(retrieveText(value)), + ), + isRequiredBys: parseArrayOf(value['dcterms:isrequiredby'], (value) => + parseString(retrieveText(value)), + ), + issueds: parseArrayOf(value['dcterms:issued'], (value) => parseDate(retrieveText(value))), + isVersionOfs: parseArrayOf(value['dcterms:isversionof'], (value) => + parseString(retrieveText(value)), + ), + languages: parseArrayOf(value['dcterms:language'], (value) => parseString(retrieveText(value))), + licenses: parseArrayOf(value['dcterms:license'], (value) => parseString(retrieveText(value))), + mediators: parseArrayOf(value['dcterms:mediator'], (value) => parseString(retrieveText(value))), + mediums: parseArrayOf(value['dcterms:medium'], (value) => parseString(retrieveText(value))), + modifieds: parseArrayOf(value['dcterms:modified'], (value) => parseDate(retrieveText(value))), + provenances: parseArrayOf(value['dcterms:provenance'], (value) => + parseString(retrieveText(value)), + ), + publishers: parseArrayOf(value['dcterms:publisher'], (value) => + parseString(retrieveText(value)), + ), + references: parseArrayOf(value['dcterms:references'], (value) => + parseString(retrieveText(value)), + ), + relations: parseArrayOf(value['dcterms:relation'], (value) => parseString(retrieveText(value))), + replaces: parseArrayOf(value['dcterms:replaces'], (value) => parseString(retrieveText(value))), + requires: parseArrayOf(value['dcterms:requires'], (value) => parseString(retrieveText(value))), + rights: parseArrayOf(value['dcterms:rights'], (value) => parseString(retrieveText(value))), + rightsHolders: parseArrayOf(value['dcterms:rightsholder'], (value) => + parseString(retrieveText(value)), + ), + sources: parseArrayOf(value['dcterms:source'], (value) => parseString(retrieveText(value))), + spatials: parseArrayOf(value['dcterms:spatial'], (value) => parseString(retrieveText(value))), + subjects: parseArrayOf(value['dcterms:subject'], (value) => parseString(retrieveText(value))), + tableOfContents: parseArrayOf(value['dcterms:tableofcontents'], (value) => + parseString(retrieveText(value)), + ), + temporals: parseArrayOf(value['dcterms:temporal'], (value) => parseString(retrieveText(value))), + titles: parseArrayOf(value['dcterms:title'], (value) => parseString(retrieveText(value))), + types: parseArrayOf(value['dcterms:type'], (value) => parseString(retrieveText(value))), + valids: parseArrayOf(value['dcterms:valid'], (value) => parseDate(retrieveText(value))), } return trimObject(itemOrFeed) From 1ba11e456c0d611a428efddb98968ae18021b174 Mon Sep 17 00:00:00 2001 From: Maciej Lamberski Date: Wed, 29 Oct 2025 00:13:58 +0100 Subject: [PATCH 2/2] chore: Update order of deprecated fields in DC Terms and use common utils --- src/namespaces/dcterms/generate/utils.ts | 196 ++++++++++++-------- src/namespaces/dcterms/parse/utils.ts | 223 +++++++++++------------ 2 files changed, 235 insertions(+), 184 deletions(-) diff --git a/src/namespaces/dcterms/generate/utils.ts b/src/namespaces/dcterms/generate/utils.ts index 1bddc99c..2edeab60 100644 --- a/src/namespaces/dcterms/generate/utils.ts +++ b/src/namespaces/dcterms/generate/utils.ts @@ -1,10 +1,9 @@ import type { DateLike, GenerateUtil } from '../../../common/types.js' import { + generateArrayOrSingular, generateCdataString, generateRfc3339Date, isObject, - isPresent, - trimArray, trimObject, } from '../../../common/utils.js' import type { DctermsNs } from '../common/types.js' @@ -14,217 +13,270 @@ export const generateItemOrFeed: GenerateUtil> = return } - // TODO: Remove this once deprecated singular fields are removed in next major version. - const generateArray = ( - pluralValues: Array | undefined, - singularValue: V | undefined, - generator: (value: V) => unknown, - ) => { - if (isPresent(pluralValues)) { - return trimArray(pluralValues.map(generator)) - } - - if (isPresent(singularValue)) { - return generator(singularValue) - } - } - const value = { - 'dcterms:abstract': generateArray( + 'dcterms:abstract': generateArrayOrSingular( itemOrFeed.abstracts, itemOrFeed.abstract, generateCdataString, ), - 'dcterms:accessRights': generateArray(itemOrFeed.accessRights, undefined, generateCdataString), - 'dcterms:accrualMethod': generateArray( + 'dcterms:accessRights': generateArrayOrSingular( + itemOrFeed.accessRights, + undefined, + generateCdataString, + ), + 'dcterms:accrualMethod': generateArrayOrSingular( itemOrFeed.accrualMethods, itemOrFeed.accrualMethod, generateCdataString, ), - 'dcterms:accrualPeriodicity': generateArray( + 'dcterms:accrualPeriodicity': generateArrayOrSingular( itemOrFeed.accrualPeriodicities, itemOrFeed.accrualPeriodicity, generateCdataString, ), - 'dcterms:accrualPolicy': generateArray( + 'dcterms:accrualPolicy': generateArrayOrSingular( itemOrFeed.accrualPolicies, itemOrFeed.accrualPolicy, generateCdataString, ), - 'dcterms:alternative': generateArray( + 'dcterms:alternative': generateArrayOrSingular( itemOrFeed.alternatives, itemOrFeed.alternative, generateCdataString, ), - 'dcterms:audience': generateArray( + 'dcterms:audience': generateArrayOrSingular( itemOrFeed.audiences, itemOrFeed.audience, generateCdataString, ), - 'dcterms:available': generateArray( + 'dcterms:available': generateArrayOrSingular( itemOrFeed.availables, itemOrFeed.available, generateRfc3339Date, ), - 'dcterms:bibliographicCitation': generateArray( + 'dcterms:bibliographicCitation': generateArrayOrSingular( itemOrFeed.bibliographicCitations, itemOrFeed.bibliographicCitation, generateCdataString, ), - 'dcterms:conformsTo': generateArray( + 'dcterms:conformsTo': generateArrayOrSingular( itemOrFeed.conformsTos, itemOrFeed.conformsTo, generateCdataString, ), - 'dcterms:contributor': generateArray( + 'dcterms:contributor': generateArrayOrSingular( itemOrFeed.contributors, itemOrFeed.contributor, generateCdataString, ), - 'dcterms:coverage': generateArray( + 'dcterms:coverage': generateArrayOrSingular( itemOrFeed.coverages, itemOrFeed.coverage, generateCdataString, ), - 'dcterms:created': generateArray(itemOrFeed.createds, itemOrFeed.created, generateRfc3339Date), - 'dcterms:creator': generateArray(itemOrFeed.creators, itemOrFeed.creator, generateCdataString), - 'dcterms:date': generateArray(itemOrFeed.dates, itemOrFeed.date, generateRfc3339Date), - 'dcterms:dateAccepted': generateArray( + 'dcterms:created': generateArrayOrSingular( + itemOrFeed.createds, + itemOrFeed.created, + generateRfc3339Date, + ), + 'dcterms:creator': generateArrayOrSingular( + itemOrFeed.creators, + itemOrFeed.creator, + generateCdataString, + ), + 'dcterms:date': generateArrayOrSingular(itemOrFeed.dates, itemOrFeed.date, generateRfc3339Date), + 'dcterms:dateAccepted': generateArrayOrSingular( itemOrFeed.dateAccepteds, itemOrFeed.dateAccepted, generateRfc3339Date, ), - 'dcterms:dateCopyrighted': generateArray( + 'dcterms:dateCopyrighted': generateArrayOrSingular( itemOrFeed.dateCopyrighteds, itemOrFeed.dateCopyrighted, generateRfc3339Date, ), - 'dcterms:dateSubmitted': generateArray( + 'dcterms:dateSubmitted': generateArrayOrSingular( itemOrFeed.dateSubmitteds, itemOrFeed.dateSubmitted, generateRfc3339Date, ), - 'dcterms:description': generateArray( + 'dcterms:description': generateArrayOrSingular( itemOrFeed.descriptions, itemOrFeed.description, generateCdataString, ), - 'dcterms:educationLevel': generateArray( + 'dcterms:educationLevel': generateArrayOrSingular( itemOrFeed.educationLevels, itemOrFeed.educationLevel, generateCdataString, ), - 'dcterms:extent': generateArray(itemOrFeed.extents, itemOrFeed.extent, generateCdataString), - 'dcterms:format': generateArray(itemOrFeed.formats, itemOrFeed.format, generateCdataString), - 'dcterms:hasFormat': generateArray( + 'dcterms:extent': generateArrayOrSingular( + itemOrFeed.extents, + itemOrFeed.extent, + generateCdataString, + ), + 'dcterms:format': generateArrayOrSingular( + itemOrFeed.formats, + itemOrFeed.format, + generateCdataString, + ), + 'dcterms:hasFormat': generateArrayOrSingular( itemOrFeed.hasFormats, itemOrFeed.hasFormat, generateCdataString, ), - 'dcterms:hasPart': generateArray(itemOrFeed.hasParts, itemOrFeed.hasPart, generateCdataString), - 'dcterms:hasVersion': generateArray( + 'dcterms:hasPart': generateArrayOrSingular( + itemOrFeed.hasParts, + itemOrFeed.hasPart, + generateCdataString, + ), + 'dcterms:hasVersion': generateArrayOrSingular( itemOrFeed.hasVersions, itemOrFeed.hasVersion, generateCdataString, ), - 'dcterms:identifier': generateArray( + 'dcterms:identifier': generateArrayOrSingular( itemOrFeed.identifiers, itemOrFeed.identifier, generateCdataString, ), - 'dcterms:instructionalMethod': generateArray( + 'dcterms:instructionalMethod': generateArrayOrSingular( itemOrFeed.instructionalMethods, itemOrFeed.instructionalMethod, generateCdataString, ), - 'dcterms:isFormatOf': generateArray( + 'dcterms:isFormatOf': generateArrayOrSingular( itemOrFeed.isFormatOfs, itemOrFeed.isFormatOf, generateCdataString, ), - 'dcterms:isPartOf': generateArray( + 'dcterms:isPartOf': generateArrayOrSingular( itemOrFeed.isPartOfs, itemOrFeed.isPartOf, generateCdataString, ), - 'dcterms:isReferencedBy': generateArray( + 'dcterms:isReferencedBy': generateArrayOrSingular( itemOrFeed.isReferencedBys, itemOrFeed.isReferencedBy, generateCdataString, ), - 'dcterms:isReplacedBy': generateArray( + 'dcterms:isReplacedBy': generateArrayOrSingular( itemOrFeed.isReplacedBys, itemOrFeed.isReplacedBy, generateCdataString, ), - 'dcterms:isRequiredBy': generateArray( + 'dcterms:isRequiredBy': generateArrayOrSingular( itemOrFeed.isRequiredBys, itemOrFeed.isRequiredBy, generateCdataString, ), - 'dcterms:issued': generateArray(itemOrFeed.issueds, itemOrFeed.issued, generateRfc3339Date), - 'dcterms:isVersionOf': generateArray( + 'dcterms:issued': generateArrayOrSingular( + itemOrFeed.issueds, + itemOrFeed.issued, + generateRfc3339Date, + ), + 'dcterms:isVersionOf': generateArrayOrSingular( itemOrFeed.isVersionOfs, itemOrFeed.isVersionOf, generateCdataString, ), - 'dcterms:language': generateArray( + 'dcterms:language': generateArrayOrSingular( itemOrFeed.languages, itemOrFeed.language, generateCdataString, ), - 'dcterms:license': generateArray(itemOrFeed.licenses, itemOrFeed.license, generateCdataString), - 'dcterms:mediator': generateArray( + 'dcterms:license': generateArrayOrSingular( + itemOrFeed.licenses, + itemOrFeed.license, + generateCdataString, + ), + 'dcterms:mediator': generateArrayOrSingular( itemOrFeed.mediators, itemOrFeed.mediator, generateCdataString, ), - 'dcterms:medium': generateArray(itemOrFeed.mediums, itemOrFeed.medium, generateCdataString), - 'dcterms:modified': generateArray( + 'dcterms:medium': generateArrayOrSingular( + itemOrFeed.mediums, + itemOrFeed.medium, + generateCdataString, + ), + 'dcterms:modified': generateArrayOrSingular( itemOrFeed.modifieds, itemOrFeed.modified, generateRfc3339Date, ), - 'dcterms:provenance': generateArray( + 'dcterms:provenance': generateArrayOrSingular( itemOrFeed.provenances, itemOrFeed.provenance, generateCdataString, ), - 'dcterms:publisher': generateArray( + 'dcterms:publisher': generateArrayOrSingular( itemOrFeed.publishers, itemOrFeed.publisher, generateCdataString, ), - 'dcterms:references': generateArray(itemOrFeed.references, undefined, generateCdataString), - 'dcterms:relation': generateArray( + 'dcterms:references': generateArrayOrSingular( + itemOrFeed.references, + undefined, + generateCdataString, + ), + 'dcterms:relation': generateArrayOrSingular( itemOrFeed.relations, itemOrFeed.relation, generateCdataString, ), - 'dcterms:replaces': generateArray(itemOrFeed.replaces, undefined, generateCdataString), - 'dcterms:requires': generateArray(itemOrFeed.requires, undefined, generateCdataString), - 'dcterms:rights': generateArray(itemOrFeed.rights, undefined, generateCdataString), - 'dcterms:rightsHolder': generateArray( + 'dcterms:replaces': generateArrayOrSingular( + itemOrFeed.replaces, + undefined, + generateCdataString, + ), + 'dcterms:requires': generateArrayOrSingular( + itemOrFeed.requires, + undefined, + generateCdataString, + ), + 'dcterms:rights': generateArrayOrSingular(itemOrFeed.rights, undefined, generateCdataString), + 'dcterms:rightsHolder': generateArrayOrSingular( itemOrFeed.rightsHolders, itemOrFeed.rightsHolder, generateCdataString, ), - 'dcterms:source': generateArray(itemOrFeed.sources, itemOrFeed.source, generateCdataString), - 'dcterms:spatial': generateArray(itemOrFeed.spatials, itemOrFeed.spatial, generateCdataString), - 'dcterms:subject': generateArray(itemOrFeed.subjects, itemOrFeed.subject, generateCdataString), - 'dcterms:tableOfContents': generateArray( + 'dcterms:source': generateArrayOrSingular( + itemOrFeed.sources, + itemOrFeed.source, + generateCdataString, + ), + 'dcterms:spatial': generateArrayOrSingular( + itemOrFeed.spatials, + itemOrFeed.spatial, + generateCdataString, + ), + 'dcterms:subject': generateArrayOrSingular( + itemOrFeed.subjects, + itemOrFeed.subject, + generateCdataString, + ), + 'dcterms:tableOfContents': generateArrayOrSingular( itemOrFeed.tableOfContents, undefined, generateCdataString, ), - 'dcterms:temporal': generateArray( + 'dcterms:temporal': generateArrayOrSingular( itemOrFeed.temporals, itemOrFeed.temporal, generateCdataString, ), - 'dcterms:title': generateArray(itemOrFeed.titles, itemOrFeed.title, generateCdataString), - 'dcterms:type': generateArray(itemOrFeed.types, itemOrFeed.type, generateCdataString), - 'dcterms:valid': generateArray(itemOrFeed.valids, itemOrFeed.valid, generateRfc3339Date), + 'dcterms:title': generateArrayOrSingular( + itemOrFeed.titles, + itemOrFeed.title, + generateCdataString, + ), + 'dcterms:type': generateArrayOrSingular(itemOrFeed.types, itemOrFeed.type, generateCdataString), + 'dcterms:valid': generateArrayOrSingular( + itemOrFeed.valids, + itemOrFeed.valid, + generateRfc3339Date, + ), } return trimObject(value) diff --git a/src/namespaces/dcterms/parse/utils.ts b/src/namespaces/dcterms/parse/utils.ts index 841f5b34..80a92bb0 100644 --- a/src/namespaces/dcterms/parse/utils.ts +++ b/src/namespaces/dcterms/parse/utils.ts @@ -16,7 +16,117 @@ export const retrieveItemOrFeed: ParsePartialUtil> } const itemOrFeed = { - // Singular fields (deprecated - kept for backward compatibility, returns first value) + abstracts: parseArrayOf(value['dcterms:abstract'], (value) => parseString(retrieveText(value))), + accessRights: parseArrayOf(value['dcterms:accessrights'], (value) => + parseString(retrieveText(value)), + ), + accrualMethods: parseArrayOf(value['dcterms:accrualmethod'], (value) => + parseString(retrieveText(value)), + ), + accrualPeriodicities: parseArrayOf(value['dcterms:accrualperiodicity'], (value) => + parseString(retrieveText(value)), + ), + accrualPolicies: parseArrayOf(value['dcterms:accrualpolicy'], (value) => + parseString(retrieveText(value)), + ), + alternatives: parseArrayOf(value['dcterms:alternative'], (value) => + parseString(retrieveText(value)), + ), + audiences: parseArrayOf(value['dcterms:audience'], (value) => parseString(retrieveText(value))), + availables: parseArrayOf(value['dcterms:available'], (value) => parseDate(retrieveText(value))), + bibliographicCitations: parseArrayOf(value['dcterms:bibliographiccitation'], (value) => + parseString(retrieveText(value)), + ), + conformsTos: parseArrayOf(value['dcterms:conformsto'], (value) => + parseString(retrieveText(value)), + ), + contributors: parseArrayOf(value['dcterms:contributor'], (value) => + parseString(retrieveText(value)), + ), + coverages: parseArrayOf(value['dcterms:coverage'], (value) => parseString(retrieveText(value))), + createds: parseArrayOf(value['dcterms:created'], (value) => parseDate(retrieveText(value))), + creators: parseArrayOf(value['dcterms:creator'], (value) => parseString(retrieveText(value))), + dates: parseArrayOf(value['dcterms:date'], (value) => parseDate(retrieveText(value))), + dateAccepteds: parseArrayOf(value['dcterms:dateaccepted'], (value) => + parseDate(retrieveText(value)), + ), + dateCopyrighteds: parseArrayOf(value['dcterms:datecopyrighted'], (value) => + parseDate(retrieveText(value)), + ), + dateSubmitteds: parseArrayOf(value['dcterms:datesubmitted'], (value) => + parseDate(retrieveText(value)), + ), + descriptions: parseArrayOf(value['dcterms:description'], (value) => + parseString(retrieveText(value)), + ), + educationLevels: parseArrayOf(value['dcterms:educationlevel'], (value) => + parseString(retrieveText(value)), + ), + extents: parseArrayOf(value['dcterms:extent'], (value) => parseString(retrieveText(value))), + formats: parseArrayOf(value['dcterms:format'], (value) => parseString(retrieveText(value))), + hasFormats: parseArrayOf(value['dcterms:hasformat'], (value) => + parseString(retrieveText(value)), + ), + hasParts: parseArrayOf(value['dcterms:haspart'], (value) => parseString(retrieveText(value))), + hasVersions: parseArrayOf(value['dcterms:hasversion'], (value) => + parseString(retrieveText(value)), + ), + identifiers: parseArrayOf(value['dcterms:identifier'], (value) => + parseString(retrieveText(value)), + ), + instructionalMethods: parseArrayOf(value['dcterms:instructionalmethod'], (value) => + parseString(retrieveText(value)), + ), + isFormatOfs: parseArrayOf(value['dcterms:isformatof'], (value) => + parseString(retrieveText(value)), + ), + isPartOfs: parseArrayOf(value['dcterms:ispartof'], (value) => parseString(retrieveText(value))), + isReferencedBys: parseArrayOf(value['dcterms:isreferencedby'], (value) => + parseString(retrieveText(value)), + ), + isReplacedBys: parseArrayOf(value['dcterms:isreplacedby'], (value) => + parseString(retrieveText(value)), + ), + isRequiredBys: parseArrayOf(value['dcterms:isrequiredby'], (value) => + parseString(retrieveText(value)), + ), + issueds: parseArrayOf(value['dcterms:issued'], (value) => parseDate(retrieveText(value))), + isVersionOfs: parseArrayOf(value['dcterms:isversionof'], (value) => + parseString(retrieveText(value)), + ), + languages: parseArrayOf(value['dcterms:language'], (value) => parseString(retrieveText(value))), + licenses: parseArrayOf(value['dcterms:license'], (value) => parseString(retrieveText(value))), + mediators: parseArrayOf(value['dcterms:mediator'], (value) => parseString(retrieveText(value))), + mediums: parseArrayOf(value['dcterms:medium'], (value) => parseString(retrieveText(value))), + modifieds: parseArrayOf(value['dcterms:modified'], (value) => parseDate(retrieveText(value))), + provenances: parseArrayOf(value['dcterms:provenance'], (value) => + parseString(retrieveText(value)), + ), + publishers: parseArrayOf(value['dcterms:publisher'], (value) => + parseString(retrieveText(value)), + ), + references: parseArrayOf(value['dcterms:references'], (value) => + parseString(retrieveText(value)), + ), + relations: parseArrayOf(value['dcterms:relation'], (value) => parseString(retrieveText(value))), + replaces: parseArrayOf(value['dcterms:replaces'], (value) => parseString(retrieveText(value))), + requires: parseArrayOf(value['dcterms:requires'], (value) => parseString(retrieveText(value))), + rights: parseArrayOf(value['dcterms:rights'], (value) => parseString(retrieveText(value))), + rightsHolders: parseArrayOf(value['dcterms:rightsholder'], (value) => + parseString(retrieveText(value)), + ), + sources: parseArrayOf(value['dcterms:source'], (value) => parseString(retrieveText(value))), + spatials: parseArrayOf(value['dcterms:spatial'], (value) => parseString(retrieveText(value))), + subjects: parseArrayOf(value['dcterms:subject'], (value) => parseString(retrieveText(value))), + tableOfContents: parseArrayOf(value['dcterms:tableofcontents'], (value) => + parseString(retrieveText(value)), + ), + temporals: parseArrayOf(value['dcterms:temporal'], (value) => parseString(retrieveText(value))), + titles: parseArrayOf(value['dcterms:title'], (value) => parseString(retrieveText(value))), + types: parseArrayOf(value['dcterms:type'], (value) => parseString(retrieveText(value))), + valids: parseArrayOf(value['dcterms:valid'], (value) => parseDate(retrieveText(value))), + + // Deprecated fields for backward compatibility. abstract: parseSingularOf(value['dcterms:abstract'], (value) => parseString(retrieveText(value)), ), @@ -132,117 +242,6 @@ export const retrieveItemOrFeed: ParsePartialUtil> title: parseSingularOf(value['dcterms:title'], (value) => parseString(retrieveText(value))), type: parseSingularOf(value['dcterms:type'], (value) => parseString(retrieveText(value))), valid: parseSingularOf(value['dcterms:valid'], (value) => parseDate(retrieveText(value))), - - // Plural fields (correct - all DC Terms properties are repeatable, returns all values) - abstracts: parseArrayOf(value['dcterms:abstract'], (value) => parseString(retrieveText(value))), - accessRights: parseArrayOf(value['dcterms:accessrights'], (value) => - parseString(retrieveText(value)), - ), - accrualMethods: parseArrayOf(value['dcterms:accrualmethod'], (value) => - parseString(retrieveText(value)), - ), - accrualPeriodicities: parseArrayOf(value['dcterms:accrualperiodicity'], (value) => - parseString(retrieveText(value)), - ), - accrualPolicies: parseArrayOf(value['dcterms:accrualpolicy'], (value) => - parseString(retrieveText(value)), - ), - alternatives: parseArrayOf(value['dcterms:alternative'], (value) => - parseString(retrieveText(value)), - ), - audiences: parseArrayOf(value['dcterms:audience'], (value) => parseString(retrieveText(value))), - availables: parseArrayOf(value['dcterms:available'], (value) => parseDate(retrieveText(value))), - bibliographicCitations: parseArrayOf(value['dcterms:bibliographiccitation'], (value) => - parseString(retrieveText(value)), - ), - conformsTos: parseArrayOf(value['dcterms:conformsto'], (value) => - parseString(retrieveText(value)), - ), - contributors: parseArrayOf(value['dcterms:contributor'], (value) => - parseString(retrieveText(value)), - ), - coverages: parseArrayOf(value['dcterms:coverage'], (value) => parseString(retrieveText(value))), - createds: parseArrayOf(value['dcterms:created'], (value) => parseDate(retrieveText(value))), - creators: parseArrayOf(value['dcterms:creator'], (value) => parseString(retrieveText(value))), - dates: parseArrayOf(value['dcterms:date'], (value) => parseDate(retrieveText(value))), - dateAccepteds: parseArrayOf(value['dcterms:dateaccepted'], (value) => - parseDate(retrieveText(value)), - ), - dateCopyrighteds: parseArrayOf(value['dcterms:datecopyrighted'], (value) => - parseDate(retrieveText(value)), - ), - dateSubmitteds: parseArrayOf(value['dcterms:datesubmitted'], (value) => - parseDate(retrieveText(value)), - ), - descriptions: parseArrayOf(value['dcterms:description'], (value) => - parseString(retrieveText(value)), - ), - educationLevels: parseArrayOf(value['dcterms:educationlevel'], (value) => - parseString(retrieveText(value)), - ), - extents: parseArrayOf(value['dcterms:extent'], (value) => parseString(retrieveText(value))), - formats: parseArrayOf(value['dcterms:format'], (value) => parseString(retrieveText(value))), - hasFormats: parseArrayOf(value['dcterms:hasformat'], (value) => - parseString(retrieveText(value)), - ), - hasParts: parseArrayOf(value['dcterms:haspart'], (value) => parseString(retrieveText(value))), - hasVersions: parseArrayOf(value['dcterms:hasversion'], (value) => - parseString(retrieveText(value)), - ), - identifiers: parseArrayOf(value['dcterms:identifier'], (value) => - parseString(retrieveText(value)), - ), - instructionalMethods: parseArrayOf(value['dcterms:instructionalmethod'], (value) => - parseString(retrieveText(value)), - ), - isFormatOfs: parseArrayOf(value['dcterms:isformatof'], (value) => - parseString(retrieveText(value)), - ), - isPartOfs: parseArrayOf(value['dcterms:ispartof'], (value) => parseString(retrieveText(value))), - isReferencedBys: parseArrayOf(value['dcterms:isreferencedby'], (value) => - parseString(retrieveText(value)), - ), - isReplacedBys: parseArrayOf(value['dcterms:isreplacedby'], (value) => - parseString(retrieveText(value)), - ), - isRequiredBys: parseArrayOf(value['dcterms:isrequiredby'], (value) => - parseString(retrieveText(value)), - ), - issueds: parseArrayOf(value['dcterms:issued'], (value) => parseDate(retrieveText(value))), - isVersionOfs: parseArrayOf(value['dcterms:isversionof'], (value) => - parseString(retrieveText(value)), - ), - languages: parseArrayOf(value['dcterms:language'], (value) => parseString(retrieveText(value))), - licenses: parseArrayOf(value['dcterms:license'], (value) => parseString(retrieveText(value))), - mediators: parseArrayOf(value['dcterms:mediator'], (value) => parseString(retrieveText(value))), - mediums: parseArrayOf(value['dcterms:medium'], (value) => parseString(retrieveText(value))), - modifieds: parseArrayOf(value['dcterms:modified'], (value) => parseDate(retrieveText(value))), - provenances: parseArrayOf(value['dcterms:provenance'], (value) => - parseString(retrieveText(value)), - ), - publishers: parseArrayOf(value['dcterms:publisher'], (value) => - parseString(retrieveText(value)), - ), - references: parseArrayOf(value['dcterms:references'], (value) => - parseString(retrieveText(value)), - ), - relations: parseArrayOf(value['dcterms:relation'], (value) => parseString(retrieveText(value))), - replaces: parseArrayOf(value['dcterms:replaces'], (value) => parseString(retrieveText(value))), - requires: parseArrayOf(value['dcterms:requires'], (value) => parseString(retrieveText(value))), - rights: parseArrayOf(value['dcterms:rights'], (value) => parseString(retrieveText(value))), - rightsHolders: parseArrayOf(value['dcterms:rightsholder'], (value) => - parseString(retrieveText(value)), - ), - sources: parseArrayOf(value['dcterms:source'], (value) => parseString(retrieveText(value))), - spatials: parseArrayOf(value['dcterms:spatial'], (value) => parseString(retrieveText(value))), - subjects: parseArrayOf(value['dcterms:subject'], (value) => parseString(retrieveText(value))), - tableOfContents: parseArrayOf(value['dcterms:tableofcontents'], (value) => - parseString(retrieveText(value)), - ), - temporals: parseArrayOf(value['dcterms:temporal'], (value) => parseString(retrieveText(value))), - titles: parseArrayOf(value['dcterms:title'], (value) => parseString(retrieveText(value))), - types: parseArrayOf(value['dcterms:type'], (value) => parseString(retrieveText(value))), - valids: parseArrayOf(value['dcterms:valid'], (value) => parseDate(retrieveText(value))), } return trimObject(itemOrFeed)