@digitalculture/ochre-sdk 0.5.17 → 0.5.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -63,6 +63,7 @@ __export(index_exports, {
63
63
  parsePerson: () => parsePerson,
64
64
  parsePersons: () => parsePersons,
65
65
  parseProperties: () => parseProperties,
66
+ parseProperty: () => parseProperty,
66
67
  parsePropertyValue: () => parsePropertyValue,
67
68
  parsePropertyValues: () => parsePropertyValues,
68
69
  parseResource: () => parseResource,
@@ -524,9 +525,36 @@ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
524
525
  const { searchNestedProperties } = options;
525
526
  const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
526
527
  if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
527
- let isFound = property.values.some(
528
- (value) => value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"))
529
- );
528
+ let isFound = property.values.some((value) => {
529
+ if (value.content === null) {
530
+ return false;
531
+ }
532
+ if (typeof value.content === "string") {
533
+ if (typeof filter.value !== "string") {
534
+ return false;
535
+ }
536
+ return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
537
+ }
538
+ if (typeof value.content === "number") {
539
+ if (typeof filter.value !== "number") {
540
+ return false;
541
+ }
542
+ return value.content === filter.value;
543
+ }
544
+ if (typeof value.content === "boolean") {
545
+ if (typeof filter.value !== "boolean") {
546
+ return false;
547
+ }
548
+ return value.booleanValue === filter.value;
549
+ }
550
+ if (value.content instanceof Date) {
551
+ if (!(filter.value instanceof Date)) {
552
+ return false;
553
+ }
554
+ return value.content.getTime() === filter.value.getTime();
555
+ }
556
+ return false;
557
+ });
530
558
  if (!isFound && searchNestedProperties) {
531
559
  isFound = property.properties.some(
532
560
  (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
@@ -561,6 +589,23 @@ var websiteSchema = import_zod3.z.object({
561
589
  { message: "Invalid website privacy" }
562
590
  )
563
591
  });
592
+ var resourceTypeSchema = import_zod3.z.enum(
593
+ [
594
+ "audio",
595
+ "document",
596
+ "drawing",
597
+ "FITS",
598
+ "geospatial",
599
+ "IIIF",
600
+ "image",
601
+ "model",
602
+ "PTM",
603
+ "TEI",
604
+ "video",
605
+ "webpage"
606
+ ],
607
+ { message: "Invalid resource type" }
608
+ );
564
609
  var componentSchema = import_zod3.z.enum(
565
610
  [
566
611
  "annotated-document",
@@ -874,33 +919,71 @@ function parseEvents(events) {
874
919
  }
875
920
  return returnEvents;
876
921
  }
877
- function parseProperties(properties, language = "eng") {
878
- const returnProperties = [];
879
- for (const property of properties) {
880
- const valuesToParse = "value" in property && property.value ? Array.isArray(property.value) ? property.value : [property.value] : [];
881
- const values = valuesToParse.map(
882
- (value) => !["string", "number", "boolean"].includes(typeof value) && typeof value === "object" ? {
883
- content: value.slug ? parseFakeString(value.slug) : parseStringContent(value),
884
- type: value.type,
885
- category: value.category !== "value" ? value.category ?? null : null,
886
- uuid: value.uuid ?? null,
887
- publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null
888
- } : {
889
- content: parseFakeString(value),
890
- type: "string",
922
+ function parseProperty(property, type, language = "eng") {
923
+ const valuesToParse = "value" in property && property.value ? Array.isArray(property.value) ? property.value : [property.value] : [];
924
+ const values = valuesToParse.map((value) => {
925
+ let content = null;
926
+ let booleanValue = null;
927
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
928
+ content = parseFakeString(value);
929
+ const returnValue = {
930
+ content,
931
+ booleanValue,
932
+ type,
891
933
  category: "value",
892
934
  uuid: null,
893
935
  publicationDateTime: null
936
+ };
937
+ return returnValue;
938
+ } else {
939
+ switch (type) {
940
+ case "integer":
941
+ case "decimal": {
942
+ content = Number(value.content);
943
+ break;
944
+ }
945
+ case "dateTime": {
946
+ content = value.content ? typeof value.content === "string" ? new Date(value.content) : new Date(parseStringContent({ content: value.content })) : null;
947
+ break;
948
+ }
949
+ default: {
950
+ if ("slug" in value && value.slug != null) {
951
+ content = parseFakeString(value.slug);
952
+ } else if (value.content != null) {
953
+ content = parseStringContent({ content: value.content });
954
+ }
955
+ if (type === "boolean") {
956
+ booleanValue = value.booleanValue ?? null;
957
+ }
958
+ break;
959
+ }
894
960
  }
961
+ const returnValue = {
962
+ content,
963
+ booleanValue,
964
+ type,
965
+ category: value.category ?? "value",
966
+ uuid: value.uuid ?? null,
967
+ publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null
968
+ };
969
+ return returnValue;
970
+ }
971
+ });
972
+ return {
973
+ label: parseStringContent(property.label, language).replace(/\s*\.{3}$/, "").trim(),
974
+ values,
975
+ comment: property.comment != null ? parseFakeString(property.comment) : null,
976
+ properties: property.property ? parseProperties(
977
+ Array.isArray(property.property) ? property.property : [property.property]
978
+ ) : []
979
+ };
980
+ }
981
+ function parseProperties(properties, language = "eng") {
982
+ const returnProperties = [];
983
+ for (const property of properties) {
984
+ returnProperties.push(
985
+ parseProperty(property, "string", language)
895
986
  );
896
- returnProperties.push({
897
- label: parseStringContent(property.label, language).replace(/\s*\.{3}$/, "").trim(),
898
- values,
899
- comment: property.comment != null ? parseFakeString(property.comment) : null,
900
- properties: property.property ? parseProperties(
901
- Array.isArray(property.property) ? property.property : [property.property]
902
- ) : []
903
- });
904
987
  }
905
988
  return returnProperties;
906
989
  }
@@ -957,10 +1040,13 @@ function parsePeriods(periods) {
957
1040
  function parseBibliography(bibliography) {
958
1041
  let resource = null;
959
1042
  if (bibliography.source?.resource) {
1043
+ const resourceType = resourceTypeSchema.parse(
1044
+ bibliography.source.resource.type
1045
+ );
960
1046
  resource = {
961
1047
  uuid: bibliography.source.resource.uuid,
962
1048
  publicationDateTime: bibliography.source.resource.publicationDateTime ? new Date(bibliography.source.resource.publicationDateTime) : null,
963
- type: bibliography.source.resource.type,
1049
+ type: resourceType,
964
1050
  identification: parseIdentification(
965
1051
  bibliography.source.resource.identification
966
1052
  )
@@ -1203,11 +1289,12 @@ function parseSet(set) {
1203
1289
  };
1204
1290
  }
1205
1291
  function parseResource(resource, isNested = false) {
1292
+ const resourceType = resourceTypeSchema.parse(resource.type);
1206
1293
  const returnResource = {
1207
1294
  uuid: resource.uuid,
1208
1295
  category: "resource",
1209
1296
  publicationDateTime: resource.publicationDateTime ? new Date(resource.publicationDateTime) : null,
1210
- type: resource.type,
1297
+ type: resourceType,
1211
1298
  number: resource.n,
1212
1299
  format: resource.format ?? null,
1213
1300
  context: "context" in resource && resource.context ? parseContext(resource.context) : null,
@@ -1644,7 +1731,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1644
1731
  "width"
1645
1732
  );
1646
1733
  if (widthProperty !== null) {
1647
- width = Number.parseFloat(widthProperty);
1734
+ if (typeof widthProperty === "number") {
1735
+ width = widthProperty;
1736
+ } else if (typeof widthProperty === "string") {
1737
+ width = Number.parseFloat(widthProperty);
1738
+ }
1648
1739
  }
1649
1740
  let height = null;
1650
1741
  const heightProperty = getPropertyValueByLabel(
@@ -1652,7 +1743,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1652
1743
  "height"
1653
1744
  );
1654
1745
  if (heightProperty !== null) {
1655
- height = Number.parseFloat(heightProperty);
1746
+ if (typeof heightProperty === "number") {
1747
+ height = heightProperty;
1748
+ } else if (typeof heightProperty === "string") {
1749
+ height = Number.parseFloat(heightProperty);
1750
+ }
1656
1751
  }
1657
1752
  let isFullWidth = true;
1658
1753
  const isFullWidthProperty = getPropertyValueByLabel(
@@ -1714,7 +1809,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1714
1809
  "seconds-per-image"
1715
1810
  );
1716
1811
  if (secondsPerImageProperty !== null) {
1717
- secondsPerImage = Number.parseFloat(secondsPerImageProperty);
1812
+ if (typeof secondsPerImageProperty === "number") {
1813
+ secondsPerImage = secondsPerImageProperty;
1814
+ } else if (typeof secondsPerImageProperty === "string") {
1815
+ secondsPerImage = Number.parseFloat(secondsPerImageProperty);
1816
+ }
1718
1817
  }
1719
1818
  }
1720
1819
  carouselOptions = {
@@ -1969,7 +2068,7 @@ async function parseWebpage(webpageResource) {
1969
2068
  resourceProperties,
1970
2069
  "presentation"
1971
2070
  );
1972
- if (!resourceType) {
2071
+ if (resourceType == null) {
1973
2072
  continue;
1974
2073
  }
1975
2074
  switch (resourceType) {
@@ -2150,7 +2249,7 @@ async function parseBlock(blockResource) {
2150
2249
  resourceProperties,
2151
2250
  "presentation"
2152
2251
  );
2153
- if (!resourceType) {
2252
+ if (resourceType == null) {
2154
2253
  continue;
2155
2254
  }
2156
2255
  switch (resourceType) {
@@ -2223,6 +2322,16 @@ function parseWebsiteProperties(properties) {
2223
2322
  if (!result.success) {
2224
2323
  throw new Error(`Invalid website properties: ${result.error.message}`);
2225
2324
  }
2325
+ let contact = null;
2326
+ const contactProperty = websiteProperties.find(
2327
+ (property) => property.label === "contact"
2328
+ );
2329
+ if (contactProperty) {
2330
+ const [name, email] = (contactProperty.values[0]?.content).split(
2331
+ ";"
2332
+ );
2333
+ contact = { name, email: email ?? null };
2334
+ }
2226
2335
  const logoUuid = websiteProperties.find((property) => property.label === "logo")?.values[0]?.uuid ?? null;
2227
2336
  let isHeaderDisplayed = true;
2228
2337
  let headerVariant = "default";
@@ -2289,6 +2398,7 @@ function parseWebsiteProperties(properties) {
2289
2398
  type: validatedType,
2290
2399
  privacy: validatedPrivacy,
2291
2400
  status: validatedStatus,
2401
+ contact,
2292
2402
  isHeaderDisplayed,
2293
2403
  headerVariant,
2294
2404
  headerAlignment,
@@ -2759,6 +2869,7 @@ async function fetchWebsite(abbreviation) {
2759
2869
  parsePerson,
2760
2870
  parsePersons,
2761
2871
  parseProperties,
2872
+ parseProperty,
2762
2873
  parsePropertyValue,
2763
2874
  parsePropertyValues,
2764
2875
  parseResource,
package/dist/index.d.cts CHANGED
@@ -112,7 +112,7 @@ type Link = {
112
112
  uuid: string;
113
113
  publicationDateTime: Date | null;
114
114
  type: string | null;
115
- category: "resource" | "spatialUnit" | "concept" | "set" | "tree" | "person" | "bibliography" | "epigraphicUnit" | "propertyValue" | null;
115
+ category: string | null;
116
116
  identification: Identification | null;
117
117
  content: string | null;
118
118
  href: string | null;
@@ -199,6 +199,10 @@ type Footnote = {
199
199
  label: string;
200
200
  content: string;
201
201
  };
202
+ /**
203
+ * Represents the type of a resource
204
+ */
205
+ type ResourceType = "audio" | "document" | "drawing" | "FITS" | "geospatial" | "IIIF" | "image" | "model" | "PTM" | "TEI" | "video" | "webpage";
202
206
  /**
203
207
  * Represents a resource item with associated metadata, content and relationships
204
208
  */
@@ -206,7 +210,7 @@ type Resource = {
206
210
  uuid: string;
207
211
  category: "resource";
208
212
  publicationDateTime: Date | null;
209
- type: string;
213
+ type: ResourceType;
210
214
  number: number;
211
215
  context: Context | null;
212
216
  license: License | null;
@@ -360,13 +364,15 @@ type PropertyValue = {
360
364
  notes: Array<Note>;
361
365
  links: Array<Link>;
362
366
  };
367
+ type PropertyValueContentType = "string" | "integer" | "decimal" | "boolean" | "date" | "dateTime" | "time" | "coordinate" | "IDREF";
363
368
  /**
364
369
  * Represents a property value with type information
365
370
  */
366
- type PropertyValueContent = {
367
- content: string;
368
- type: "string" | "number" | "integer" | "boolean" | "date" | "dateTime" | "time" | "IDREF";
369
- category: string | null;
371
+ type PropertyValueContent<T extends PropertyValueContentType> = {
372
+ content: T extends "number" ? number : T extends "integer" ? number : T extends "decimal" ? number : T extends "dateTime" ? Date | null : string;
373
+ booleanValue: T extends "boolean" ? boolean : null;
374
+ type: T;
375
+ category: string;
370
376
  uuid: string | null;
371
377
  publicationDateTime: Date | null;
372
378
  };
@@ -375,7 +381,7 @@ type PropertyValueContent = {
375
381
  */
376
382
  type Property = {
377
383
  label: string;
378
- values: Array<PropertyValueContent>;
384
+ values: Array<PropertyValueContent<PropertyValueContentType>>;
379
385
  comment: string | null;
380
386
  properties: Array<Property>;
381
387
  };
@@ -443,6 +449,10 @@ type WebsiteProperties = {
443
449
  type: "traditional" | "digital-collection" | "plum" | "cedar" | "elm" | "maple" | "oak" | "palm";
444
450
  privacy: "public" | "password" | "private";
445
451
  status: "development" | "preview" | "production";
452
+ contact: {
453
+ name: string;
454
+ email: string | null;
455
+ } | null;
446
456
  isHeaderDisplayed: boolean;
447
457
  headerVariant: "default" | "floating" | "inline";
448
458
  headerAlignment: "start" | "center" | "end";
@@ -988,12 +998,14 @@ type OchreNestedConcept = Omit<OchreConcept, "context" | "availability">;
988
998
  /**
989
999
  * Raw property value structure corresponding to the parsed PropertyValue type
990
1000
  */
991
- type OchrePropertyValueContent = OchreStringContent & {
1001
+ type OchrePropertyValueContent = {
992
1002
  uuid?: string;
993
1003
  publicationDateTime?: string; // YYYY-MM-DDThh:mm:ssZ
994
1004
  type: string;
995
1005
  category?: string;
996
1006
  slug?: FakeString;
1007
+ booleanValue?: boolean;
1008
+ content?: FakeString | OchreStringItem | Array<OchreStringItem>;
997
1009
  };
998
1010
 
999
1011
  /**
@@ -1020,6 +1032,7 @@ type OchreIdentification = {
1020
1032
  heightPreview?: number;
1021
1033
  height?: number;
1022
1034
  width?: number;
1035
+ email?: FakeString;
1023
1036
  website?: string;
1024
1037
  };
1025
1038
 
@@ -1584,7 +1597,7 @@ declare function getPropertyByLabel(properties: Array<Property>, label: string,
1584
1597
  * }
1585
1598
  * ```
1586
1599
  */
1587
- declare function getPropertyValuesByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): Array<string> | null;
1600
+ declare function getPropertyValuesByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): Array<string | number | boolean | Date | null> | null;
1588
1601
  /**
1589
1602
  * Gets the first value of a property with the given label
1590
1603
  *
@@ -1601,7 +1614,7 @@ declare function getPropertyValuesByLabel(properties: Array<Property>, label: st
1601
1614
  * }
1602
1615
  * ```
1603
1616
  */
1604
- declare function getPropertyValueByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): string | null;
1617
+ declare function getPropertyValueByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): string | number | boolean | Date | null;
1605
1618
  /**
1606
1619
  * Gets all unique property labels from an array of properties
1607
1620
  *
@@ -1639,7 +1652,7 @@ declare function getAllPropertyLabels(properties: Array<Property>, options?: Pro
1639
1652
  */
1640
1653
  declare function filterProperties(property: Property, filter: {
1641
1654
  label: string;
1642
- value: string;
1655
+ value: string | number | boolean | Date;
1643
1656
  }, options?: PropertyOptions): boolean;
1644
1657
 
1645
1658
  /**
@@ -1756,6 +1769,7 @@ declare function parseObservations(observations: Array<OchreObservation>): Array
1756
1769
  * @returns Array of parsed Event objects
1757
1770
  */
1758
1771
  declare function parseEvents(events: Array<OchreEvent>): Array<Event>;
1772
+ declare function parseProperty<T extends PropertyValueContentType>(property: OchreProperty, type: T, language?: string): Property;
1759
1773
  /**
1760
1774
  * Parses raw properties into standardized Property objects
1761
1775
  *
@@ -1933,4 +1947,4 @@ declare function parseStringDocumentItem(item: OchreStringRichTextItem, footnote
1933
1947
  */
1934
1948
  declare function parseStringContent(content: OchreStringContent, language?: string): string;
1935
1949
 
1936
- export { type Bibliography, type Concept, type Context, type ContextItem, type ContextNode, type Coordinates, type Data, type Document, type Event, type Footnote, type Gallery, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type License, type Link, type Metadata, type NestedConcept, type NestedResource, type NestedSpatialUnit, type Note, type Observation, type Period, type Person, type Property, type PropertyValue, type PropertyValueContent, type Resource, type Set, type SpatialUnit, type Style, type Tree, type WebBlock, type WebElement, type WebElementComponent, type WebImage, type Webpage, type WebpageProperties, type Website, type WebsiteProperties, fetchBibliography, fetchByUuid, fetchConcept, fetchGallery, fetchPeriod, fetchPropertyValue, fetchResource, fetchSet, fetchSpatialUnit, fetchTree, fetchWebsite, filterProperties, getAllPropertyLabels, getPropertyByLabel, getPropertyValueByLabel, getPropertyValuesByLabel, parseBibliographies, parseBibliography, parseConcept, parseConcepts, parseContext, parseCoordinates, parseDocument, parseEmail, parseEvents, parseFakeString, parseIdentification, parseImage, parseImageMap, parseInterpretations, parseLanguages, parseLicense, parseLink, parseLinks, parseMetadata, parseNotes, parseObservation, parseObservations, parsePeriod, parsePeriods, parsePerson, parsePersons, parseProperties, parsePropertyValue, parsePropertyValues, parseResource, parseResources, parseSet, parseSpatialUnit, parseSpatialUnits, parseStringContent, parseStringDocumentItem, parseStringItem, parseTree, parseWebsite };
1950
+ export { type Bibliography, type Concept, type Context, type ContextItem, type ContextNode, type Coordinates, type Data, type Document, type Event, type Footnote, type Gallery, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type License, type Link, type Metadata, type NestedConcept, type NestedResource, type NestedSpatialUnit, type Note, type Observation, type Period, type Person, type Property, type PropertyValue, type PropertyValueContent, type PropertyValueContentType, type Resource, type ResourceType, type Set, type SpatialUnit, type Style, type Tree, type WebBlock, type WebElement, type WebElementComponent, type WebImage, type Webpage, type WebpageProperties, type Website, type WebsiteProperties, fetchBibliography, fetchByUuid, fetchConcept, fetchGallery, fetchPeriod, fetchPropertyValue, fetchResource, fetchSet, fetchSpatialUnit, fetchTree, fetchWebsite, filterProperties, getAllPropertyLabels, getPropertyByLabel, getPropertyValueByLabel, getPropertyValuesByLabel, parseBibliographies, parseBibliography, parseConcept, parseConcepts, parseContext, parseCoordinates, parseDocument, parseEmail, parseEvents, parseFakeString, parseIdentification, parseImage, parseImageMap, parseInterpretations, parseLanguages, parseLicense, parseLink, parseLinks, parseMetadata, parseNotes, parseObservation, parseObservations, parsePeriod, parsePeriods, parsePerson, parsePersons, parseProperties, parseProperty, parsePropertyValue, parsePropertyValues, parseResource, parseResources, parseSet, parseSpatialUnit, parseSpatialUnits, parseStringContent, parseStringDocumentItem, parseStringItem, parseTree, parseWebsite };
package/dist/index.d.ts CHANGED
@@ -112,7 +112,7 @@ type Link = {
112
112
  uuid: string;
113
113
  publicationDateTime: Date | null;
114
114
  type: string | null;
115
- category: "resource" | "spatialUnit" | "concept" | "set" | "tree" | "person" | "bibliography" | "epigraphicUnit" | "propertyValue" | null;
115
+ category: string | null;
116
116
  identification: Identification | null;
117
117
  content: string | null;
118
118
  href: string | null;
@@ -199,6 +199,10 @@ type Footnote = {
199
199
  label: string;
200
200
  content: string;
201
201
  };
202
+ /**
203
+ * Represents the type of a resource
204
+ */
205
+ type ResourceType = "audio" | "document" | "drawing" | "FITS" | "geospatial" | "IIIF" | "image" | "model" | "PTM" | "TEI" | "video" | "webpage";
202
206
  /**
203
207
  * Represents a resource item with associated metadata, content and relationships
204
208
  */
@@ -206,7 +210,7 @@ type Resource = {
206
210
  uuid: string;
207
211
  category: "resource";
208
212
  publicationDateTime: Date | null;
209
- type: string;
213
+ type: ResourceType;
210
214
  number: number;
211
215
  context: Context | null;
212
216
  license: License | null;
@@ -360,13 +364,15 @@ type PropertyValue = {
360
364
  notes: Array<Note>;
361
365
  links: Array<Link>;
362
366
  };
367
+ type PropertyValueContentType = "string" | "integer" | "decimal" | "boolean" | "date" | "dateTime" | "time" | "coordinate" | "IDREF";
363
368
  /**
364
369
  * Represents a property value with type information
365
370
  */
366
- type PropertyValueContent = {
367
- content: string;
368
- type: "string" | "number" | "integer" | "boolean" | "date" | "dateTime" | "time" | "IDREF";
369
- category: string | null;
371
+ type PropertyValueContent<T extends PropertyValueContentType> = {
372
+ content: T extends "number" ? number : T extends "integer" ? number : T extends "decimal" ? number : T extends "dateTime" ? Date | null : string;
373
+ booleanValue: T extends "boolean" ? boolean : null;
374
+ type: T;
375
+ category: string;
370
376
  uuid: string | null;
371
377
  publicationDateTime: Date | null;
372
378
  };
@@ -375,7 +381,7 @@ type PropertyValueContent = {
375
381
  */
376
382
  type Property = {
377
383
  label: string;
378
- values: Array<PropertyValueContent>;
384
+ values: Array<PropertyValueContent<PropertyValueContentType>>;
379
385
  comment: string | null;
380
386
  properties: Array<Property>;
381
387
  };
@@ -443,6 +449,10 @@ type WebsiteProperties = {
443
449
  type: "traditional" | "digital-collection" | "plum" | "cedar" | "elm" | "maple" | "oak" | "palm";
444
450
  privacy: "public" | "password" | "private";
445
451
  status: "development" | "preview" | "production";
452
+ contact: {
453
+ name: string;
454
+ email: string | null;
455
+ } | null;
446
456
  isHeaderDisplayed: boolean;
447
457
  headerVariant: "default" | "floating" | "inline";
448
458
  headerAlignment: "start" | "center" | "end";
@@ -988,12 +998,14 @@ type OchreNestedConcept = Omit<OchreConcept, "context" | "availability">;
988
998
  /**
989
999
  * Raw property value structure corresponding to the parsed PropertyValue type
990
1000
  */
991
- type OchrePropertyValueContent = OchreStringContent & {
1001
+ type OchrePropertyValueContent = {
992
1002
  uuid?: string;
993
1003
  publicationDateTime?: string; // YYYY-MM-DDThh:mm:ssZ
994
1004
  type: string;
995
1005
  category?: string;
996
1006
  slug?: FakeString;
1007
+ booleanValue?: boolean;
1008
+ content?: FakeString | OchreStringItem | Array<OchreStringItem>;
997
1009
  };
998
1010
 
999
1011
  /**
@@ -1020,6 +1032,7 @@ type OchreIdentification = {
1020
1032
  heightPreview?: number;
1021
1033
  height?: number;
1022
1034
  width?: number;
1035
+ email?: FakeString;
1023
1036
  website?: string;
1024
1037
  };
1025
1038
 
@@ -1584,7 +1597,7 @@ declare function getPropertyByLabel(properties: Array<Property>, label: string,
1584
1597
  * }
1585
1598
  * ```
1586
1599
  */
1587
- declare function getPropertyValuesByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): Array<string> | null;
1600
+ declare function getPropertyValuesByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): Array<string | number | boolean | Date | null> | null;
1588
1601
  /**
1589
1602
  * Gets the first value of a property with the given label
1590
1603
  *
@@ -1601,7 +1614,7 @@ declare function getPropertyValuesByLabel(properties: Array<Property>, label: st
1601
1614
  * }
1602
1615
  * ```
1603
1616
  */
1604
- declare function getPropertyValueByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): string | null;
1617
+ declare function getPropertyValueByLabel(properties: Array<Property>, label: string, options?: PropertyOptions): string | number | boolean | Date | null;
1605
1618
  /**
1606
1619
  * Gets all unique property labels from an array of properties
1607
1620
  *
@@ -1639,7 +1652,7 @@ declare function getAllPropertyLabels(properties: Array<Property>, options?: Pro
1639
1652
  */
1640
1653
  declare function filterProperties(property: Property, filter: {
1641
1654
  label: string;
1642
- value: string;
1655
+ value: string | number | boolean | Date;
1643
1656
  }, options?: PropertyOptions): boolean;
1644
1657
 
1645
1658
  /**
@@ -1756,6 +1769,7 @@ declare function parseObservations(observations: Array<OchreObservation>): Array
1756
1769
  * @returns Array of parsed Event objects
1757
1770
  */
1758
1771
  declare function parseEvents(events: Array<OchreEvent>): Array<Event>;
1772
+ declare function parseProperty<T extends PropertyValueContentType>(property: OchreProperty, type: T, language?: string): Property;
1759
1773
  /**
1760
1774
  * Parses raw properties into standardized Property objects
1761
1775
  *
@@ -1933,4 +1947,4 @@ declare function parseStringDocumentItem(item: OchreStringRichTextItem, footnote
1933
1947
  */
1934
1948
  declare function parseStringContent(content: OchreStringContent, language?: string): string;
1935
1949
 
1936
- export { type Bibliography, type Concept, type Context, type ContextItem, type ContextNode, type Coordinates, type Data, type Document, type Event, type Footnote, type Gallery, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type License, type Link, type Metadata, type NestedConcept, type NestedResource, type NestedSpatialUnit, type Note, type Observation, type Period, type Person, type Property, type PropertyValue, type PropertyValueContent, type Resource, type Set, type SpatialUnit, type Style, type Tree, type WebBlock, type WebElement, type WebElementComponent, type WebImage, type Webpage, type WebpageProperties, type Website, type WebsiteProperties, fetchBibliography, fetchByUuid, fetchConcept, fetchGallery, fetchPeriod, fetchPropertyValue, fetchResource, fetchSet, fetchSpatialUnit, fetchTree, fetchWebsite, filterProperties, getAllPropertyLabels, getPropertyByLabel, getPropertyValueByLabel, getPropertyValuesByLabel, parseBibliographies, parseBibliography, parseConcept, parseConcepts, parseContext, parseCoordinates, parseDocument, parseEmail, parseEvents, parseFakeString, parseIdentification, parseImage, parseImageMap, parseInterpretations, parseLanguages, parseLicense, parseLink, parseLinks, parseMetadata, parseNotes, parseObservation, parseObservations, parsePeriod, parsePeriods, parsePerson, parsePersons, parseProperties, parsePropertyValue, parsePropertyValues, parseResource, parseResources, parseSet, parseSpatialUnit, parseSpatialUnits, parseStringContent, parseStringDocumentItem, parseStringItem, parseTree, parseWebsite };
1950
+ export { type Bibliography, type Concept, type Context, type ContextItem, type ContextNode, type Coordinates, type Data, type Document, type Event, type Footnote, type Gallery, type Identification, type Image, type ImageMap, type ImageMapArea, type Interpretation, type License, type Link, type Metadata, type NestedConcept, type NestedResource, type NestedSpatialUnit, type Note, type Observation, type Period, type Person, type Property, type PropertyValue, type PropertyValueContent, type PropertyValueContentType, type Resource, type ResourceType, type Set, type SpatialUnit, type Style, type Tree, type WebBlock, type WebElement, type WebElementComponent, type WebImage, type Webpage, type WebpageProperties, type Website, type WebsiteProperties, fetchBibliography, fetchByUuid, fetchConcept, fetchGallery, fetchPeriod, fetchPropertyValue, fetchResource, fetchSet, fetchSpatialUnit, fetchTree, fetchWebsite, filterProperties, getAllPropertyLabels, getPropertyByLabel, getPropertyValueByLabel, getPropertyValuesByLabel, parseBibliographies, parseBibliography, parseConcept, parseConcepts, parseContext, parseCoordinates, parseDocument, parseEmail, parseEvents, parseFakeString, parseIdentification, parseImage, parseImageMap, parseInterpretations, parseLanguages, parseLicense, parseLink, parseLinks, parseMetadata, parseNotes, parseObservation, parseObservations, parsePeriod, parsePeriods, parsePerson, parsePersons, parseProperties, parseProperty, parsePropertyValue, parsePropertyValues, parseResource, parseResources, parseSet, parseSpatialUnit, parseSpatialUnits, parseStringContent, parseStringDocumentItem, parseStringItem, parseTree, parseWebsite };
package/dist/index.js CHANGED
@@ -444,9 +444,36 @@ function filterProperties(property, filter, options = DEFAULT_OPTIONS) {
444
444
  const { searchNestedProperties } = options;
445
445
  const isAllFields = filter.label.toLocaleLowerCase("en-US") === "all fields";
446
446
  if (isAllFields || property.label.toLocaleLowerCase("en-US") === filter.label.toLocaleLowerCase("en-US")) {
447
- let isFound = property.values.some(
448
- (value) => value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"))
449
- );
447
+ let isFound = property.values.some((value) => {
448
+ if (value.content === null) {
449
+ return false;
450
+ }
451
+ if (typeof value.content === "string") {
452
+ if (typeof filter.value !== "string") {
453
+ return false;
454
+ }
455
+ return value.content.toLocaleLowerCase("en-US").includes(filter.value.toLocaleLowerCase("en-US"));
456
+ }
457
+ if (typeof value.content === "number") {
458
+ if (typeof filter.value !== "number") {
459
+ return false;
460
+ }
461
+ return value.content === filter.value;
462
+ }
463
+ if (typeof value.content === "boolean") {
464
+ if (typeof filter.value !== "boolean") {
465
+ return false;
466
+ }
467
+ return value.booleanValue === filter.value;
468
+ }
469
+ if (value.content instanceof Date) {
470
+ if (!(filter.value instanceof Date)) {
471
+ return false;
472
+ }
473
+ return value.content.getTime() === filter.value.getTime();
474
+ }
475
+ return false;
476
+ });
450
477
  if (!isFound && searchNestedProperties) {
451
478
  isFound = property.properties.some(
452
479
  (property2) => filterProperties(property2, filter, { searchNestedProperties: true })
@@ -481,6 +508,23 @@ var websiteSchema = z3.object({
481
508
  { message: "Invalid website privacy" }
482
509
  )
483
510
  });
511
+ var resourceTypeSchema = z3.enum(
512
+ [
513
+ "audio",
514
+ "document",
515
+ "drawing",
516
+ "FITS",
517
+ "geospatial",
518
+ "IIIF",
519
+ "image",
520
+ "model",
521
+ "PTM",
522
+ "TEI",
523
+ "video",
524
+ "webpage"
525
+ ],
526
+ { message: "Invalid resource type" }
527
+ );
484
528
  var componentSchema = z3.enum(
485
529
  [
486
530
  "annotated-document",
@@ -794,33 +838,71 @@ function parseEvents(events) {
794
838
  }
795
839
  return returnEvents;
796
840
  }
797
- function parseProperties(properties, language = "eng") {
798
- const returnProperties = [];
799
- for (const property of properties) {
800
- const valuesToParse = "value" in property && property.value ? Array.isArray(property.value) ? property.value : [property.value] : [];
801
- const values = valuesToParse.map(
802
- (value) => !["string", "number", "boolean"].includes(typeof value) && typeof value === "object" ? {
803
- content: value.slug ? parseFakeString(value.slug) : parseStringContent(value),
804
- type: value.type,
805
- category: value.category !== "value" ? value.category ?? null : null,
806
- uuid: value.uuid ?? null,
807
- publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null
808
- } : {
809
- content: parseFakeString(value),
810
- type: "string",
841
+ function parseProperty(property, type, language = "eng") {
842
+ const valuesToParse = "value" in property && property.value ? Array.isArray(property.value) ? property.value : [property.value] : [];
843
+ const values = valuesToParse.map((value) => {
844
+ let content = null;
845
+ let booleanValue = null;
846
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
847
+ content = parseFakeString(value);
848
+ const returnValue = {
849
+ content,
850
+ booleanValue,
851
+ type,
811
852
  category: "value",
812
853
  uuid: null,
813
854
  publicationDateTime: null
855
+ };
856
+ return returnValue;
857
+ } else {
858
+ switch (type) {
859
+ case "integer":
860
+ case "decimal": {
861
+ content = Number(value.content);
862
+ break;
863
+ }
864
+ case "dateTime": {
865
+ content = value.content ? typeof value.content === "string" ? new Date(value.content) : new Date(parseStringContent({ content: value.content })) : null;
866
+ break;
867
+ }
868
+ default: {
869
+ if ("slug" in value && value.slug != null) {
870
+ content = parseFakeString(value.slug);
871
+ } else if (value.content != null) {
872
+ content = parseStringContent({ content: value.content });
873
+ }
874
+ if (type === "boolean") {
875
+ booleanValue = value.booleanValue ?? null;
876
+ }
877
+ break;
878
+ }
814
879
  }
880
+ const returnValue = {
881
+ content,
882
+ booleanValue,
883
+ type,
884
+ category: value.category ?? "value",
885
+ uuid: value.uuid ?? null,
886
+ publicationDateTime: value.publicationDateTime != null ? new Date(value.publicationDateTime) : null
887
+ };
888
+ return returnValue;
889
+ }
890
+ });
891
+ return {
892
+ label: parseStringContent(property.label, language).replace(/\s*\.{3}$/, "").trim(),
893
+ values,
894
+ comment: property.comment != null ? parseFakeString(property.comment) : null,
895
+ properties: property.property ? parseProperties(
896
+ Array.isArray(property.property) ? property.property : [property.property]
897
+ ) : []
898
+ };
899
+ }
900
+ function parseProperties(properties, language = "eng") {
901
+ const returnProperties = [];
902
+ for (const property of properties) {
903
+ returnProperties.push(
904
+ parseProperty(property, "string", language)
815
905
  );
816
- returnProperties.push({
817
- label: parseStringContent(property.label, language).replace(/\s*\.{3}$/, "").trim(),
818
- values,
819
- comment: property.comment != null ? parseFakeString(property.comment) : null,
820
- properties: property.property ? parseProperties(
821
- Array.isArray(property.property) ? property.property : [property.property]
822
- ) : []
823
- });
824
906
  }
825
907
  return returnProperties;
826
908
  }
@@ -877,10 +959,13 @@ function parsePeriods(periods) {
877
959
  function parseBibliography(bibliography) {
878
960
  let resource = null;
879
961
  if (bibliography.source?.resource) {
962
+ const resourceType = resourceTypeSchema.parse(
963
+ bibliography.source.resource.type
964
+ );
880
965
  resource = {
881
966
  uuid: bibliography.source.resource.uuid,
882
967
  publicationDateTime: bibliography.source.resource.publicationDateTime ? new Date(bibliography.source.resource.publicationDateTime) : null,
883
- type: bibliography.source.resource.type,
968
+ type: resourceType,
884
969
  identification: parseIdentification(
885
970
  bibliography.source.resource.identification
886
971
  )
@@ -1123,11 +1208,12 @@ function parseSet(set) {
1123
1208
  };
1124
1209
  }
1125
1210
  function parseResource(resource, isNested = false) {
1211
+ const resourceType = resourceTypeSchema.parse(resource.type);
1126
1212
  const returnResource = {
1127
1213
  uuid: resource.uuid,
1128
1214
  category: "resource",
1129
1215
  publicationDateTime: resource.publicationDateTime ? new Date(resource.publicationDateTime) : null,
1130
- type: resource.type,
1216
+ type: resourceType,
1131
1217
  number: resource.n,
1132
1218
  format: resource.format ?? null,
1133
1219
  context: "context" in resource && resource.context ? parseContext(resource.context) : null,
@@ -1564,7 +1650,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1564
1650
  "width"
1565
1651
  );
1566
1652
  if (widthProperty !== null) {
1567
- width = Number.parseFloat(widthProperty);
1653
+ if (typeof widthProperty === "number") {
1654
+ width = widthProperty;
1655
+ } else if (typeof widthProperty === "string") {
1656
+ width = Number.parseFloat(widthProperty);
1657
+ }
1568
1658
  }
1569
1659
  let height = null;
1570
1660
  const heightProperty = getPropertyValueByLabel(
@@ -1572,7 +1662,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1572
1662
  "height"
1573
1663
  );
1574
1664
  if (heightProperty !== null) {
1575
- height = Number.parseFloat(heightProperty);
1665
+ if (typeof heightProperty === "number") {
1666
+ height = heightProperty;
1667
+ } else if (typeof heightProperty === "string") {
1668
+ height = Number.parseFloat(heightProperty);
1669
+ }
1576
1670
  }
1577
1671
  let isFullWidth = true;
1578
1672
  const isFullWidthProperty = getPropertyValueByLabel(
@@ -1634,7 +1728,11 @@ async function parseWebElementProperties(componentProperty, elementResource) {
1634
1728
  "seconds-per-image"
1635
1729
  );
1636
1730
  if (secondsPerImageProperty !== null) {
1637
- secondsPerImage = Number.parseFloat(secondsPerImageProperty);
1731
+ if (typeof secondsPerImageProperty === "number") {
1732
+ secondsPerImage = secondsPerImageProperty;
1733
+ } else if (typeof secondsPerImageProperty === "string") {
1734
+ secondsPerImage = Number.parseFloat(secondsPerImageProperty);
1735
+ }
1638
1736
  }
1639
1737
  }
1640
1738
  carouselOptions = {
@@ -1889,7 +1987,7 @@ async function parseWebpage(webpageResource) {
1889
1987
  resourceProperties,
1890
1988
  "presentation"
1891
1989
  );
1892
- if (!resourceType) {
1990
+ if (resourceType == null) {
1893
1991
  continue;
1894
1992
  }
1895
1993
  switch (resourceType) {
@@ -2070,7 +2168,7 @@ async function parseBlock(blockResource) {
2070
2168
  resourceProperties,
2071
2169
  "presentation"
2072
2170
  );
2073
- if (!resourceType) {
2171
+ if (resourceType == null) {
2074
2172
  continue;
2075
2173
  }
2076
2174
  switch (resourceType) {
@@ -2143,6 +2241,16 @@ function parseWebsiteProperties(properties) {
2143
2241
  if (!result.success) {
2144
2242
  throw new Error(`Invalid website properties: ${result.error.message}`);
2145
2243
  }
2244
+ let contact = null;
2245
+ const contactProperty = websiteProperties.find(
2246
+ (property) => property.label === "contact"
2247
+ );
2248
+ if (contactProperty) {
2249
+ const [name, email] = (contactProperty.values[0]?.content).split(
2250
+ ";"
2251
+ );
2252
+ contact = { name, email: email ?? null };
2253
+ }
2146
2254
  const logoUuid = websiteProperties.find((property) => property.label === "logo")?.values[0]?.uuid ?? null;
2147
2255
  let isHeaderDisplayed = true;
2148
2256
  let headerVariant = "default";
@@ -2209,6 +2317,7 @@ function parseWebsiteProperties(properties) {
2209
2317
  type: validatedType,
2210
2318
  privacy: validatedPrivacy,
2211
2319
  status: validatedStatus,
2320
+ contact,
2212
2321
  isHeaderDisplayed,
2213
2322
  headerVariant,
2214
2323
  headerAlignment,
@@ -2678,6 +2787,7 @@ export {
2678
2787
  parsePerson,
2679
2788
  parsePersons,
2680
2789
  parseProperties,
2790
+ parseProperty,
2681
2791
  parsePropertyValue,
2682
2792
  parsePropertyValues,
2683
2793
  parseResource,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalculture/ochre-sdk",
3
- "version": "0.5.17",
3
+ "version": "0.5.18",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",
@@ -41,12 +41,12 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "iso-639-3": "^3.0.1",
44
- "zod": "^3.24.2"
44
+ "zod": "^3.24.3"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@antfu/eslint-config": "^4.12.0",
48
48
  "@arethetypeswrong/cli": "^0.17.4",
49
- "@changesets/cli": "^2.29.1",
49
+ "@changesets/cli": "^2.29.2",
50
50
  "@total-typescript/ts-reset": "^0.6.1",
51
51
  "@types/node": "^22.14.1",
52
52
  "eslint": "^9.24.0",