ochre-sdk 0.20.30 → 0.21.1

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.d.mts CHANGED
@@ -671,9 +671,9 @@ type SetItemsSort = {
671
671
  language?: string;
672
672
  };
673
673
  /**
674
- * Represents a query for Set items
674
+ * Represents a leaf query for Set items
675
675
  */
676
- type Query = {
676
+ type QueryLeaf = {
677
677
  target: "property";
678
678
  propertyVariables?: Array<string>;
679
679
  dataType: Exclude<Exclude<PropertyValueContentType, "coordinate">, "date" | "dateTime">;
@@ -683,7 +683,6 @@ type Query = {
683
683
  matchMode: "includes" | "exact";
684
684
  isCaseSensitive: boolean;
685
685
  language: string;
686
- operator?: "AND" | "OR";
687
686
  isNegated?: boolean;
688
687
  } | {
689
688
  target: "property";
@@ -695,7 +694,6 @@ type Query = {
695
694
  matchMode: "includes" | "exact";
696
695
  isCaseSensitive: boolean;
697
696
  language: string;
698
- operator?: "AND" | "OR";
699
697
  isNegated?: boolean;
700
698
  } | {
701
699
  target: "property";
@@ -707,7 +705,6 @@ type Query = {
707
705
  matchMode: "includes" | "exact";
708
706
  isCaseSensitive: boolean;
709
707
  language: string;
710
- operator?: "AND" | "OR";
711
708
  isNegated?: boolean;
712
709
  } | {
713
710
  target: "string";
@@ -715,7 +712,6 @@ type Query = {
715
712
  matchMode: "includes" | "exact";
716
713
  isCaseSensitive: boolean;
717
714
  language: string;
718
- operator?: "AND" | "OR";
719
715
  isNegated?: boolean;
720
716
  } | {
721
717
  target: "title" | "description" | "image" | "periods" | "bibliography";
@@ -723,9 +719,20 @@ type Query = {
723
719
  matchMode: "includes" | "exact";
724
720
  isCaseSensitive: boolean;
725
721
  language: string;
726
- operator?: "AND" | "OR";
727
722
  isNegated?: boolean;
728
723
  };
724
+ /**
725
+ * Represents a boolean query group for Set items
726
+ */
727
+ type QueryGroup = {
728
+ and: Array<Query>;
729
+ } | {
730
+ or: Array<Query>;
731
+ };
732
+ /**
733
+ * Represents a query for Set items
734
+ */
735
+ type Query = QueryLeaf | QueryGroup;
729
736
  //#endregion
730
737
  //#region src/types/website.d.ts
731
738
  /**
@@ -764,6 +771,28 @@ type Scope = {
764
771
  type: string;
765
772
  identification: Identification;
766
773
  };
774
+ /**
775
+ * Represents a stylesheet item with its UUID and category
776
+ */
777
+ type StylesheetCategory = Extract<DataCategory, "propertyVariable" | "propertyValue">;
778
+ type StylesheetItem = {
779
+ uuid: string;
780
+ category: "propertyVariable";
781
+ styles: {
782
+ default: Array<Style>;
783
+ tablet: Array<Style>;
784
+ mobile: Array<Style>;
785
+ };
786
+ } | {
787
+ uuid: string;
788
+ category: "propertyValue";
789
+ variableUuid: string;
790
+ styles: {
791
+ default: Array<Style>;
792
+ tablet: Array<Style>;
793
+ mobile: Array<Style>;
794
+ };
795
+ };
767
796
  /**
768
797
  * Represents the OCHRE website type
769
798
  */
@@ -811,6 +840,7 @@ type Website = {
811
840
  };
812
841
  footer: {
813
842
  isDisplayed: boolean;
843
+ logoUuid: string | null;
814
844
  items: Array<WebElement | WebBlock> | null;
815
845
  };
816
846
  sidebar: {
@@ -843,6 +873,9 @@ type Website = {
843
873
  labels: {
844
874
  title: string | null;
845
875
  };
876
+ stylesheets: {
877
+ properties: Array<StylesheetItem>;
878
+ };
846
879
  };
847
880
  };
848
881
  };
@@ -1234,7 +1267,7 @@ declare function fetchItem<T extends DataCategory = DataCategory, U extends Data
1234
1267
  *
1235
1268
  * @param params - The parameters for the fetch
1236
1269
  * @param params.setScopeUuids - The Set scope UUIDs to filter by
1237
- * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
1270
+ * @param params.queries - Recursive query tree used to filter matching items
1238
1271
  * @param params.sort - Optional sorting configuration applied before pagination.
1239
1272
  * For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
1240
1273
  * @param params.page - The page number (1-indexed)
@@ -1247,7 +1280,7 @@ declare function fetchItem<T extends DataCategory = DataCategory, U extends Data
1247
1280
  */
1248
1281
  declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategory>>(params: {
1249
1282
  setScopeUuids: Array<string>;
1250
- queries: Array<Query>;
1283
+ queries?: Query | null;
1251
1284
  sort?: SetItemsSort;
1252
1285
  page: number;
1253
1286
  pageSize?: number;
@@ -1274,7 +1307,7 @@ declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategor
1274
1307
  *
1275
1308
  * @param params - The parameters for the fetch
1276
1309
  * @param params.setScopeUuids - An array of set scope UUIDs to filter by
1277
- * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
1310
+ * @param params.queries - Recursive query tree used to filter matching items
1278
1311
  * @param params.attributes - Whether to return values for bibliographies and periods
1279
1312
  * @param params.attributes.bibliographies - Whether to return values for bibliographies
1280
1313
  * @param params.attributes.periods - Whether to return values for periods
@@ -1287,7 +1320,7 @@ declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategor
1287
1320
  */
1288
1321
  declare function fetchSetPropertyValues(params: {
1289
1322
  setScopeUuids: Array<string>;
1290
- queries?: Array<Query>;
1323
+ queries?: Query | null;
1291
1324
  attributes?: {
1292
1325
  bibliographies: boolean;
1293
1326
  periods: boolean;
@@ -1470,4 +1503,4 @@ declare const DEFAULT_PAGE_SIZE = 48;
1470
1503
  */
1471
1504
  declare function flattenItemProperties<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(item: Item<T, U>): Item<T, U>;
1472
1505
  //#endregion
1473
- export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, LevelContext, LevelContextItem, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyContexts, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsiteType, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
1506
+ export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, LevelContext, LevelContextItem, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyContexts, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, QueryGroup, QueryLeaf, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, StylesheetCategory, StylesheetItem, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsiteType, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
package/dist/index.mjs CHANGED
@@ -190,7 +190,7 @@ function extractAnnotationMetadata(item) {
190
190
  result.linkVariant = "entry-page";
191
191
  break;
192
192
  default: if (textAnnotationPropertyValueUuid === "3e6f86ab-df81-45ae-8257-e2867357df56" && textAnnotationProperty.property != null) {
193
- let textStylingVariant = "block";
193
+ let textStylingVariant = "paragraph";
194
194
  let textStylingSize = "md";
195
195
  let textStylingHeadingLevel = null;
196
196
  let textStylingCss = [];
@@ -371,7 +371,7 @@ function parseStringDocumentItem(item) {
371
371
  if (textAnnotationProperty != null) {
372
372
  if ((typeof textAnnotationProperty.value === "object" && "uuid" in textAnnotationProperty.value && textAnnotationProperty.value.uuid != null ? textAnnotationProperty.value.uuid : null) === "3e6f86ab-df81-45ae-8257-e2867357df56" && textAnnotationProperty.property != null) {
373
373
  const textStylingType = "text-styling";
374
- let textStylingVariant = "block";
374
+ let textStylingVariant = "paragraph";
375
375
  let textStylingSize = "md";
376
376
  let textStylingHeadingLevel = null;
377
377
  let textStylingCss = [];
@@ -756,7 +756,7 @@ const boundsSchema = z.string().transform((str, ctx) => {
756
756
  * Shared schema for Set queries
757
757
  * @internal
758
758
  */
759
- const setQuerySchema = z.union([
759
+ const setQueryLeafSchema = z.union([
760
760
  z.object({
761
761
  target: z.literal("property"),
762
762
  propertyVariables: z.array(uuidSchema).default([]),
@@ -772,7 +772,6 @@ const setQuerySchema = z.union([
772
772
  matchMode: z.enum(["includes", "exact"]),
773
773
  isCaseSensitive: z.boolean(),
774
774
  language: z.string().default("eng"),
775
- operator: z.enum(["AND", "OR"]).optional(),
776
775
  isNegated: z.boolean().optional().default(false)
777
776
  }).strict().superRefine((value, ctx) => {
778
777
  if (value.propertyVariables.length === 0 && value.propertyValues == null) ctx.addIssue({
@@ -789,7 +788,6 @@ const setQuerySchema = z.union([
789
788
  matchMode: z.enum(["includes", "exact"]),
790
789
  isCaseSensitive: z.boolean(),
791
790
  language: z.string().default("eng"),
792
- operator: z.enum(["AND", "OR"]).optional(),
793
791
  isNegated: z.boolean().optional().default(false)
794
792
  }).strict(),
795
793
  z.object({
@@ -801,7 +799,6 @@ const setQuerySchema = z.union([
801
799
  matchMode: z.enum(["includes", "exact"]),
802
800
  isCaseSensitive: z.boolean(),
803
801
  language: z.string().default("eng"),
804
- operator: z.enum(["AND", "OR"]).optional(),
805
802
  isNegated: z.boolean().optional().default(false)
806
803
  }).strict(),
807
804
  z.object({
@@ -810,7 +807,6 @@ const setQuerySchema = z.union([
810
807
  matchMode: z.enum(["includes", "exact"]),
811
808
  isCaseSensitive: z.boolean(),
812
809
  language: z.string().default("eng"),
813
- operator: z.enum(["AND", "OR"]).optional(),
814
810
  isNegated: z.boolean().optional().default(false)
815
811
  }).strict(),
816
812
  z.object({
@@ -825,11 +821,15 @@ const setQuerySchema = z.union([
825
821
  matchMode: z.enum(["includes", "exact"]),
826
822
  isCaseSensitive: z.boolean(),
827
823
  language: z.string().default("eng"),
828
- operator: z.enum(["AND", "OR"]).optional(),
829
824
  isNegated: z.boolean().optional().default(false)
830
825
  }).strict()
831
826
  ]);
832
- const setQueriesSchema = z.array(setQuerySchema).default([]);
827
+ const setQuerySchema = z.lazy(() => z.union([
828
+ setQueryLeafSchema,
829
+ z.object({ and: z.array(setQuerySchema).min(1, "AND groups must contain at least one query") }).strict(),
830
+ z.object({ or: z.array(setQuerySchema).min(1, "OR groups must contain at least one query") }).strict()
831
+ ]));
832
+ const setQueriesSchema = setQuerySchema.nullable().default(null);
833
833
  const setItemsSortSchema = z.discriminatedUnion("target", [
834
834
  z.object({ target: z.literal("none") }).strict(),
835
835
  z.object({
@@ -854,16 +854,12 @@ const setItemsSortSchema = z.discriminatedUnion("target", [
854
854
  language: z.string().default("eng")
855
855
  }).strict()
856
856
  ]).default({ target: "none" });
857
- function validateSetQueriesOperators(queries, ctx) {
858
- for (const [index, query] of queries.entries()) if (index > 0 && query.operator == null) ctx.addIssue({
859
- code: "custom",
860
- path: [
861
- "queries",
862
- index,
863
- "operator"
864
- ],
865
- message: "Query rules after the first must include an operator"
866
- });
857
+ function hasPropertyQueryWithPropertyVariables(query) {
858
+ if (query == null) return false;
859
+ if ("target" in query) return query.target === "property" && (query.propertyVariables?.length ?? 0) > 0;
860
+ const groupQueries = "and" in query ? query.and : query.or;
861
+ for (const groupQuery of groupQueries) if (hasPropertyQueryWithPropertyVariables(groupQuery)) return true;
862
+ return false;
867
863
  }
868
864
  /**
869
865
  * Schema for validating the parameters for the Set property values fetching function
@@ -882,8 +878,7 @@ const setPropertyValuesParamsSchema = z.object({
882
878
  }),
883
879
  isLimitedToLeafPropertyValues: z.boolean().default(false)
884
880
  }).superRefine((value, ctx) => {
885
- validateSetQueriesOperators(value.queries, ctx);
886
- if (!value.queries.some((query) => query.target === "property" && query.propertyVariables.length > 0)) ctx.addIssue({
881
+ if (!hasPropertyQueryWithPropertyVariables(value.queries)) ctx.addIssue({
887
882
  code: "custom",
888
883
  path: ["queries"],
889
884
  message: "At least one property query with propertyVariables is required"
@@ -896,8 +891,6 @@ const setItemsParamsSchema = z.object({
896
891
  sort: setItemsSortSchema,
897
892
  page: z.number().min(1, "Page must be positive").default(1),
898
893
  pageSize: z.number().min(1, "Page size must be positive").default(48)
899
- }).superRefine((value, ctx) => {
900
- validateSetQueriesOperators(value.queries, ctx);
901
894
  });
902
895
  //#endregion
903
896
  //#region src/utils/parse/index.ts
@@ -2409,51 +2402,14 @@ function buildOrCtsQueryExpression(queries) {
2409
2402
  if (queries.length === 1) return queries[0] ?? "cts:false-query()";
2410
2403
  return `cts:or-query((${queries.join(", ")}))`;
2411
2404
  }
2412
- function buildPredicateGroups(predicateParts) {
2413
- const groups = [];
2414
- let currentGroup = [];
2415
- for (const predicatePart of predicateParts) {
2416
- if (predicatePart.operator == null || predicatePart.operator === "AND") {
2417
- currentGroup.push(predicatePart.predicate);
2418
- continue;
2419
- }
2420
- if (currentGroup.length > 0) groups.push(currentGroup);
2421
- currentGroup = [predicatePart.predicate];
2422
- }
2423
- if (currentGroup.length > 0) groups.push(currentGroup);
2424
- return groups;
2425
- }
2426
- function buildGroupedPredicateExpression(predicateGroups) {
2427
- if (predicateGroups.length === 0) return "";
2428
- const groupExpressions = [];
2429
- for (let index = 0; index < predicateGroups.length;) {
2430
- const predicateGroup = predicateGroups[index];
2431
- const firstPredicate = predicateGroup?.[0];
2432
- if (predicateGroup == null || predicateGroup.length < 2 || firstPredicate == null) {
2433
- groupExpressions.push(buildAndPredicate(predicateGroup ?? []));
2434
- index += 1;
2435
- continue;
2436
- }
2437
- let sharedGroupEnd = index + 1;
2438
- while (sharedGroupEnd < predicateGroups.length) {
2439
- const sharedGroup = predicateGroups[sharedGroupEnd];
2440
- if (sharedGroup == null || sharedGroup.length < 2 || sharedGroup[0] !== firstPredicate) break;
2441
- sharedGroupEnd += 1;
2442
- }
2443
- if (sharedGroupEnd === index + 1) {
2444
- groupExpressions.push(buildAndPredicate(predicateGroup));
2445
- index += 1;
2446
- continue;
2447
- }
2448
- const suffixGroupExpressions = [];
2449
- for (const sharedGroup of predicateGroups.slice(index, sharedGroupEnd)) {
2450
- const suffixPredicates = sharedGroup.slice(1);
2451
- suffixGroupExpressions.push(buildAndPredicate(suffixPredicates));
2452
- }
2453
- groupExpressions.push(buildAndPredicate([firstPredicate, buildOrPredicate(suffixGroupExpressions)]));
2454
- index = sharedGroupEnd;
2455
- }
2456
- return buildOrPredicate(groupExpressions);
2405
+ function isQueryLeaf(query) {
2406
+ return "target" in query;
2407
+ }
2408
+ function getQueryGroupChildren(query) {
2409
+ return "and" in query ? query.and : query.or;
2410
+ }
2411
+ function getQueryGroupOperator(query) {
2412
+ return "and" in query ? "and" : "or";
2457
2413
  }
2458
2414
  function buildContentTargetCandidateBranch(params) {
2459
2415
  const { containerElementName, termExpression, isCaseSensitive, language } = params;
@@ -2607,31 +2563,32 @@ function buildIncludesGroupMember(query) {
2607
2563
  case "property": return buildPropertyStringIncludesGroupMember(query);
2608
2564
  }
2609
2565
  }
2610
- function findCompatibleIncludesGroup(params) {
2611
- const { queries, startIndex, version } = params;
2612
- const startQuery = queries[startIndex];
2613
- if (startQuery == null) return null;
2614
- const groupValue = getGroupableIncludesValue(startQuery);
2566
+ function getCompatibleIncludesGroupLeaves(params) {
2567
+ const { query, version } = params;
2568
+ if (!("or" in query) || query.or.length <= 1) return null;
2569
+ const leafQueries = [];
2570
+ for (const childQuery of query.or) {
2571
+ if (!isQueryLeaf(childQuery)) return null;
2572
+ leafQueries.push(childQuery);
2573
+ }
2574
+ const firstQuery = leafQueries[0];
2575
+ if (firstQuery == null) return null;
2576
+ const groupValue = getGroupableIncludesValue(firstQuery);
2615
2577
  if (groupValue == null || !isCompatibleIncludesGroupQuery({
2616
- query: startQuery,
2578
+ query: firstQuery,
2617
2579
  value: groupValue,
2618
- isCaseSensitive: startQuery.isCaseSensitive,
2619
- language: startQuery.language,
2580
+ isCaseSensitive: firstQuery.isCaseSensitive,
2581
+ language: firstQuery.language,
2620
2582
  version
2621
- }) || startIndex > 0 && queries[startIndex]?.operator === "AND") return null;
2622
- const groupedQueries = [startQuery];
2623
- for (let index = startIndex + 1; index < queries.length; index += 1) {
2624
- const query = queries[index];
2625
- if (query?.operator !== "OR" || !isCompatibleIncludesGroupQuery({
2626
- query,
2627
- value: groupValue,
2628
- isCaseSensitive: startQuery.isCaseSensitive,
2629
- language: startQuery.language,
2630
- version
2631
- })) break;
2632
- groupedQueries.push(query);
2633
- }
2634
- return groupedQueries.length > 1 ? groupedQueries : null;
2583
+ })) return null;
2584
+ for (const leafQuery of leafQueries.slice(1)) if (!isCompatibleIncludesGroupQuery({
2585
+ query: leafQuery,
2586
+ value: groupValue,
2587
+ isCaseSensitive: firstQuery.isCaseSensitive,
2588
+ language: firstQuery.language,
2589
+ version
2590
+ })) return null;
2591
+ return leafQueries;
2635
2592
  }
2636
2593
  function buildIncludesGroupClause(params) {
2637
2594
  const { queries, queryKey } = params;
@@ -2889,7 +2846,7 @@ function buildQueryClause(params) {
2889
2846
  /**
2890
2847
  * Build a boolean query clause for an XQuery string.
2891
2848
  */
2892
- function buildBooleanQueryClause(params) {
2849
+ function buildBooleanQueryNode(params) {
2893
2850
  const { query, version, queryKey } = params;
2894
2851
  const compiledQueryClause = buildQueryClause({
2895
2852
  query,
@@ -2900,51 +2857,79 @@ function buildBooleanQueryClause(params) {
2900
2857
  return {
2901
2858
  declarations: compiledQueryClause.declarations,
2902
2859
  predicate: query.isNegated ? `not(${baseClause})` : baseClause,
2903
- candidateQueryVar: query.isNegated ? null : compiledQueryClause.candidateQueryVar
2860
+ candidateQueryVars: query.isNegated || compiledQueryClause.candidateQueryVar == null ? [] : [compiledQueryClause.candidateQueryVar]
2904
2861
  };
2905
2862
  }
2906
- function buildQueryPlan(params) {
2907
- const { queries, version, baseItemsExpression } = params;
2863
+ function buildQueryNode(params) {
2864
+ const { query, version, queryKey } = params;
2865
+ if (isQueryLeaf(query)) return buildBooleanQueryNode({
2866
+ query,
2867
+ version,
2868
+ queryKey
2869
+ });
2870
+ const groupQueries = getQueryGroupChildren(query);
2871
+ const optimizedIncludesGroupQueries = getCompatibleIncludesGroupLeaves({
2872
+ query,
2873
+ version
2874
+ });
2875
+ if (groupQueries.length === 1) {
2876
+ const onlyQuery = groupQueries[0];
2877
+ if (onlyQuery == null) return {
2878
+ declarations: [],
2879
+ predicate: "",
2880
+ candidateQueryVars: []
2881
+ };
2882
+ return buildQueryNode({
2883
+ query: onlyQuery,
2884
+ version,
2885
+ queryKey
2886
+ });
2887
+ }
2888
+ if (optimizedIncludesGroupQueries != null) {
2889
+ const compiledClause = buildIncludesGroupClause({
2890
+ queries: optimizedIncludesGroupQueries,
2891
+ queryKey
2892
+ });
2893
+ return {
2894
+ declarations: compiledClause.declarations,
2895
+ predicate: compiledClause.predicate,
2896
+ candidateQueryVars: compiledClause.candidateQueryVar == null ? [] : [compiledClause.candidateQueryVar]
2897
+ };
2898
+ }
2908
2899
  const declarations = [];
2909
- const predicateParts = [];
2900
+ const predicates = [];
2910
2901
  const candidateQueryVars = [];
2911
- let hasCtsIncludesClauses = false;
2912
- for (let index = 0; index < queries.length;) {
2913
- const groupedQueries = findCompatibleIncludesGroup({
2914
- queries,
2915
- startIndex: index,
2916
- version
2917
- });
2918
- const query = queries[index];
2919
- if (query == null) break;
2920
- const compiledClause = groupedQueries != null ? buildIncludesGroupClause({
2921
- queries: groupedQueries,
2922
- queryKey: `${index + 1}`
2923
- }) : buildBooleanQueryClause({
2924
- query,
2902
+ for (const [groupIndex, groupQuery] of groupQueries.entries()) {
2903
+ const compiledQueryNode = buildQueryNode({
2904
+ query: groupQuery,
2925
2905
  version,
2926
- queryKey: `${index + 1}`
2906
+ queryKey: `${queryKey}_${groupIndex + 1}`
2927
2907
  });
2928
- if (compiledClause.declarations.length > 0) {
2929
- hasCtsIncludesClauses = true;
2930
- declarations.push(...compiledClause.declarations);
2931
- }
2932
- if (compiledClause.candidateQueryVar != null) candidateQueryVars.push(compiledClause.candidateQueryVar);
2933
- if (index === 0) {
2934
- predicateParts.push({
2935
- operator: null,
2936
- predicate: compiledClause.predicate
2937
- });
2938
- index += groupedQueries?.length ?? 1;
2939
- continue;
2940
- }
2941
- predicateParts.push({
2942
- operator: query.operator ?? "OR",
2943
- predicate: compiledClause.predicate
2908
+ declarations.push(...compiledQueryNode.declarations);
2909
+ predicates.push(compiledQueryNode.predicate);
2910
+ candidateQueryVars.push(...compiledQueryNode.candidateQueryVars);
2911
+ }
2912
+ return {
2913
+ declarations,
2914
+ predicate: getQueryGroupOperator(query) === "and" ? buildAndPredicate(predicates) : buildOrPredicate(predicates),
2915
+ candidateQueryVars
2916
+ };
2917
+ }
2918
+ function buildQueryPlan(params) {
2919
+ const { queries, version, baseItemsExpression } = params;
2920
+ const declarations = [];
2921
+ let predicate = "";
2922
+ let candidateQueryVars = [];
2923
+ if (queries != null) {
2924
+ const compiledQueryNode = buildQueryNode({
2925
+ query: queries,
2926
+ version,
2927
+ queryKey: "1"
2944
2928
  });
2945
- index += groupedQueries?.length ?? 1;
2929
+ if (compiledQueryNode.declarations.length > 0) declarations.push(`let ${CTS_INCLUDES_STOP_WORDS_VAR} := (${CTS_INCLUDES_STOP_WORDS.map((stopWord) => stringLiteral(stopWord)).join(", ")})`, ...compiledQueryNode.declarations);
2930
+ predicate = compiledQueryNode.predicate;
2931
+ candidateQueryVars = compiledQueryNode.candidateQueryVars;
2946
2932
  }
2947
- if (hasCtsIncludesClauses) declarations.unshift(`let ${CTS_INCLUDES_STOP_WORDS_VAR} := (${CTS_INCLUDES_STOP_WORDS.map((stopWord) => stringLiteral(stopWord)).join(", ")})`);
2948
2933
  let itemsExpression = `(${baseItemsExpression})`;
2949
2934
  if (candidateQueryVars.length > 0) {
2950
2935
  const candidateQueriesExpression = `(${candidateQueryVars.join(", ")})`;
@@ -2962,7 +2947,7 @@ function buildQueryPlan(params) {
2962
2947
  return {
2963
2948
  declarations,
2964
2949
  itemsExpression,
2965
- predicate: buildGroupedPredicateExpression(buildPredicateGroups(predicateParts))
2950
+ predicate
2966
2951
  };
2967
2952
  }
2968
2953
  //#endregion
@@ -3042,7 +3027,7 @@ function buildOrderedItemsClause(sort) {
3042
3027
  * @param params - The parameters for the fetch
3043
3028
  * @param params.setScopeUuids - An array of Set scope UUIDs to filter by
3044
3029
  * @param params.belongsToCollectionScopeUuids - An array of collection scope UUIDs to filter by
3045
- * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
3030
+ * @param params.queries - Recursive query tree used to filter matching items
3046
3031
  * @param params.sort - Optional sorting configuration applied before pagination.
3047
3032
  * For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
3048
3033
  * @param params.page - The page number (1-indexed)
@@ -3088,7 +3073,7 @@ function buildXQuery$1(params, options) {
3088
3073
  *
3089
3074
  * @param params - The parameters for the fetch
3090
3075
  * @param params.setScopeUuids - The Set scope UUIDs to filter by
3091
- * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
3076
+ * @param params.queries - Recursive query tree used to filter matching items
3092
3077
  * @param params.sort - Optional sorting configuration applied before pagination.
3093
3078
  * For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
3094
3079
  * @param params.page - The page number (1-indexed)
@@ -3267,9 +3252,15 @@ function aggregateAttributeValues(values) {
3267
3252
  }
3268
3253
  function getPropertyVariableUuidsFromQueries(queries) {
3269
3254
  const propertyVariableUuids = /* @__PURE__ */ new Set();
3270
- for (const query of queries) {
3271
- if (query.target !== "property") continue;
3272
- for (const propertyVariableUuid of query.propertyVariables ?? []) propertyVariableUuids.add(propertyVariableUuid);
3255
+ if (queries == null) return [];
3256
+ const pendingQueries = [queries];
3257
+ for (const query of pendingQueries) {
3258
+ if ("target" in query) {
3259
+ if (query.target !== "property") continue;
3260
+ for (const propertyVariableUuid of query.propertyVariables ?? []) propertyVariableUuids.add(propertyVariableUuid);
3261
+ continue;
3262
+ }
3263
+ pendingQueries.push(..."and" in query ? query.and : query.or);
3273
3264
  }
3274
3265
  return [...propertyVariableUuids];
3275
3266
  }
@@ -3341,7 +3332,7 @@ const responseSchema = z.object({ result: z.union([z.object({ ochre: z.object({
3341
3332
  * @param params - The parameters for the fetch
3342
3333
  * @param params.setScopeUuids - An array of set scope UUIDs to filter by
3343
3334
  * @param params.belongsToCollectionScopeUuids - An array of collection scope UUIDs to filter by
3344
- * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
3335
+ * @param params.queries - Recursive query tree used to filter matching items
3345
3336
  * @param params.attributes - Whether to return values for bibliographies and periods
3346
3337
  * @param params.attributes.bibliographies - Whether to return values for bibliographies
3347
3338
  * @param params.attributes.periods - Whether to return values for periods
@@ -3409,7 +3400,7 @@ return (${returnedSequences.join(", ")})`}}</ochre>`;
3409
3400
  *
3410
3401
  * @param params - The parameters for the fetch
3411
3402
  * @param params.setScopeUuids - An array of set scope UUIDs to filter by
3412
- * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
3403
+ * @param params.queries - Recursive query tree used to filter matching items
3413
3404
  * @param params.attributes - Whether to return values for bibliographies and periods
3414
3405
  * @param params.attributes.bibliographies - Whether to return values for bibliographies
3415
3406
  * @param params.attributes.periods - Whether to return values for periods
@@ -3818,6 +3809,37 @@ function parseAllOptionContexts(options) {
3818
3809
  prominent: handleContexts(options.prominentContexts)
3819
3810
  };
3820
3811
  }
3812
+ function parseStylesheets(styles) {
3813
+ return styles.map((style) => {
3814
+ const defaultStyles = [];
3815
+ for (const [label, value] of Object.entries(style)) {
3816
+ if (label === "variableUuid" || label === "valueUuid" || label === "category" || label === "content") continue;
3817
+ defaultStyles.push({
3818
+ label,
3819
+ value: parseFakeString(value)
3820
+ });
3821
+ }
3822
+ const stylesByViewport = {
3823
+ default: defaultStyles,
3824
+ tablet: [],
3825
+ mobile: []
3826
+ };
3827
+ if (style.category === "propertyValue" || style.valueUuid != null) {
3828
+ if (style.valueUuid == null) throw new Error(`Stylesheet property value "${style.variableUuid}" is missing a value UUID`);
3829
+ return {
3830
+ uuid: style.valueUuid,
3831
+ category: "propertyValue",
3832
+ variableUuid: style.variableUuid,
3833
+ styles: stylesByViewport
3834
+ };
3835
+ }
3836
+ return {
3837
+ uuid: style.variableUuid,
3838
+ category: "propertyVariable",
3839
+ styles: stylesByViewport
3840
+ };
3841
+ });
3842
+ }
3821
3843
  /**
3822
3844
  * Parses raw web element properties into a standardized WebElementComponent structure
3823
3845
  *
@@ -4893,6 +4915,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
4893
4915
  },
4894
4916
  footer: {
4895
4917
  isDisplayed: true,
4918
+ logoUuid: null,
4896
4919
  items: null
4897
4920
  },
4898
4921
  sidebar,
@@ -4911,7 +4934,8 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
4911
4934
  options: {
4912
4935
  contexts: null,
4913
4936
  scopes: null,
4914
- labels: { title: null }
4937
+ labels: { title: null },
4938
+ stylesheets: { properties: [] }
4915
4939
  }
4916
4940
  };
4917
4941
  const contactProperty = getPropertyByLabel(websiteProperties, "contact");
@@ -4925,7 +4949,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
4925
4949
  }
4926
4950
  returnProperties.theme.isThemeToggleDisplayed = getPropertyValueByLabel(websiteProperties, "supports-theme-toggle") ?? true;
4927
4951
  returnProperties.theme.defaultTheme = getPropertyValueByLabel(websiteProperties, "default-theme") ?? "system";
4928
- returnProperties.icon.logoUuid = getPropertyByLabel(websiteProperties, "logo")?.values[0]?.uuid ?? null;
4952
+ returnProperties.icon.logoUuid = getPropertyByLabel(websiteProperties, "navbar-logo")?.values[0]?.uuid ?? null;
4929
4953
  returnProperties.icon.faviconUuid = getPropertyByLabel(websiteProperties, "favicon-ico")?.values[0]?.uuid ?? null;
4930
4954
  returnProperties.icon.appleTouchIconUuid = getPropertyByLabel(websiteProperties, "favicon-img")?.values[0]?.uuid ?? null;
4931
4955
  returnProperties.navbar.isDisplayed = getPropertyValueByLabel(websiteProperties, "navbar-displayed") ?? true;
@@ -4934,6 +4958,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
4934
4958
  returnProperties.navbar.isProjectDisplayed = getPropertyValueByLabel(websiteProperties, "navbar-project-displayed") ?? true;
4935
4959
  returnProperties.navbar.searchBarBoundElementUuid = getPropertyByLabel(websiteProperties, "bound-element-navbar-search-bar")?.values[0]?.uuid ?? null;
4936
4960
  returnProperties.footer.isDisplayed = getPropertyValueByLabel(websiteProperties, "footer-displayed") ?? true;
4961
+ returnProperties.footer.logoUuid = getPropertyByLabel(websiteProperties, "footer-logo")?.values[0]?.uuid ?? null;
4937
4962
  const itemPageTypeProperty = getPropertyByLabelAndValue(websiteProperties, "page-type", "item-page");
4938
4963
  if (itemPageTypeProperty !== null) {
4939
4964
  returnProperties.itemPage.isMainContentDisplayed = getPropertyValueByLabel(itemPageTypeProperty.properties, "item-page-main-content-displayed") ?? true;
@@ -4959,6 +4984,7 @@ function parseWebsiteProperties(properties, websiteTree, sidebar) {
4959
4984
  returnProperties.options.labels.title = labelNotes.find((note) => note.title === "Title label")?.content ?? null;
4960
4985
  }
4961
4986
  }
4987
+ if ("styleOptions" in websiteTree && websiteTree.styleOptions != null) returnProperties.options.stylesheets.properties = parseStylesheets(ensureArray(websiteTree.styleOptions.style));
4962
4988
  return returnProperties;
4963
4989
  }
4964
4990
  function parseContexts(contexts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.20.30",
3
+ "version": "0.21.1",
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",
@@ -51,8 +51,8 @@
51
51
  "bumpp": "^11.0.1",
52
52
  "eslint": "^10.1.0",
53
53
  "prettier": "^3.8.1",
54
- "tsdown": "^0.21.4",
55
- "typescript": "^5.9.3"
54
+ "tsdown": "^0.21.5",
55
+ "typescript": "^6.0.2"
56
56
  },
57
57
  "scripts": {
58
58
  "dev": "tsdown src/index.ts --watch",