@se-studio/contentful-rest-api 1.0.18 → 1.0.19
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.ts +95 -58
- package/dist/index.js +792 -738
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -36,6 +36,9 @@ function personTag(slug) {
|
|
|
36
36
|
function assetTag(assetId) {
|
|
37
37
|
return `${AssetTag}#${assetId}`;
|
|
38
38
|
}
|
|
39
|
+
function templateTag(label) {
|
|
40
|
+
return `${TemplateTag}#${label}`;
|
|
41
|
+
}
|
|
39
42
|
function locationTag(slug) {
|
|
40
43
|
return `${LocationTag}#${slug}`;
|
|
41
44
|
}
|
|
@@ -306,14 +309,25 @@ var DEFAULT_POSITION_FIELDS = {
|
|
|
306
309
|
indexOfType: 0
|
|
307
310
|
};
|
|
308
311
|
function createInternalLink(id, fields, context, href, internalType, additionalProps) {
|
|
309
|
-
const {
|
|
312
|
+
const {
|
|
313
|
+
cmsLabel,
|
|
314
|
+
title,
|
|
315
|
+
featuredImage,
|
|
316
|
+
backgroundColour,
|
|
317
|
+
textColour,
|
|
318
|
+
indexed,
|
|
319
|
+
hidden,
|
|
320
|
+
slug,
|
|
321
|
+
description
|
|
322
|
+
} = fields;
|
|
323
|
+
const text = makeContentfulTitle(title, id);
|
|
310
324
|
return {
|
|
311
325
|
type: "Internal link",
|
|
312
326
|
internalType,
|
|
313
327
|
id,
|
|
314
328
|
name: cmsLabel ?? "",
|
|
315
329
|
useName: true,
|
|
316
|
-
text
|
|
330
|
+
text,
|
|
317
331
|
visual: lookupAsset(context, featuredImage),
|
|
318
332
|
backgroundColour,
|
|
319
333
|
textColour,
|
|
@@ -321,6 +335,8 @@ function createInternalLink(id, fields, context, href, internalType, additionalP
|
|
|
321
335
|
hidden,
|
|
322
336
|
slug,
|
|
323
337
|
href,
|
|
338
|
+
title,
|
|
339
|
+
description,
|
|
324
340
|
...additionalProps
|
|
325
341
|
};
|
|
326
342
|
}
|
|
@@ -573,6 +589,9 @@ function lookupMediaEntry(context, link) {
|
|
|
573
589
|
return void 0;
|
|
574
590
|
}
|
|
575
591
|
|
|
592
|
+
// src/api/helpers.ts
|
|
593
|
+
init_utils();
|
|
594
|
+
|
|
576
595
|
// src/utils/arrayUtils.ts
|
|
577
596
|
function notEmpty(value) {
|
|
578
597
|
if (value === null || value === void 0) return false;
|
|
@@ -620,11 +639,19 @@ function sleep(ms) {
|
|
|
620
639
|
}
|
|
621
640
|
function calculateBackoffDelay(attempt, config, retryAfter) {
|
|
622
641
|
if (retryAfter !== void 0) {
|
|
623
|
-
|
|
642
|
+
const result2 = Math.min(retryAfter * 1e3, config.maxDelay);
|
|
643
|
+
console.log(
|
|
644
|
+
`Calculated backoff delay: ${result2}ms (attempt ${attempt + 1}), retryAfter: ${retryAfter}`
|
|
645
|
+
);
|
|
646
|
+
return result2;
|
|
624
647
|
}
|
|
625
648
|
const exponentialDelay = config.initialDelay * config.backoffMultiplier ** attempt;
|
|
626
649
|
const jitter = Math.random() * exponentialDelay;
|
|
627
|
-
|
|
650
|
+
const result = Math.min(exponentialDelay + jitter, config.maxDelay);
|
|
651
|
+
console.log(
|
|
652
|
+
`Calculated backoff delay: ${result}ms (attempt ${attempt + 1}), exponentialDelay: ${exponentialDelay}, jitter: ${jitter}`
|
|
653
|
+
);
|
|
654
|
+
return result;
|
|
628
655
|
}
|
|
629
656
|
async function withRetry(fn, config) {
|
|
630
657
|
const retryConfig = {
|
|
@@ -705,6 +732,211 @@ var RateLimiter = class {
|
|
|
705
732
|
}
|
|
706
733
|
};
|
|
707
734
|
|
|
735
|
+
// src/api/helpers.ts
|
|
736
|
+
var PAGE_LINK_FIELDS = "sys,fields.cmsLabel,fields.title,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden,fields.tags";
|
|
737
|
+
var ARTICLE_LINK_FIELDS = "sys,fields.cmsLabel,fields.title,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden,fields.tags,fields.articleType,fields.date,fields.author";
|
|
738
|
+
var ARTICLE_TYPE_LINK_FIELDS = "sys,fields.name,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden";
|
|
739
|
+
var TAG_LINK_FIELDS = "sys,fields.cmsLabel,fields.name,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden";
|
|
740
|
+
var PERSON_LINK_FIELDS = "sys,fields.name,fields.slug,fields.media,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden";
|
|
741
|
+
function convertAllAssets(response, context) {
|
|
742
|
+
const visuals = /* @__PURE__ */ new Map();
|
|
743
|
+
const assets = response.includes?.Asset;
|
|
744
|
+
if (assets && assets.length > 0) {
|
|
745
|
+
for (const asset of assets) {
|
|
746
|
+
const visual = convertAssetToVisual(context, asset);
|
|
747
|
+
if (visual) {
|
|
748
|
+
visuals.set(visual.id, visual);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return visuals;
|
|
753
|
+
}
|
|
754
|
+
function convertAllIncludes(response) {
|
|
755
|
+
const includes = /* @__PURE__ */ new Map();
|
|
756
|
+
const entries = [...response.items, ...response.includes?.Entry || []];
|
|
757
|
+
if (entries && entries.length > 0) {
|
|
758
|
+
for (const entry of entries) {
|
|
759
|
+
if (entry?.sys && entry.fields) {
|
|
760
|
+
includes.set(entry.sys.id, {
|
|
761
|
+
id: entry.sys.id,
|
|
762
|
+
type: entry.sys.contentType.sys.id,
|
|
763
|
+
entry
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return includes;
|
|
769
|
+
}
|
|
770
|
+
async function fetchSingleEntity(context, config, fetchConfig, options) {
|
|
771
|
+
const client = getContentfulClient(config, options?.preview);
|
|
772
|
+
const cacheTags = getCacheTags(
|
|
773
|
+
fetchConfig.cacheTagType,
|
|
774
|
+
fetchConfig.cacheTagIdentifier,
|
|
775
|
+
options?.preview
|
|
776
|
+
);
|
|
777
|
+
const requestOptions = {
|
|
778
|
+
...options,
|
|
779
|
+
next: {
|
|
780
|
+
...options?.next,
|
|
781
|
+
tags: cacheTags
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
const fetchFn = async () => {
|
|
785
|
+
const response = await client.getEntries(
|
|
786
|
+
{
|
|
787
|
+
content_type: fetchConfig.contentType,
|
|
788
|
+
...fetchConfig.query,
|
|
789
|
+
include: 10,
|
|
790
|
+
locale: options?.locale,
|
|
791
|
+
limit: 1
|
|
792
|
+
},
|
|
793
|
+
requestOptions
|
|
794
|
+
);
|
|
795
|
+
const entry = response.items[0];
|
|
796
|
+
if (!entry || !entry.fields) {
|
|
797
|
+
return { data: null, errors: [] };
|
|
798
|
+
}
|
|
799
|
+
try {
|
|
800
|
+
const assets = convertAllAssets(response, context);
|
|
801
|
+
const includes = convertAllIncludes(response);
|
|
802
|
+
const fullContext = {
|
|
803
|
+
...context,
|
|
804
|
+
includes,
|
|
805
|
+
assets,
|
|
806
|
+
errors: []
|
|
807
|
+
};
|
|
808
|
+
const converted = fetchConfig.resolver(fullContext, entry);
|
|
809
|
+
if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
810
|
+
console.error(`CMS conversion errors for ${fetchConfig.contentType}:`, {
|
|
811
|
+
entryId: entry.sys.id,
|
|
812
|
+
...fetchConfig.errorLogContext,
|
|
813
|
+
errors: fullContext.errors
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
return { data: converted, errors: fullContext.errors };
|
|
817
|
+
} catch (error) {
|
|
818
|
+
const entryId = entry.sys.id;
|
|
819
|
+
const entryType = entry.sys.contentType?.sys?.id;
|
|
820
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
821
|
+
const cmsError = {
|
|
822
|
+
entryId,
|
|
823
|
+
entryType,
|
|
824
|
+
message: errorMessage,
|
|
825
|
+
error
|
|
826
|
+
};
|
|
827
|
+
return { data: null, errors: [cmsError] };
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
if (options?.retry) {
|
|
831
|
+
return await withRetry(fetchFn, options.retry);
|
|
832
|
+
}
|
|
833
|
+
return await fetchFn();
|
|
834
|
+
}
|
|
835
|
+
async function fetchAllLinks(contentType, client, requestOptions, converter, context, pageSize = 100, select) {
|
|
836
|
+
const allLinks = [];
|
|
837
|
+
const errors = [];
|
|
838
|
+
let skip = 0;
|
|
839
|
+
let hasMore = true;
|
|
840
|
+
const fetchFn = async () => {
|
|
841
|
+
while (hasMore) {
|
|
842
|
+
try {
|
|
843
|
+
const response = await client.getEntries(
|
|
844
|
+
{
|
|
845
|
+
content_type: contentType,
|
|
846
|
+
include: 2,
|
|
847
|
+
// Minimal include for link-only fetching
|
|
848
|
+
locale: requestOptions?.locale,
|
|
849
|
+
limit: pageSize,
|
|
850
|
+
skip,
|
|
851
|
+
...select && { select }
|
|
852
|
+
},
|
|
853
|
+
requestOptions
|
|
854
|
+
);
|
|
855
|
+
if (response.items.length === 0) {
|
|
856
|
+
hasMore = false;
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
const includes = convertAllIncludes(response);
|
|
860
|
+
const assets = convertAllAssets(response, context);
|
|
861
|
+
const fullContext = {
|
|
862
|
+
...context,
|
|
863
|
+
includes,
|
|
864
|
+
assets,
|
|
865
|
+
errors: []
|
|
866
|
+
};
|
|
867
|
+
for (const entry of response.items) {
|
|
868
|
+
if (!entry.fields) continue;
|
|
869
|
+
try {
|
|
870
|
+
const converted = converter(
|
|
871
|
+
fullContext,
|
|
872
|
+
entry
|
|
873
|
+
);
|
|
874
|
+
converted.lastModified = entry.sys.updatedAt ? new Date(entry.sys.updatedAt) : void 0;
|
|
875
|
+
allLinks.push(converted);
|
|
876
|
+
} catch (error) {
|
|
877
|
+
const entryId = entry.sys.id;
|
|
878
|
+
const entryType = entry.sys.contentType?.sys?.id;
|
|
879
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
880
|
+
errors.push({
|
|
881
|
+
entryId,
|
|
882
|
+
entryType,
|
|
883
|
+
message: errorMessage,
|
|
884
|
+
error
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
skip += pageSize;
|
|
889
|
+
if (skip >= response.total) {
|
|
890
|
+
hasMore = false;
|
|
891
|
+
}
|
|
892
|
+
} catch (error) {
|
|
893
|
+
console.error("Error fetching links", typeof error, error, JSON.stringify(error, null, 2));
|
|
894
|
+
throw error;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
return { data: allLinks, errors };
|
|
898
|
+
};
|
|
899
|
+
return await fetchFn();
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// src/api/article.ts
|
|
903
|
+
async function contentfulArticleRest(context, config, slug, articleTypeSlug, options) {
|
|
904
|
+
return fetchSingleEntity(
|
|
905
|
+
context,
|
|
906
|
+
config,
|
|
907
|
+
{
|
|
908
|
+
contentType: "article",
|
|
909
|
+
cacheTagType: "article",
|
|
910
|
+
cacheTagIdentifier: slug,
|
|
911
|
+
query: {
|
|
912
|
+
"fields.slug": slug,
|
|
913
|
+
"fields.articleType.sys.contentType.sys.id": "articleType",
|
|
914
|
+
"fields.articleType.fields.slug": articleTypeSlug
|
|
915
|
+
},
|
|
916
|
+
resolver: (ctx, entry) => ctx.articleResolver(ctx, entry),
|
|
917
|
+
errorLogContext: { slug, articleTypeSlug }
|
|
918
|
+
},
|
|
919
|
+
options
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/api/article-type.ts
|
|
924
|
+
async function contentfulArticleTypeRest(context, config, indexPageSlug, options) {
|
|
925
|
+
return fetchSingleEntity(
|
|
926
|
+
context,
|
|
927
|
+
config,
|
|
928
|
+
{
|
|
929
|
+
contentType: "articleType",
|
|
930
|
+
cacheTagType: "articleType",
|
|
931
|
+
cacheTagIdentifier: indexPageSlug,
|
|
932
|
+
query: { "fields.indexPageSlug": indexPageSlug },
|
|
933
|
+
resolver: (ctx, entry) => ctx.articleTypeResolver(ctx, entry),
|
|
934
|
+
errorLogContext: { indexPageSlug }
|
|
935
|
+
},
|
|
936
|
+
options
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
|
|
708
940
|
// src/converters/resolver.ts
|
|
709
941
|
function resolveHelper(context, fromId, entry, getResolver) {
|
|
710
942
|
const id = entry.sys.id;
|
|
@@ -758,17 +990,22 @@ function resolveNavigationItem(context, fromId, entry) {
|
|
|
758
990
|
return result;
|
|
759
991
|
}
|
|
760
992
|
function resolveCollectionContent(context, fromId, entry) {
|
|
761
|
-
return resolveHelper(
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
993
|
+
return resolveHelper(
|
|
994
|
+
context,
|
|
995
|
+
fromId,
|
|
996
|
+
entry,
|
|
997
|
+
(type) => {
|
|
998
|
+
const resolver = context.contentResolver.get(type);
|
|
999
|
+
if (resolver) {
|
|
1000
|
+
return resolver;
|
|
1001
|
+
}
|
|
1002
|
+
const linkResolver = context.linkResolver.get(type);
|
|
1003
|
+
if (linkResolver) {
|
|
1004
|
+
return linkResolver;
|
|
1005
|
+
}
|
|
1006
|
+
return void 0;
|
|
769
1007
|
}
|
|
770
|
-
|
|
771
|
-
});
|
|
1008
|
+
);
|
|
772
1009
|
}
|
|
773
1010
|
function resolvePageContent(context, fromId, entry) {
|
|
774
1011
|
const id = entry.sys.id;
|
|
@@ -973,53 +1210,329 @@ function resolveRichTextDocument(context, fromId, richText) {
|
|
|
973
1210
|
return { json: resolved };
|
|
974
1211
|
}
|
|
975
1212
|
|
|
976
|
-
// src/converters/
|
|
977
|
-
function
|
|
978
|
-
const { sys, fields } = entry;
|
|
979
|
-
const { id } = sys;
|
|
1213
|
+
// src/converters/navigationItem.ts
|
|
1214
|
+
function createLink(context, entry) {
|
|
980
1215
|
const {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
collectionType,
|
|
994
|
-
showHeading,
|
|
995
|
-
heading,
|
|
996
|
-
// Already handled elsewhere
|
|
997
|
-
cmsLabel,
|
|
998
|
-
...simpleFields
|
|
999
|
-
// anchor, backgroundColour, textColour, preHeading, heading, postHeading, backgroundOverlayOpacity
|
|
1216
|
+
sys: { id },
|
|
1217
|
+
fields
|
|
1218
|
+
} = entry;
|
|
1219
|
+
const {
|
|
1220
|
+
title,
|
|
1221
|
+
link,
|
|
1222
|
+
text,
|
|
1223
|
+
internal,
|
|
1224
|
+
icon: navIcon,
|
|
1225
|
+
mobileIcon: mobileNavIcon,
|
|
1226
|
+
useTitle,
|
|
1227
|
+
...otherFields
|
|
1000
1228
|
} = fields;
|
|
1001
|
-
const
|
|
1002
|
-
lookupAsset(context,
|
|
1003
|
-
lookupAsset(context,
|
|
1004
|
-
);
|
|
1005
|
-
const visual = createResponsiveVisual(
|
|
1006
|
-
lookupMediaEntry(context, visualField),
|
|
1007
|
-
lookupMediaEntry(context, mobileVisualField),
|
|
1008
|
-
visualCustomSize
|
|
1229
|
+
const icon = createResponsiveVisual(
|
|
1230
|
+
lookupAsset(context, navIcon),
|
|
1231
|
+
lookupAsset(context, mobileNavIcon)
|
|
1009
1232
|
);
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1233
|
+
const realText = useTitle ? resolveBuildYear(title) : text ? resolveBuildYear(text) : void 0;
|
|
1234
|
+
if (link) {
|
|
1235
|
+
return {
|
|
1236
|
+
type: "External link",
|
|
1237
|
+
id,
|
|
1238
|
+
href: link,
|
|
1239
|
+
icon,
|
|
1240
|
+
name: makeContentfulTitle(title, id),
|
|
1241
|
+
...otherFields,
|
|
1242
|
+
text: realText
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
if (internal) {
|
|
1246
|
+
const resolved = resolveLink(context, id, internal);
|
|
1247
|
+
return { ...resolved, icon, id, text: realText };
|
|
1248
|
+
}
|
|
1249
|
+
const blank = {
|
|
1250
|
+
type: "Blank link",
|
|
1251
|
+
nick: true,
|
|
1252
|
+
id,
|
|
1253
|
+
name: makeContentfulTitle(title, id),
|
|
1254
|
+
...otherFields,
|
|
1255
|
+
icon,
|
|
1256
|
+
text: realText
|
|
1257
|
+
};
|
|
1258
|
+
return blank;
|
|
1259
|
+
}
|
|
1260
|
+
function baseNavigationItemConverter(context, entry) {
|
|
1261
|
+
const {
|
|
1262
|
+
sys: { id },
|
|
1263
|
+
fields
|
|
1264
|
+
} = entry;
|
|
1265
|
+
const { navigationItems } = fields;
|
|
1266
|
+
const link = createLink(context, entry);
|
|
1267
|
+
const resolvedNavigationItems = navigationItems?.map((item) => resolveNavigationItem(context, id, item)).filter((item) => item !== void 0);
|
|
1268
|
+
const result = {
|
|
1269
|
+
id,
|
|
1270
|
+
link,
|
|
1271
|
+
entries: resolvedNavigationItems
|
|
1272
|
+
};
|
|
1273
|
+
return result;
|
|
1274
|
+
}
|
|
1275
|
+
function resolveNavigation(context, link) {
|
|
1276
|
+
const id = link.sys.id;
|
|
1277
|
+
const possibleEntry = context.includes.get(id);
|
|
1278
|
+
if (!possibleEntry || possibleEntry.type !== "navigation") {
|
|
1279
|
+
return void 0;
|
|
1280
|
+
}
|
|
1281
|
+
const entry = possibleEntry.entry;
|
|
1282
|
+
const { fields } = entry;
|
|
1283
|
+
if (!fields) {
|
|
1284
|
+
return void 0;
|
|
1285
|
+
}
|
|
1286
|
+
const { name, entries: fieldEntries, ...rest } = fields;
|
|
1287
|
+
const entries = fieldEntries?.map((item) => resolveNavigationItem(context, id, item)) ?? [];
|
|
1288
|
+
return {
|
|
1289
|
+
id,
|
|
1290
|
+
name,
|
|
1291
|
+
entries,
|
|
1292
|
+
...rest
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// src/converters/template.ts
|
|
1297
|
+
function resolveTemplate(context, link) {
|
|
1298
|
+
const id = link.sys.id;
|
|
1299
|
+
const possibleEntry = context.includes.get(id);
|
|
1300
|
+
if (!possibleEntry || possibleEntry.type !== "template") {
|
|
1301
|
+
return null;
|
|
1302
|
+
}
|
|
1303
|
+
const entry = possibleEntry.entry;
|
|
1304
|
+
const { fields } = entry;
|
|
1305
|
+
if (!fields) {
|
|
1306
|
+
return null;
|
|
1307
|
+
}
|
|
1308
|
+
const preContent = fields.preContent?.map((content) => resolvePageContent(context, id, content)).filter((item) => item !== null) ?? [];
|
|
1309
|
+
const postContent = fields.postContent?.map((content) => resolvePageContent(context, id, content)).filter((item) => item !== null) ?? [];
|
|
1310
|
+
const menu = fields.menu ? resolveNavigation(context, fields.menu) : void 0;
|
|
1311
|
+
const footer = fields.footer ? resolveNavigation(context, fields.footer) : void 0;
|
|
1312
|
+
const stickyNav = fields.flags?.includes("Sticky nav") ?? false;
|
|
1313
|
+
const { backgroundColour, textColour } = fields;
|
|
1314
|
+
return {
|
|
1315
|
+
preContent,
|
|
1316
|
+
postContent,
|
|
1317
|
+
menu,
|
|
1318
|
+
footer,
|
|
1319
|
+
backgroundColour,
|
|
1320
|
+
textColour,
|
|
1321
|
+
stickyNav
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// src/converters/article.ts
|
|
1326
|
+
function resolveArticleTemplateHierarchy(context, articleTypeLink, directTemplateLink) {
|
|
1327
|
+
if (directTemplateLink) {
|
|
1328
|
+
return resolveTemplate(context, directTemplateLink);
|
|
1329
|
+
}
|
|
1330
|
+
const articleTypeEntry = context.includes.get(articleTypeLink.sys.id);
|
|
1331
|
+
if (!articleTypeEntry) {
|
|
1332
|
+
console.warn(`ArticleType entry not found for id: ${articleTypeLink.sys.id}`);
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1335
|
+
const articleTypeFields = articleTypeEntry.entry.fields;
|
|
1336
|
+
if (articleTypeFields?.articleTemplate) {
|
|
1337
|
+
return resolveTemplate(context, articleTypeFields.articleTemplate);
|
|
1338
|
+
}
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
function baseArticleConverter(context, entry) {
|
|
1342
|
+
const { sys, fields } = entry;
|
|
1343
|
+
const { id } = sys;
|
|
1344
|
+
const {
|
|
1345
|
+
slug,
|
|
1346
|
+
title,
|
|
1347
|
+
description,
|
|
1348
|
+
featuredImage,
|
|
1349
|
+
tags,
|
|
1350
|
+
content,
|
|
1351
|
+
template: templateLink,
|
|
1352
|
+
topContent: topContentLinks,
|
|
1353
|
+
bottomContent: bottomContentLinks,
|
|
1354
|
+
articleType,
|
|
1355
|
+
...simpleFields
|
|
1356
|
+
} = fields;
|
|
1357
|
+
const articleTypeLink = resolveLink(context, id, articleType);
|
|
1358
|
+
const template = resolveArticleTemplateHierarchy(context, articleType, templateLink);
|
|
1359
|
+
const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1360
|
+
const articleContent = content?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1361
|
+
const bottomContent = bottomContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1362
|
+
const preContent = template?.preContent ?? [];
|
|
1363
|
+
const postContent = template?.postContent ?? [];
|
|
1364
|
+
const contents = addPositionMetadata([
|
|
1365
|
+
...topContent,
|
|
1366
|
+
...preContent,
|
|
1367
|
+
...articleContent,
|
|
1368
|
+
...postContent,
|
|
1369
|
+
...bottomContent
|
|
1370
|
+
]);
|
|
1371
|
+
const article = {
|
|
1372
|
+
type: "Article",
|
|
1373
|
+
id,
|
|
1374
|
+
slug,
|
|
1375
|
+
title: makeContentfulTitle(title, sys.id),
|
|
1376
|
+
description: makeContentfulDescription(description, sys.id),
|
|
1377
|
+
featuredImage: lookupAsset(context, featuredImage),
|
|
1378
|
+
articleType: articleTypeLink,
|
|
1379
|
+
tags: tags?.map((tag) => resolveLink(context, id, tag)),
|
|
1380
|
+
contents,
|
|
1381
|
+
...simpleFields,
|
|
1382
|
+
// Note: summary field exists in Contentful but is not part of IArticle interface
|
|
1383
|
+
// Keeping it in simpleFields for potential future use
|
|
1384
|
+
menu: template?.menu,
|
|
1385
|
+
footer: template?.footer
|
|
1386
|
+
};
|
|
1387
|
+
return article;
|
|
1388
|
+
}
|
|
1389
|
+
function calculateArticleTypeHref(slug) {
|
|
1390
|
+
return `/${slug}/`;
|
|
1391
|
+
}
|
|
1392
|
+
function calculateArticleHref(articleTypeSlug, slug) {
|
|
1393
|
+
return `${calculateArticleTypeHref(articleTypeSlug)}${slug}/`;
|
|
1394
|
+
}
|
|
1395
|
+
function baseArticleLinkConverter(context, entry) {
|
|
1396
|
+
const { sys, fields } = entry;
|
|
1397
|
+
if (sys.contentType.sys.id !== "article") {
|
|
1398
|
+
throw new Error(`Invalid content type: expected "article", got "${sys.contentType.sys.id}"`);
|
|
1399
|
+
}
|
|
1400
|
+
const articleTypeLink = resolveLink(context, sys.id, fields.articleType);
|
|
1401
|
+
const tags = fields.tags?.map((tag) => resolveLink(context, sys.id, tag));
|
|
1402
|
+
const primaryTag = tags?.[0] ?? void 0;
|
|
1403
|
+
const author = fields.author ? resolveLink(context, sys.id, fields.author) : void 0;
|
|
1404
|
+
return createInternalLink(
|
|
1405
|
+
sys.id,
|
|
1406
|
+
{
|
|
1407
|
+
cmsLabel: fields.cmsLabel,
|
|
1408
|
+
title: fields.title,
|
|
1409
|
+
featuredImage: fields.featuredImage,
|
|
1410
|
+
backgroundColour: fields.backgroundColour,
|
|
1411
|
+
textColour: fields.textColour,
|
|
1412
|
+
indexed: fields.indexed,
|
|
1413
|
+
hidden: fields.hidden,
|
|
1414
|
+
slug: fields.slug
|
|
1415
|
+
},
|
|
1416
|
+
context,
|
|
1417
|
+
calculateArticleHref(articleTypeLink.slug, fields.slug),
|
|
1418
|
+
"Article",
|
|
1419
|
+
{
|
|
1420
|
+
tags,
|
|
1421
|
+
primaryTag,
|
|
1422
|
+
articleType: articleTypeLink,
|
|
1423
|
+
date: fields.date,
|
|
1424
|
+
author
|
|
1425
|
+
}
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
function baseArticleTypeLinkConverter(context, entry) {
|
|
1429
|
+
const { sys, fields } = entry;
|
|
1430
|
+
if (sys.contentType.sys.id !== "articleType") {
|
|
1431
|
+
throw new Error(
|
|
1432
|
+
`Invalid content type: expected "articleType", got "${sys.contentType.sys.id}"`
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
return createInternalLink(
|
|
1436
|
+
sys.id,
|
|
1437
|
+
{
|
|
1438
|
+
cmsLabel: fields.name,
|
|
1439
|
+
title: fields.name,
|
|
1440
|
+
featuredImage: fields.featuredImage,
|
|
1441
|
+
backgroundColour: fields.backgroundColour,
|
|
1442
|
+
textColour: fields.textColour,
|
|
1443
|
+
indexed: fields.indexed,
|
|
1444
|
+
hidden: fields.hidden,
|
|
1445
|
+
slug: fields.slug
|
|
1446
|
+
},
|
|
1447
|
+
context,
|
|
1448
|
+
calculateArticleTypeHref(fields.slug),
|
|
1449
|
+
"ArticleType",
|
|
1450
|
+
{ indexPageSlug: fields.indexPageSlug }
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
function baseArticleTypeConverter(context, entry) {
|
|
1454
|
+
const { sys, fields } = entry;
|
|
1455
|
+
const { id } = sys;
|
|
1456
|
+
const {
|
|
1457
|
+
indexPageSlug,
|
|
1458
|
+
indexPageName,
|
|
1459
|
+
indexPageDescription,
|
|
1460
|
+
featuredImage,
|
|
1461
|
+
menu: menuLink,
|
|
1462
|
+
footer: footerLink,
|
|
1463
|
+
indexPageTemplate: templateLink,
|
|
1464
|
+
indexPageTopContent: topContentLinks,
|
|
1465
|
+
structuredData,
|
|
1466
|
+
slug: _slug,
|
|
1467
|
+
...other
|
|
1468
|
+
} = fields;
|
|
1469
|
+
const template = templateLink ? resolveTemplate(context, templateLink) : null;
|
|
1470
|
+
const menu = menuLink ? resolveNavigation(context, menuLink) : template?.menu;
|
|
1471
|
+
const footer = footerLink ? resolveNavigation(context, footerLink) : template?.footer;
|
|
1472
|
+
const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1473
|
+
const preContent = template?.preContent ?? [];
|
|
1474
|
+
const postContent = template?.postContent ?? [];
|
|
1475
|
+
const contents = addPositionMetadata([...topContent, ...preContent, ...postContent]);
|
|
1476
|
+
const articleType = {
|
|
1477
|
+
type: "Article type",
|
|
1478
|
+
id,
|
|
1479
|
+
slug: indexPageSlug,
|
|
1480
|
+
title: makeContentfulTitle(indexPageName, sys.id),
|
|
1481
|
+
description: makeContentfulDescription(indexPageDescription, sys.id),
|
|
1482
|
+
featuredImage: lookupAsset(context, featuredImage),
|
|
1483
|
+
contents,
|
|
1484
|
+
structuredData,
|
|
1485
|
+
menu,
|
|
1486
|
+
footer,
|
|
1487
|
+
...other
|
|
1488
|
+
};
|
|
1489
|
+
return articleType;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// src/converters/collection.ts
|
|
1493
|
+
function baseCollectionConverter(context, entry) {
|
|
1494
|
+
const { sys, fields } = entry;
|
|
1495
|
+
const { id } = sys;
|
|
1496
|
+
const {
|
|
1497
|
+
// Fields requiring transformation
|
|
1498
|
+
backgroundVisual: bgVisual,
|
|
1499
|
+
mobileBackgroundVisual: mobileBgVisual,
|
|
1500
|
+
visual: visualField,
|
|
1501
|
+
mobileVisual: mobileVisualField,
|
|
1502
|
+
visualCustomSize,
|
|
1503
|
+
icon: iconField,
|
|
1504
|
+
links: linksField,
|
|
1505
|
+
contents: contentsField,
|
|
1506
|
+
body: bodyField,
|
|
1507
|
+
additionalCopy: additionalCopyField,
|
|
1508
|
+
showHeading,
|
|
1509
|
+
heading,
|
|
1510
|
+
// Already handled elsewhere
|
|
1511
|
+
cmsLabel,
|
|
1512
|
+
...simpleFields
|
|
1513
|
+
// anchor, backgroundColour, textColour, preHeading, heading, postHeading, backgroundOverlayOpacity
|
|
1514
|
+
} = fields;
|
|
1515
|
+
const backgroundVisual = createResponsiveVisual(
|
|
1516
|
+
lookupAsset(context, bgVisual),
|
|
1517
|
+
lookupAsset(context, mobileBgVisual)
|
|
1518
|
+
);
|
|
1519
|
+
const visual = createResponsiveVisual(
|
|
1520
|
+
lookupMediaEntry(context, visualField),
|
|
1521
|
+
lookupMediaEntry(context, mobileVisualField),
|
|
1522
|
+
visualCustomSize
|
|
1523
|
+
);
|
|
1524
|
+
const collection = {
|
|
1525
|
+
type: "Collection",
|
|
1526
|
+
id,
|
|
1527
|
+
name: cmsLabel,
|
|
1528
|
+
cmsLabel,
|
|
1529
|
+
...DEFAULT_POSITION_FIELDS,
|
|
1530
|
+
...simpleFields,
|
|
1531
|
+
heading: showHeading ? heading : void 0,
|
|
1532
|
+
body: resolveRichTextDocument(context, id, bodyField),
|
|
1533
|
+
additionalCopy: resolveRichTextDocument(context, id, additionalCopyField),
|
|
1534
|
+
icon: lookupAsset(context, iconField),
|
|
1535
|
+
backgroundVisual,
|
|
1023
1536
|
visual,
|
|
1024
1537
|
links: linksField?.map((link) => resolveLink(context, id, link)),
|
|
1025
1538
|
contents: contentsField?.map((content) => resolveCollectionContent(context, id, content))
|
|
@@ -1043,7 +1556,6 @@ function baseComponentConverter(context, entry) {
|
|
|
1043
1556
|
body: bodyField,
|
|
1044
1557
|
additionalCopy: additionalCopyField,
|
|
1045
1558
|
// Field name change
|
|
1046
|
-
componentType,
|
|
1047
1559
|
showHeading,
|
|
1048
1560
|
heading,
|
|
1049
1561
|
otherMedia: otherMediaField,
|
|
@@ -1067,7 +1579,6 @@ function baseComponentConverter(context, entry) {
|
|
|
1067
1579
|
id,
|
|
1068
1580
|
name: cmsLabel,
|
|
1069
1581
|
cmsLabel,
|
|
1070
|
-
componentType,
|
|
1071
1582
|
...DEFAULT_POSITION_FIELDS,
|
|
1072
1583
|
...simpleFields,
|
|
1073
1584
|
heading: showHeading ? heading : void 0,
|
|
@@ -1082,6 +1593,49 @@ function baseComponentConverter(context, entry) {
|
|
|
1082
1593
|
return component;
|
|
1083
1594
|
}
|
|
1084
1595
|
|
|
1596
|
+
// src/converters/customType.ts
|
|
1597
|
+
function baseCustomTypeConverter(context, entry) {
|
|
1598
|
+
const { sys, fields } = entry;
|
|
1599
|
+
const { id } = sys;
|
|
1600
|
+
const {
|
|
1601
|
+
slug,
|
|
1602
|
+
indexPageSlug,
|
|
1603
|
+
indexPageName,
|
|
1604
|
+
indexPageDescription,
|
|
1605
|
+
featuredImage,
|
|
1606
|
+
menu: menuLink,
|
|
1607
|
+
footer: footerLink,
|
|
1608
|
+
indexPageTemplate: templateLink,
|
|
1609
|
+
indexPageTopContent: topContentLinks,
|
|
1610
|
+
structuredData,
|
|
1611
|
+
...other
|
|
1612
|
+
} = fields;
|
|
1613
|
+
const template = templateLink ? resolveTemplate(context, templateLink) : null;
|
|
1614
|
+
const menu = menuLink ? resolveNavigation(context, menuLink) : template?.menu;
|
|
1615
|
+
const footer = footerLink ? resolveNavigation(context, footerLink) : template?.footer;
|
|
1616
|
+
const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1617
|
+
const preContent = template?.preContent ?? [];
|
|
1618
|
+
const postContent = template?.postContent ?? [];
|
|
1619
|
+
const contents = addPositionMetadata([...topContent, ...preContent, ...postContent]);
|
|
1620
|
+
const customType = {
|
|
1621
|
+
type: "Custom type",
|
|
1622
|
+
id,
|
|
1623
|
+
slug,
|
|
1624
|
+
indexPageSlug,
|
|
1625
|
+
indexPageName: makeContentfulTitle(indexPageName, sys.id),
|
|
1626
|
+
indexPageDescription: makeContentfulDescription(indexPageDescription, sys.id),
|
|
1627
|
+
title: makeContentfulTitle(indexPageName, sys.id),
|
|
1628
|
+
description: makeContentfulDescription(indexPageDescription, sys.id),
|
|
1629
|
+
featuredImage: lookupAsset(context, featuredImage),
|
|
1630
|
+
contents,
|
|
1631
|
+
structuredData,
|
|
1632
|
+
menu,
|
|
1633
|
+
footer,
|
|
1634
|
+
...other
|
|
1635
|
+
};
|
|
1636
|
+
return customType;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1085
1639
|
// src/converters/link.ts
|
|
1086
1640
|
function baseLinkConverter(context, entry) {
|
|
1087
1641
|
const { sys, fields } = entry;
|
|
@@ -1123,7 +1677,9 @@ function baseLinkConverter(context, entry) {
|
|
|
1123
1677
|
slug: internalTarget.slug,
|
|
1124
1678
|
indexed: internalTarget.indexed,
|
|
1125
1679
|
hidden: internalTarget.hidden,
|
|
1126
|
-
tags: internalTarget.tags
|
|
1680
|
+
tags: internalTarget.tags,
|
|
1681
|
+
title: internalTarget.title,
|
|
1682
|
+
description: internalTarget.description
|
|
1127
1683
|
};
|
|
1128
1684
|
}
|
|
1129
1685
|
if (fields.external) {
|
|
@@ -1155,124 +1711,11 @@ function baseLinkConverter(context, entry) {
|
|
|
1155
1711
|
href,
|
|
1156
1712
|
visual: asset
|
|
1157
1713
|
};
|
|
1158
|
-
}
|
|
1159
|
-
return {
|
|
1160
|
-
...baseProps,
|
|
1161
|
-
type: "Blank link",
|
|
1162
|
-
href: null
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
// src/converters/navigationItem.ts
|
|
1167
|
-
function createLink(context, entry) {
|
|
1168
|
-
const {
|
|
1169
|
-
sys: { id },
|
|
1170
|
-
fields
|
|
1171
|
-
} = entry;
|
|
1172
|
-
const {
|
|
1173
|
-
title,
|
|
1174
|
-
link,
|
|
1175
|
-
text,
|
|
1176
|
-
internal,
|
|
1177
|
-
icon: navIcon,
|
|
1178
|
-
mobileIcon: mobileNavIcon,
|
|
1179
|
-
useTitle,
|
|
1180
|
-
...otherFields
|
|
1181
|
-
} = fields;
|
|
1182
|
-
const icon = createResponsiveVisual(
|
|
1183
|
-
lookupAsset(context, navIcon),
|
|
1184
|
-
lookupAsset(context, mobileNavIcon)
|
|
1185
|
-
);
|
|
1186
|
-
const realText = useTitle ? resolveBuildYear(title) : text ? resolveBuildYear(text) : void 0;
|
|
1187
|
-
if (link) {
|
|
1188
|
-
return {
|
|
1189
|
-
type: "External link",
|
|
1190
|
-
id,
|
|
1191
|
-
href: link,
|
|
1192
|
-
icon,
|
|
1193
|
-
name: makeContentfulTitle(title, id),
|
|
1194
|
-
...otherFields,
|
|
1195
|
-
text: realText
|
|
1196
|
-
};
|
|
1197
|
-
}
|
|
1198
|
-
if (internal) {
|
|
1199
|
-
const resolved = resolveLink(context, id, internal);
|
|
1200
|
-
return { ...resolved, icon, id, text: realText };
|
|
1201
|
-
}
|
|
1202
|
-
const blank = {
|
|
1203
|
-
type: "Blank link",
|
|
1204
|
-
nick: true,
|
|
1205
|
-
id,
|
|
1206
|
-
name: makeContentfulTitle(title, id),
|
|
1207
|
-
...otherFields,
|
|
1208
|
-
icon,
|
|
1209
|
-
text: realText
|
|
1210
|
-
};
|
|
1211
|
-
return blank;
|
|
1212
|
-
}
|
|
1213
|
-
function baseNavigationItemConverter(context, entry) {
|
|
1214
|
-
const {
|
|
1215
|
-
sys: { id },
|
|
1216
|
-
fields
|
|
1217
|
-
} = entry;
|
|
1218
|
-
const { navigationItems } = fields;
|
|
1219
|
-
const link = createLink(context, entry);
|
|
1220
|
-
const resolvedNavigationItems = navigationItems?.map((item) => resolveNavigationItem(context, id, item)).filter((item) => item !== void 0);
|
|
1221
|
-
const result = {
|
|
1222
|
-
id,
|
|
1223
|
-
link,
|
|
1224
|
-
entries: resolvedNavigationItems
|
|
1225
|
-
};
|
|
1226
|
-
return result;
|
|
1227
|
-
}
|
|
1228
|
-
function resolveNavigation(context, link) {
|
|
1229
|
-
const id = link.sys.id;
|
|
1230
|
-
const possibleEntry = context.includes.get(id);
|
|
1231
|
-
if (!possibleEntry || possibleEntry.type !== "navigation") {
|
|
1232
|
-
return void 0;
|
|
1233
|
-
}
|
|
1234
|
-
const entry = possibleEntry.entry;
|
|
1235
|
-
const { fields } = entry;
|
|
1236
|
-
if (!fields) {
|
|
1237
|
-
return void 0;
|
|
1238
|
-
}
|
|
1239
|
-
const entries = fields.entries?.map((item) => resolveNavigationItem(context, id, item)) ?? [];
|
|
1240
|
-
const { name, textColour, backgroundColour } = fields;
|
|
1241
|
-
return {
|
|
1242
|
-
id,
|
|
1243
|
-
name,
|
|
1244
|
-
entries,
|
|
1245
|
-
textColour,
|
|
1246
|
-
backgroundColour
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
// src/converters/template.ts
|
|
1251
|
-
function resolveTemplate(context, link) {
|
|
1252
|
-
const id = link.sys.id;
|
|
1253
|
-
const possibleEntry = context.includes.get(id);
|
|
1254
|
-
if (!possibleEntry || possibleEntry.type !== "template") {
|
|
1255
|
-
return null;
|
|
1256
|
-
}
|
|
1257
|
-
const entry = possibleEntry.entry;
|
|
1258
|
-
const { fields } = entry;
|
|
1259
|
-
if (!fields) {
|
|
1260
|
-
return null;
|
|
1261
|
-
}
|
|
1262
|
-
const preContent = fields.preContent?.map((content) => resolvePageContent(context, id, content)).filter((item) => item !== null) ?? [];
|
|
1263
|
-
const postContent = fields.postContent?.map((content) => resolvePageContent(context, id, content)).filter((item) => item !== null) ?? [];
|
|
1264
|
-
const menu = fields.menu ? resolveNavigation(context, fields.menu) : void 0;
|
|
1265
|
-
const footer = fields.footer ? resolveNavigation(context, fields.footer) : void 0;
|
|
1266
|
-
const stickyNav = fields.flags?.includes("Sticky nav") ?? false;
|
|
1267
|
-
const { backgroundColour, textColour } = fields;
|
|
1268
|
-
return {
|
|
1269
|
-
preContent,
|
|
1270
|
-
postContent,
|
|
1271
|
-
menu,
|
|
1272
|
-
footer,
|
|
1273
|
-
backgroundColour,
|
|
1274
|
-
textColour,
|
|
1275
|
-
stickyNav
|
|
1714
|
+
}
|
|
1715
|
+
return {
|
|
1716
|
+
...baseProps,
|
|
1717
|
+
type: "Blank link",
|
|
1718
|
+
href: null
|
|
1276
1719
|
};
|
|
1277
1720
|
}
|
|
1278
1721
|
|
|
@@ -1401,16 +1844,7 @@ function basePersonLinkConverter(context, entry) {
|
|
|
1401
1844
|
return createInternalLink(
|
|
1402
1845
|
sys.id,
|
|
1403
1846
|
{
|
|
1404
|
-
|
|
1405
|
-
// Person has no cmsLabel, use name field
|
|
1406
|
-
title: fields.name,
|
|
1407
|
-
featuredImage: fields.media,
|
|
1408
|
-
// Person uses 'media' not 'featuredImage'
|
|
1409
|
-
backgroundColour: fields.backgroundColour,
|
|
1410
|
-
textColour: fields.textColour,
|
|
1411
|
-
indexed: fields.indexed,
|
|
1412
|
-
hidden: fields.hidden,
|
|
1413
|
-
slug: fields.slug
|
|
1847
|
+
...fields
|
|
1414
1848
|
},
|
|
1415
1849
|
context,
|
|
1416
1850
|
calculatePersonHref(fields.slug),
|
|
@@ -1418,140 +1852,39 @@ function basePersonLinkConverter(context, entry) {
|
|
|
1418
1852
|
);
|
|
1419
1853
|
}
|
|
1420
1854
|
|
|
1421
|
-
// src/converters/
|
|
1422
|
-
function
|
|
1423
|
-
|
|
1424
|
-
return resolveTemplate(context, directTemplateLink);
|
|
1425
|
-
}
|
|
1426
|
-
const articleTypeEntry = context.includes.get(articleTypeLink.sys.id);
|
|
1427
|
-
if (!articleTypeEntry) {
|
|
1428
|
-
console.warn(`ArticleType entry not found for id: ${articleTypeLink.sys.id}`);
|
|
1429
|
-
return null;
|
|
1430
|
-
}
|
|
1431
|
-
const articleTypeFields = articleTypeEntry.entry.fields;
|
|
1432
|
-
if (articleTypeFields?.articleTemplate) {
|
|
1433
|
-
return resolveTemplate(context, articleTypeFields.articleTemplate);
|
|
1434
|
-
}
|
|
1435
|
-
return null;
|
|
1436
|
-
}
|
|
1437
|
-
function baseArticleConverter(context, entry) {
|
|
1438
|
-
const { sys, fields } = entry;
|
|
1439
|
-
const { id } = sys;
|
|
1440
|
-
const {
|
|
1441
|
-
slug,
|
|
1442
|
-
title,
|
|
1443
|
-
description,
|
|
1444
|
-
featuredImage,
|
|
1445
|
-
tags,
|
|
1446
|
-
content,
|
|
1447
|
-
template: templateLink,
|
|
1448
|
-
topContent: topContentLinks,
|
|
1449
|
-
bottomContent: bottomContentLinks,
|
|
1450
|
-
articleType,
|
|
1451
|
-
...simpleFields
|
|
1452
|
-
} = fields;
|
|
1453
|
-
const articleTypeLink = resolveLink(context, id, articleType);
|
|
1454
|
-
const template = resolveArticleTemplateHierarchy(context, articleType, templateLink);
|
|
1455
|
-
const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1456
|
-
const articleContent = content?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1457
|
-
const bottomContent = bottomContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1458
|
-
const preContent = template?.preContent ?? [];
|
|
1459
|
-
const postContent = template?.postContent ?? [];
|
|
1460
|
-
const contents = addPositionMetadata([
|
|
1461
|
-
...topContent,
|
|
1462
|
-
...preContent,
|
|
1463
|
-
...articleContent,
|
|
1464
|
-
...postContent,
|
|
1465
|
-
...bottomContent
|
|
1466
|
-
]);
|
|
1467
|
-
const article = {
|
|
1468
|
-
type: "Article",
|
|
1469
|
-
id,
|
|
1470
|
-
slug,
|
|
1471
|
-
title: makeContentfulTitle(title, sys.id),
|
|
1472
|
-
description: makeContentfulDescription(description, sys.id),
|
|
1473
|
-
featuredImage: lookupAsset(context, featuredImage),
|
|
1474
|
-
articleType: articleTypeLink,
|
|
1475
|
-
tags: tags?.map((tag) => resolveLink(context, id, tag)),
|
|
1476
|
-
contents,
|
|
1477
|
-
...simpleFields,
|
|
1478
|
-
// Note: summary field exists in Contentful but is not part of IArticle interface
|
|
1479
|
-
// Keeping it in simpleFields for potential future use
|
|
1480
|
-
menu: template?.menu,
|
|
1481
|
-
footer: template?.footer
|
|
1482
|
-
};
|
|
1483
|
-
return article;
|
|
1484
|
-
}
|
|
1485
|
-
function calculateArticleTypeHref(slug) {
|
|
1486
|
-
return `/${slug}/`;
|
|
1487
|
-
}
|
|
1488
|
-
function calculateArticleHref(articleTypeSlug, slug) {
|
|
1489
|
-
return `${calculateArticleTypeHref(articleTypeSlug)}${slug}/`;
|
|
1490
|
-
}
|
|
1491
|
-
function baseArticleLinkConverter(context, entry) {
|
|
1492
|
-
const { sys, fields } = entry;
|
|
1493
|
-
if (sys.contentType.sys.id !== "article") {
|
|
1494
|
-
throw new Error(`Invalid content type: expected "article", got "${sys.contentType.sys.id}"`);
|
|
1495
|
-
}
|
|
1496
|
-
const articleTypeLink = resolveLink(context, sys.id, fields.articleType);
|
|
1497
|
-
return createInternalLink(
|
|
1498
|
-
sys.id,
|
|
1499
|
-
{
|
|
1500
|
-
cmsLabel: fields.cmsLabel,
|
|
1501
|
-
title: fields.title,
|
|
1502
|
-
featuredImage: fields.featuredImage,
|
|
1503
|
-
backgroundColour: fields.backgroundColour,
|
|
1504
|
-
textColour: fields.textColour,
|
|
1505
|
-
indexed: fields.indexed,
|
|
1506
|
-
hidden: fields.hidden,
|
|
1507
|
-
slug: fields.slug
|
|
1508
|
-
},
|
|
1509
|
-
context,
|
|
1510
|
-
calculateArticleHref(articleTypeLink.slug, fields.slug),
|
|
1511
|
-
"Article",
|
|
1512
|
-
{
|
|
1513
|
-
tags: fields.tags?.map((tag) => resolveLink(context, sys.id, tag)),
|
|
1514
|
-
articleType: articleTypeLink
|
|
1515
|
-
}
|
|
1516
|
-
);
|
|
1855
|
+
// src/converters/tag.ts
|
|
1856
|
+
function calculateTagHref(slug) {
|
|
1857
|
+
return `/tag/${slug}/`;
|
|
1517
1858
|
}
|
|
1518
|
-
function
|
|
1859
|
+
function baseTagLinkConverter(context, entry) {
|
|
1519
1860
|
const { sys, fields } = entry;
|
|
1520
|
-
if (sys.contentType.sys.id !== "
|
|
1521
|
-
throw new Error(
|
|
1522
|
-
`Invalid content type: expected "articleType", got "${sys.contentType.sys.id}"`
|
|
1523
|
-
);
|
|
1861
|
+
if (sys.contentType.sys.id !== "tag") {
|
|
1862
|
+
throw new Error(`Invalid content type: expected "tag", got "${sys.contentType.sys.id}"`);
|
|
1524
1863
|
}
|
|
1525
1864
|
return createInternalLink(
|
|
1526
1865
|
sys.id,
|
|
1527
1866
|
{
|
|
1528
|
-
|
|
1529
|
-
title: fields.name,
|
|
1530
|
-
featuredImage: fields.featuredImage,
|
|
1531
|
-
backgroundColour: fields.backgroundColour,
|
|
1532
|
-
textColour: fields.textColour,
|
|
1533
|
-
indexed: fields.indexed,
|
|
1534
|
-
hidden: fields.hidden,
|
|
1535
|
-
slug: fields.slug
|
|
1867
|
+
...fields
|
|
1536
1868
|
},
|
|
1537
1869
|
context,
|
|
1538
|
-
|
|
1539
|
-
"
|
|
1870
|
+
calculateTagHref(fields.slug),
|
|
1871
|
+
"Tag"
|
|
1540
1872
|
);
|
|
1541
1873
|
}
|
|
1542
|
-
function
|
|
1874
|
+
function baseTagConverter(context, entry) {
|
|
1543
1875
|
const { sys, fields } = entry;
|
|
1544
1876
|
const { id } = sys;
|
|
1545
1877
|
const {
|
|
1878
|
+
name,
|
|
1546
1879
|
slug,
|
|
1547
|
-
|
|
1548
|
-
indexPageDescription,
|
|
1880
|
+
description,
|
|
1549
1881
|
featuredImage,
|
|
1882
|
+
tagType,
|
|
1550
1883
|
menu: menuLink,
|
|
1551
1884
|
footer: footerLink,
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
...
|
|
1885
|
+
template: templateLink,
|
|
1886
|
+
topContent: topContentLinks,
|
|
1887
|
+
...rest
|
|
1555
1888
|
} = fields;
|
|
1556
1889
|
const template = templateLink ? resolveTemplate(context, templateLink) : null;
|
|
1557
1890
|
const menu = menuLink ? resolveNavigation(context, menuLink) : template?.menu;
|
|
@@ -1559,152 +1892,34 @@ function baseArticleTypeConverter(context, entry) {
|
|
|
1559
1892
|
const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
|
|
1560
1893
|
const preContent = template?.preContent ?? [];
|
|
1561
1894
|
const postContent = template?.postContent ?? [];
|
|
1562
|
-
const
|
|
1563
|
-
const
|
|
1564
|
-
|
|
1895
|
+
const contents = addPositionMetadata([...topContent, ...preContent, ...postContent]);
|
|
1896
|
+
const tagTypeEntry = tagType ? context.includes.get(tagType.sys.id) : null;
|
|
1897
|
+
const tagTypeName = tagTypeEntry?.entry?.fields?.name;
|
|
1898
|
+
const tag = {
|
|
1899
|
+
type: "Tag",
|
|
1565
1900
|
id,
|
|
1566
1901
|
slug,
|
|
1567
|
-
title: makeContentfulTitle(
|
|
1568
|
-
description: makeContentfulDescription(
|
|
1902
|
+
title: makeContentfulTitle(name, sys.id),
|
|
1903
|
+
description: makeContentfulDescription(description, sys.id),
|
|
1569
1904
|
featuredImage: lookupAsset(context, featuredImage),
|
|
1570
|
-
|
|
1571
|
-
|
|
1905
|
+
tagType: tagTypeName ?? null,
|
|
1906
|
+
contents,
|
|
1907
|
+
...rest,
|
|
1572
1908
|
menu,
|
|
1573
|
-
footer
|
|
1574
|
-
};
|
|
1575
|
-
return articleType;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
// src/converters/tag.ts
|
|
1579
|
-
function calculateTagHref(slug) {
|
|
1580
|
-
return `/tag/${slug}/`;
|
|
1581
|
-
}
|
|
1582
|
-
function baseTagLinkConverter(context, entry) {
|
|
1583
|
-
const { sys, fields } = entry;
|
|
1584
|
-
if (sys.contentType.sys.id !== "tag") {
|
|
1585
|
-
throw new Error(`Invalid content type: expected "tag", got "${sys.contentType.sys.id}"`);
|
|
1586
|
-
}
|
|
1587
|
-
return createInternalLink(
|
|
1588
|
-
sys.id,
|
|
1589
|
-
{
|
|
1590
|
-
cmsLabel: fields.cmsLabel,
|
|
1591
|
-
title: fields.name,
|
|
1592
|
-
featuredImage: fields.featuredImage,
|
|
1593
|
-
backgroundColour: fields.backgroundColour,
|
|
1594
|
-
textColour: fields.textColour,
|
|
1595
|
-
indexed: fields.indexed,
|
|
1596
|
-
hidden: fields.hidden,
|
|
1597
|
-
slug: fields.slug
|
|
1598
|
-
},
|
|
1599
|
-
context,
|
|
1600
|
-
calculateTagHref(fields.slug),
|
|
1601
|
-
"Tag"
|
|
1602
|
-
);
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
// src/api.ts
|
|
1606
|
-
init_utils();
|
|
1607
|
-
var PAGE_LINK_FIELDS = "sys,fields.cmsLabel,fields.title,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden,fields.tags";
|
|
1608
|
-
var ARTICLE_LINK_FIELDS = "sys,fields.cmsLabel,fields.title,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden,fields.tags,fields.articleType";
|
|
1609
|
-
var ARTICLE_RELATED_FIELDS = "sys,fields.cmsLabel,fields.title,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden,fields.tags,fields.articleType,fields.date,fields.author";
|
|
1610
|
-
var ARTICLE_TYPE_LINK_FIELDS = "sys,fields.name,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden";
|
|
1611
|
-
var TAG_LINK_FIELDS = "sys,fields.cmsLabel,fields.name,fields.slug,fields.featuredImage,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden";
|
|
1612
|
-
var PERSON_LINK_FIELDS = "sys,fields.name,fields.slug,fields.media,fields.backgroundColour,fields.textColour,fields.indexed,fields.hidden";
|
|
1613
|
-
function convertAllAssets(response, context) {
|
|
1614
|
-
const visuals = /* @__PURE__ */ new Map();
|
|
1615
|
-
const assets = response.includes?.Asset;
|
|
1616
|
-
if (assets && assets.length > 0) {
|
|
1617
|
-
for (const asset of assets) {
|
|
1618
|
-
const visual = convertAssetToVisual(context, asset);
|
|
1619
|
-
if (visual) {
|
|
1620
|
-
visuals.set(visual.id, visual);
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
return visuals;
|
|
1625
|
-
}
|
|
1626
|
-
function convertAllIncludes(response) {
|
|
1627
|
-
const includes = /* @__PURE__ */ new Map();
|
|
1628
|
-
const entries = [...response.items, ...response.includes?.Entry || []];
|
|
1629
|
-
if (entries && entries.length > 0) {
|
|
1630
|
-
for (const entry of entries) {
|
|
1631
|
-
if (entry?.sys && entry.fields) {
|
|
1632
|
-
includes.set(entry.sys.id, {
|
|
1633
|
-
id: entry.sys.id,
|
|
1634
|
-
type: entry.sys.contentType.sys.id,
|
|
1635
|
-
entry
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
return includes;
|
|
1641
|
-
}
|
|
1642
|
-
async function contentfulPageRest(context, config, slug, options) {
|
|
1643
|
-
const client = getContentfulClient(config, options?.preview);
|
|
1644
|
-
const cacheTags = getCacheTags("page", slug, options?.preview);
|
|
1645
|
-
const requestOptions = {
|
|
1646
|
-
...options,
|
|
1647
|
-
next: {
|
|
1648
|
-
...options?.next,
|
|
1649
|
-
tags: cacheTags
|
|
1650
|
-
}
|
|
1651
|
-
};
|
|
1652
|
-
const fetchFn = async () => {
|
|
1653
|
-
const response = await client.getEntries(
|
|
1654
|
-
{
|
|
1655
|
-
content_type: "page",
|
|
1656
|
-
"fields.slug": slug,
|
|
1657
|
-
include: 10,
|
|
1658
|
-
locale: options?.locale,
|
|
1659
|
-
limit: 1
|
|
1660
|
-
},
|
|
1661
|
-
requestOptions
|
|
1662
|
-
);
|
|
1663
|
-
const pageEntry = response.items[0];
|
|
1664
|
-
if (!pageEntry || !pageEntry.fields) {
|
|
1665
|
-
return { data: null, errors: [] };
|
|
1666
|
-
}
|
|
1667
|
-
try {
|
|
1668
|
-
const assets = convertAllAssets(response, context);
|
|
1669
|
-
const includes = convertAllIncludes(response);
|
|
1670
|
-
const fullContext = {
|
|
1671
|
-
...context,
|
|
1672
|
-
includes,
|
|
1673
|
-
assets,
|
|
1674
|
-
errors: []
|
|
1675
|
-
};
|
|
1676
|
-
const converted = fullContext.pageResolver(fullContext, pageEntry);
|
|
1677
|
-
if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
1678
|
-
console.error("CMS conversion errors for page:", {
|
|
1679
|
-
pageId: pageEntry.sys.id,
|
|
1680
|
-
slug,
|
|
1681
|
-
errors: fullContext.errors
|
|
1682
|
-
});
|
|
1683
|
-
}
|
|
1684
|
-
return { data: converted, errors: fullContext.errors };
|
|
1685
|
-
} catch (error) {
|
|
1686
|
-
const entryId = pageEntry.sys.id;
|
|
1687
|
-
const entryType = pageEntry.sys.contentType?.sys?.id;
|
|
1688
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
1689
|
-
const cmsError = {
|
|
1690
|
-
entryId,
|
|
1691
|
-
entryType,
|
|
1692
|
-
message: errorMessage,
|
|
1693
|
-
error
|
|
1694
|
-
};
|
|
1695
|
-
return { data: null, errors: [cmsError] };
|
|
1696
|
-
}
|
|
1909
|
+
footer
|
|
1697
1910
|
};
|
|
1698
|
-
|
|
1699
|
-
return await withRetry(fetchFn, options.retry);
|
|
1700
|
-
}
|
|
1701
|
-
return await fetchFn();
|
|
1911
|
+
return tag;
|
|
1702
1912
|
}
|
|
1913
|
+
|
|
1914
|
+
// src/api/context.ts
|
|
1703
1915
|
function createBaseConverterContext() {
|
|
1704
1916
|
const linkResolver = /* @__PURE__ */ new Map();
|
|
1705
1917
|
linkResolver.set("page", basePageLinkConverter);
|
|
1706
1918
|
linkResolver.set("article", baseArticleLinkConverter);
|
|
1707
|
-
linkResolver.set(
|
|
1919
|
+
linkResolver.set(
|
|
1920
|
+
"articleType",
|
|
1921
|
+
baseArticleTypeLinkConverter
|
|
1922
|
+
);
|
|
1708
1923
|
linkResolver.set("tag", baseTagLinkConverter);
|
|
1709
1924
|
linkResolver.set("person", basePersonLinkConverter);
|
|
1710
1925
|
linkResolver.set("pageVariant", basePageVariantLinkConverter);
|
|
@@ -1721,6 +1936,8 @@ function createBaseConverterContext() {
|
|
|
1721
1936
|
navigationItemResolver: baseNavigationItemConverter,
|
|
1722
1937
|
articleResolver: baseArticleConverter,
|
|
1723
1938
|
articleTypeResolver: baseArticleTypeConverter,
|
|
1939
|
+
tagResolver: baseTagConverter,
|
|
1940
|
+
customTypeResolver: baseCustomTypeConverter,
|
|
1724
1941
|
componentResolver: baseComponentConverter,
|
|
1725
1942
|
collectionResolver: baseCollectionConverter,
|
|
1726
1943
|
linkResolver,
|
|
@@ -1728,279 +1945,26 @@ function createBaseConverterContext() {
|
|
|
1728
1945
|
videoPrefix: ""
|
|
1729
1946
|
};
|
|
1730
1947
|
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
{
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
"fields.articleType.fields.slug": articleTypeSlug,
|
|
1748
|
-
include: 10,
|
|
1749
|
-
locale: options?.locale,
|
|
1750
|
-
limit: 1
|
|
1751
|
-
},
|
|
1752
|
-
requestOptions
|
|
1753
|
-
);
|
|
1754
|
-
const articleEntry = response.items[0];
|
|
1755
|
-
if (!articleEntry || !articleEntry.fields) {
|
|
1756
|
-
return { data: null, errors: [] };
|
|
1757
|
-
}
|
|
1758
|
-
const assets = convertAllAssets(response, context);
|
|
1759
|
-
const includes = convertAllIncludes(response);
|
|
1760
|
-
const fullContext = {
|
|
1761
|
-
...context,
|
|
1762
|
-
includes,
|
|
1763
|
-
assets,
|
|
1764
|
-
errors: []
|
|
1765
|
-
};
|
|
1766
|
-
try {
|
|
1767
|
-
const converted = fullContext.articleResolver(fullContext, articleEntry);
|
|
1768
|
-
if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
1769
|
-
console.error("CMS conversion errors for article:", {
|
|
1770
|
-
articleId: articleEntry.sys.id,
|
|
1771
|
-
slug,
|
|
1772
|
-
articleTypeSlug,
|
|
1773
|
-
errors: fullContext.errors
|
|
1774
|
-
});
|
|
1775
|
-
}
|
|
1776
|
-
return { data: converted, errors: fullContext.errors };
|
|
1777
|
-
} catch (error) {
|
|
1778
|
-
const entryId = articleEntry.sys.id;
|
|
1779
|
-
const entryType = articleEntry.sys.contentType?.sys?.id;
|
|
1780
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
1781
|
-
const cmsError = {
|
|
1782
|
-
entryId,
|
|
1783
|
-
entryType,
|
|
1784
|
-
message: errorMessage,
|
|
1785
|
-
error
|
|
1786
|
-
};
|
|
1787
|
-
return { data: null, errors: [cmsError] };
|
|
1788
|
-
}
|
|
1789
|
-
};
|
|
1790
|
-
if (options?.retry) {
|
|
1791
|
-
return await withRetry(fetchFn, options.retry);
|
|
1792
|
-
}
|
|
1793
|
-
return await fetchFn();
|
|
1794
|
-
}
|
|
1795
|
-
async function contentfulArticleTypeRest(context, config, slug, options) {
|
|
1796
|
-
const client = getContentfulClient(config, options?.preview);
|
|
1797
|
-
const cacheTags = getCacheTags("articleType", slug, options?.preview);
|
|
1798
|
-
const requestOptions = {
|
|
1799
|
-
...options,
|
|
1800
|
-
next: {
|
|
1801
|
-
...options?.next,
|
|
1802
|
-
tags: cacheTags
|
|
1803
|
-
}
|
|
1804
|
-
};
|
|
1805
|
-
const fetchFn = async () => {
|
|
1806
|
-
const response = await client.getEntries(
|
|
1807
|
-
{
|
|
1808
|
-
content_type: "articleType",
|
|
1809
|
-
"fields.slug": slug,
|
|
1810
|
-
include: 10,
|
|
1811
|
-
locale: options?.locale,
|
|
1812
|
-
limit: 1
|
|
1813
|
-
},
|
|
1814
|
-
requestOptions
|
|
1815
|
-
);
|
|
1816
|
-
const articleTypeEntry = response.items[0];
|
|
1817
|
-
if (!articleTypeEntry || !articleTypeEntry.fields) {
|
|
1818
|
-
return { data: null, errors: [] };
|
|
1819
|
-
}
|
|
1820
|
-
const assets = convertAllAssets(response, context);
|
|
1821
|
-
const includes = convertAllIncludes(response);
|
|
1822
|
-
const fullContext = {
|
|
1823
|
-
...context,
|
|
1824
|
-
includes,
|
|
1825
|
-
assets,
|
|
1826
|
-
errors: []
|
|
1827
|
-
};
|
|
1828
|
-
try {
|
|
1829
|
-
const converted = fullContext.articleTypeResolver(fullContext, articleTypeEntry);
|
|
1830
|
-
if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
1831
|
-
console.error("CMS conversion errors for article type:", {
|
|
1832
|
-
articleTypeId: articleTypeEntry.sys.id,
|
|
1833
|
-
slug,
|
|
1834
|
-
errors: fullContext.errors
|
|
1835
|
-
});
|
|
1836
|
-
}
|
|
1837
|
-
return { data: converted, errors: fullContext.errors };
|
|
1838
|
-
} catch (error) {
|
|
1839
|
-
const entryId = articleTypeEntry.sys.id;
|
|
1840
|
-
const entryType = articleTypeEntry.sys.contentType?.sys?.id;
|
|
1841
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
1842
|
-
const cmsError = {
|
|
1843
|
-
entryId,
|
|
1844
|
-
entryType,
|
|
1845
|
-
message: errorMessage,
|
|
1846
|
-
error
|
|
1847
|
-
};
|
|
1848
|
-
return { data: null, errors: [cmsError] };
|
|
1849
|
-
}
|
|
1850
|
-
};
|
|
1851
|
-
if (options?.retry) {
|
|
1852
|
-
return await withRetry(fetchFn, options.retry);
|
|
1853
|
-
}
|
|
1854
|
-
return await fetchFn();
|
|
1855
|
-
}
|
|
1856
|
-
function baseArticleLinkConverterWithMetadata(context, entry) {
|
|
1857
|
-
const baseLink = baseArticleLinkConverter(context, entry);
|
|
1858
|
-
return {
|
|
1859
|
-
...baseLink,
|
|
1860
|
-
date: entry.fields.date ? new Date(entry.fields.date) : void 0,
|
|
1861
|
-
author: entry.fields.author ? resolveLink(context, baseLink.id, entry.fields.author) : void 0,
|
|
1862
|
-
articleType: entry.fields.articleType ? resolveLink(context, baseLink.id, entry.fields.articleType) : void 0
|
|
1863
|
-
};
|
|
1864
|
-
}
|
|
1865
|
-
async function getAllArticlesForRelated(context, config, options) {
|
|
1866
|
-
const client = getContentfulClient(config, options?.preview);
|
|
1867
|
-
const allArticles = [];
|
|
1868
|
-
const errors = [];
|
|
1869
|
-
const pageSize = 100;
|
|
1870
|
-
let skip = 0;
|
|
1871
|
-
let hasMore = true;
|
|
1872
|
-
const cacheTags = getCacheTags("article", void 0, options?.preview);
|
|
1873
|
-
const requestOptions = {
|
|
1874
|
-
...options,
|
|
1875
|
-
next: {
|
|
1876
|
-
...options?.next,
|
|
1877
|
-
tags: cacheTags
|
|
1878
|
-
}
|
|
1879
|
-
};
|
|
1880
|
-
const fetchFn = async () => {
|
|
1881
|
-
while (hasMore) {
|
|
1882
|
-
const response = await client.getEntries(
|
|
1883
|
-
{
|
|
1884
|
-
content_type: "article",
|
|
1885
|
-
"fields.indexed": true,
|
|
1886
|
-
"fields.hidden[ne]": true,
|
|
1887
|
-
order: "-fields.date",
|
|
1888
|
-
include: 2,
|
|
1889
|
-
// Shallow include - just enough for tags, articleType, author
|
|
1890
|
-
locale: options?.locale,
|
|
1891
|
-
limit: pageSize,
|
|
1892
|
-
skip,
|
|
1893
|
-
select: ARTICLE_RELATED_FIELDS
|
|
1894
|
-
},
|
|
1895
|
-
requestOptions
|
|
1896
|
-
);
|
|
1897
|
-
if (response.items.length === 0) {
|
|
1898
|
-
hasMore = false;
|
|
1899
|
-
break;
|
|
1900
|
-
}
|
|
1901
|
-
const assets = convertAllAssets(response, context);
|
|
1902
|
-
const includes = convertAllIncludes(response);
|
|
1903
|
-
const fullContext = {
|
|
1904
|
-
...context,
|
|
1905
|
-
includes,
|
|
1906
|
-
assets,
|
|
1907
|
-
errors: []
|
|
1908
|
-
};
|
|
1909
|
-
for (const entry of response.items) {
|
|
1910
|
-
if (!entry.fields) continue;
|
|
1911
|
-
try {
|
|
1912
|
-
const converted = baseArticleLinkConverterWithMetadata(fullContext, entry);
|
|
1913
|
-
allArticles.push(converted);
|
|
1914
|
-
} catch (error) {
|
|
1915
|
-
const entryId = entry.sys.id;
|
|
1916
|
-
const entryType = entry.sys.contentType?.sys?.id;
|
|
1917
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
1918
|
-
errors.push({
|
|
1919
|
-
entryId,
|
|
1920
|
-
entryType,
|
|
1921
|
-
message: errorMessage,
|
|
1922
|
-
error
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
skip += pageSize;
|
|
1927
|
-
if (skip >= response.total) {
|
|
1928
|
-
hasMore = false;
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
return { data: allArticles, errors };
|
|
1932
|
-
};
|
|
1933
|
-
if (options?.retry) {
|
|
1934
|
-
return await withRetry(fetchFn, options.retry);
|
|
1935
|
-
}
|
|
1936
|
-
return await fetchFn();
|
|
1937
|
-
}
|
|
1938
|
-
async function fetchAllLinks(contentType, client, requestOptions, converter, context, pageSize = 100, select) {
|
|
1939
|
-
const allLinks = [];
|
|
1940
|
-
const errors = [];
|
|
1941
|
-
let skip = 0;
|
|
1942
|
-
let hasMore = true;
|
|
1943
|
-
const fetchFn = async () => {
|
|
1944
|
-
while (hasMore) {
|
|
1945
|
-
try {
|
|
1946
|
-
const response = await client.getEntries(
|
|
1947
|
-
{
|
|
1948
|
-
content_type: contentType,
|
|
1949
|
-
include: 2,
|
|
1950
|
-
// Minimal include for link-only fetching
|
|
1951
|
-
locale: requestOptions?.locale,
|
|
1952
|
-
limit: pageSize,
|
|
1953
|
-
skip,
|
|
1954
|
-
...select && { select }
|
|
1955
|
-
},
|
|
1956
|
-
requestOptions
|
|
1957
|
-
);
|
|
1958
|
-
if (response.items.length === 0) {
|
|
1959
|
-
hasMore = false;
|
|
1960
|
-
break;
|
|
1961
|
-
}
|
|
1962
|
-
const includes = convertAllIncludes(response);
|
|
1963
|
-
const assets = convertAllAssets(response, context);
|
|
1964
|
-
const fullContext = {
|
|
1965
|
-
...context,
|
|
1966
|
-
includes,
|
|
1967
|
-
assets,
|
|
1968
|
-
errors: []
|
|
1969
|
-
};
|
|
1970
|
-
for (const entry of response.items) {
|
|
1971
|
-
if (!entry.fields) continue;
|
|
1972
|
-
try {
|
|
1973
|
-
const converted = converter(
|
|
1974
|
-
fullContext,
|
|
1975
|
-
entry
|
|
1976
|
-
);
|
|
1977
|
-
converted.lastModified = entry.sys.updatedAt ? new Date(entry.sys.updatedAt) : void 0;
|
|
1978
|
-
allLinks.push(converted);
|
|
1979
|
-
} catch (error) {
|
|
1980
|
-
const entryId = entry.sys.id;
|
|
1981
|
-
const entryType = entry.sys.contentType?.sys?.id;
|
|
1982
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
|
|
1983
|
-
errors.push({
|
|
1984
|
-
entryId,
|
|
1985
|
-
entryType,
|
|
1986
|
-
message: errorMessage,
|
|
1987
|
-
error
|
|
1988
|
-
});
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
skip += pageSize;
|
|
1992
|
-
if (skip >= response.total) {
|
|
1993
|
-
hasMore = false;
|
|
1994
|
-
}
|
|
1995
|
-
} catch (error) {
|
|
1996
|
-
console.error("Error fetching links", typeof error, error, JSON.stringify(error, null, 2));
|
|
1997
|
-
throw error;
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
return { data: allLinks, errors };
|
|
2001
|
-
};
|
|
2002
|
-
return await fetchFn();
|
|
1948
|
+
|
|
1949
|
+
// src/api/custom-type.ts
|
|
1950
|
+
async function contentfulCustomTypeRest(context, config, indexPageSlug, options) {
|
|
1951
|
+
return fetchSingleEntity(
|
|
1952
|
+
context,
|
|
1953
|
+
config,
|
|
1954
|
+
{
|
|
1955
|
+
contentType: "customType",
|
|
1956
|
+
cacheTagType: "customType",
|
|
1957
|
+
cacheTagIdentifier: indexPageSlug,
|
|
1958
|
+
query: { "fields.indexPageSlug": indexPageSlug },
|
|
1959
|
+
resolver: (ctx, entry) => ctx.customTypeResolver(ctx, entry),
|
|
1960
|
+
errorLogContext: { indexPageSlug }
|
|
1961
|
+
},
|
|
1962
|
+
options
|
|
1963
|
+
);
|
|
2003
1964
|
}
|
|
1965
|
+
|
|
1966
|
+
// src/api/links.ts
|
|
1967
|
+
init_utils();
|
|
2004
1968
|
async function contentfulAllPageLinks(context, config, options) {
|
|
2005
1969
|
const client = getContentfulClient(config, options?.preview);
|
|
2006
1970
|
const cacheTags = getCacheTags("page", void 0, options?.preview);
|
|
@@ -2121,34 +2085,67 @@ async function contentfulAllArticleTypeLinks(context, config, options) {
|
|
|
2121
2085
|
}
|
|
2122
2086
|
return await fetchFn();
|
|
2123
2087
|
}
|
|
2088
|
+
|
|
2089
|
+
// src/api/page.ts
|
|
2090
|
+
async function contentfulPageRest(context, config, slug, options) {
|
|
2091
|
+
return fetchSingleEntity(
|
|
2092
|
+
context,
|
|
2093
|
+
config,
|
|
2094
|
+
{
|
|
2095
|
+
contentType: "page",
|
|
2096
|
+
cacheTagType: "page",
|
|
2097
|
+
cacheTagIdentifier: slug,
|
|
2098
|
+
query: { "fields.slug": slug },
|
|
2099
|
+
resolver: (ctx, entry) => ctx.pageResolver(ctx, entry),
|
|
2100
|
+
errorLogContext: { slug }
|
|
2101
|
+
},
|
|
2102
|
+
options
|
|
2103
|
+
);
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// src/api/related-articles.ts
|
|
2124
2107
|
function filterRelatedArticles(articles, options) {
|
|
2125
|
-
const {
|
|
2108
|
+
const {
|
|
2109
|
+
excludeArticleIds,
|
|
2110
|
+
articleTypeIds: rawArticleTypeIds,
|
|
2111
|
+
tagIds: rawTagIds,
|
|
2112
|
+
authorIds: rawAuthorIds,
|
|
2113
|
+
before,
|
|
2114
|
+
after,
|
|
2115
|
+
count
|
|
2116
|
+
} = options;
|
|
2117
|
+
const excludeIds = excludeArticleIds ? [...new Set(excludeArticleIds)] : [];
|
|
2118
|
+
const articleTypeIds = rawArticleTypeIds ? [...new Set(rawArticleTypeIds)] : [];
|
|
2119
|
+
const tagIds = rawTagIds ? [...new Set(rawTagIds)] : [];
|
|
2120
|
+
const authorIds = rawAuthorIds ? [...new Set(rawAuthorIds)] : [];
|
|
2126
2121
|
const scoredArticles = articles.map((article) => {
|
|
2127
2122
|
let score = 0;
|
|
2128
|
-
if (excludeIds
|
|
2129
|
-
return null;
|
|
2130
|
-
}
|
|
2131
|
-
if (articleTypeId && article.articleType?.id !== articleTypeId) {
|
|
2123
|
+
if (excludeIds.length > 0 && excludeIds.includes(article.id)) {
|
|
2132
2124
|
return null;
|
|
2133
2125
|
}
|
|
2134
|
-
if (
|
|
2135
|
-
|
|
2126
|
+
if (articleTypeIds.length > 0) {
|
|
2127
|
+
if (!article.articleType?.id || !articleTypeIds.includes(article.articleType.id)) {
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2136
2130
|
}
|
|
2137
2131
|
if (article.date) {
|
|
2138
|
-
|
|
2132
|
+
const articleDate = new Date(article.date);
|
|
2133
|
+
if (before && articleDate > before) {
|
|
2139
2134
|
return null;
|
|
2140
2135
|
}
|
|
2141
|
-
if (after &&
|
|
2136
|
+
if (after && articleDate < after) {
|
|
2142
2137
|
return null;
|
|
2143
2138
|
}
|
|
2144
2139
|
}
|
|
2145
|
-
if (tagIds
|
|
2140
|
+
if (tagIds.length > 0 && article.tags) {
|
|
2146
2141
|
const articleTagIds = article.tags.map((tag) => tag.id);
|
|
2147
2142
|
const matchingTags = tagIds.filter((tagId) => articleTagIds.includes(tagId));
|
|
2148
2143
|
score += matchingTags.length * 10;
|
|
2149
2144
|
}
|
|
2150
|
-
if (
|
|
2151
|
-
|
|
2145
|
+
if (authorIds.length > 0 && article.author?.id) {
|
|
2146
|
+
if (authorIds.includes(article.author.id)) {
|
|
2147
|
+
score += 5;
|
|
2148
|
+
}
|
|
2152
2149
|
}
|
|
2153
2150
|
return { article, score };
|
|
2154
2151
|
}).filter((item) => item !== null);
|
|
@@ -2157,16 +2154,17 @@ function filterRelatedArticles(articles, options) {
|
|
|
2157
2154
|
return b.score - a.score;
|
|
2158
2155
|
}
|
|
2159
2156
|
if (a.article.date && b.article.date) {
|
|
2160
|
-
|
|
2157
|
+
const articleDateA = new Date(a.article.date);
|
|
2158
|
+
const articleDateB = new Date(b.article.date);
|
|
2159
|
+
return articleDateB.getTime() - articleDateA.getTime();
|
|
2161
2160
|
}
|
|
2162
2161
|
return 0;
|
|
2163
2162
|
});
|
|
2164
|
-
const topArticles = count ? scoredArticles.slice(0, count) : scoredArticles;
|
|
2165
|
-
return topArticles.map(({ article }) =>
|
|
2166
|
-
const { date: _date, author: _author, articleType: _articleType, ...cleanLink } = article;
|
|
2167
|
-
return cleanLink;
|
|
2168
|
-
});
|
|
2163
|
+
const topArticles = count !== void 0 ? scoredArticles.slice(0, count) : scoredArticles;
|
|
2164
|
+
return topArticles.map(({ article }) => article);
|
|
2169
2165
|
}
|
|
2166
|
+
|
|
2167
|
+
// src/api/sitemap.ts
|
|
2170
2168
|
function linksToSitemapEntries(links, sitemapConfig) {
|
|
2171
2169
|
return links.filter((link) => link.indexed !== false && link.hidden !== true && link.href).map((link) => ({
|
|
2172
2170
|
url: link.href,
|
|
@@ -2226,6 +2224,60 @@ function createSitemapProvider(fetcher, sitemapConfig) {
|
|
|
2226
2224
|
return (context, config, options) => fetcher(context, config, sitemapConfig, options);
|
|
2227
2225
|
}
|
|
2228
2226
|
|
|
2227
|
+
// src/api/tag.ts
|
|
2228
|
+
async function contentfulTagRest(context, config, slug, options) {
|
|
2229
|
+
return fetchSingleEntity(
|
|
2230
|
+
context,
|
|
2231
|
+
config,
|
|
2232
|
+
{
|
|
2233
|
+
contentType: "tag",
|
|
2234
|
+
cacheTagType: "tag",
|
|
2235
|
+
cacheTagIdentifier: slug,
|
|
2236
|
+
query: { "fields.slug": slug },
|
|
2237
|
+
resolver: (ctx, entry) => ctx.tagResolver(ctx, entry),
|
|
2238
|
+
errorLogContext: { slug }
|
|
2239
|
+
},
|
|
2240
|
+
options
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
// src/api/template.ts
|
|
2245
|
+
function templateConverter(context, entry) {
|
|
2246
|
+
const { fields, sys } = entry;
|
|
2247
|
+
const id = sys.id;
|
|
2248
|
+
const preContent = fields.preContent?.map((content) => resolvePageContent(context, id, content)).filter((item) => item !== null) ?? [];
|
|
2249
|
+
const postContent = fields.postContent?.map((content) => resolvePageContent(context, id, content)).filter((item) => item !== null) ?? [];
|
|
2250
|
+
const menu = fields.menu ? resolveNavigation(context, fields.menu) : void 0;
|
|
2251
|
+
const footer = fields.footer ? resolveNavigation(context, fields.footer) : void 0;
|
|
2252
|
+
const stickyNav = fields.flags?.includes("Sticky nav") ?? false;
|
|
2253
|
+
return {
|
|
2254
|
+
id,
|
|
2255
|
+
cmsLabel: fields.cmsLabel,
|
|
2256
|
+
preContent,
|
|
2257
|
+
postContent,
|
|
2258
|
+
menu,
|
|
2259
|
+
footer,
|
|
2260
|
+
backgroundColour: fields.backgroundColour,
|
|
2261
|
+
textColour: fields.textColour,
|
|
2262
|
+
stickyNav
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
async function contentfulTemplateRest(context, config, cmsLabel, options) {
|
|
2266
|
+
return fetchSingleEntity(
|
|
2267
|
+
context,
|
|
2268
|
+
config,
|
|
2269
|
+
{
|
|
2270
|
+
contentType: "template",
|
|
2271
|
+
cacheTagType: "template",
|
|
2272
|
+
cacheTagIdentifier: cmsLabel,
|
|
2273
|
+
query: { "fields.cmsLabel": cmsLabel },
|
|
2274
|
+
resolver: (ctx, entry) => templateConverter(ctx, entry),
|
|
2275
|
+
errorLogContext: { cmsLabel }
|
|
2276
|
+
},
|
|
2277
|
+
options
|
|
2278
|
+
);
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2229
2281
|
// src/revalidation/handlers.ts
|
|
2230
2282
|
init_tags();
|
|
2231
2283
|
init_utils();
|
|
@@ -2257,6 +2309,11 @@ var pageVariantHandler = {
|
|
|
2257
2309
|
makeTags: (extracted) => [extracted ? pageTag(extracted) : void 0],
|
|
2258
2310
|
getGlobalTags: () => [PageTag]
|
|
2259
2311
|
};
|
|
2312
|
+
var templateHandler = {
|
|
2313
|
+
extract: (data) => data.fields?.cmsLabel?.[defaultLocale],
|
|
2314
|
+
makeTags: (extracted) => [extracted ? templateTag(extracted) : void 0],
|
|
2315
|
+
getGlobalTags: () => [TemplateTag]
|
|
2316
|
+
};
|
|
2260
2317
|
var contentTypeHandlers = {
|
|
2261
2318
|
page: {
|
|
2262
2319
|
extract: (data) => data.fields?.slug?.[defaultLocale],
|
|
@@ -2278,11 +2335,8 @@ var contentTypeHandlers = {
|
|
|
2278
2335
|
makeTags: (extracted) => [extracted ? tagTag(extracted) : void 0],
|
|
2279
2336
|
getGlobalTags: () => [TagTag]
|
|
2280
2337
|
},
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
makeTags: () => void 0,
|
|
2284
|
-
getGlobalTags: () => ["template"]
|
|
2285
|
-
},
|
|
2338
|
+
// biome-ignore lint/suspicious/noExplicitAny: Any is ok for handlers with different types
|
|
2339
|
+
template: templateHandler,
|
|
2286
2340
|
customType: {
|
|
2287
2341
|
extract: () => void 0,
|
|
2288
2342
|
makeTags: () => void 0,
|
|
@@ -2446,6 +2500,6 @@ function createRevalidationHandler(config = {}) {
|
|
|
2446
2500
|
init_tags();
|
|
2447
2501
|
init_utils();
|
|
2448
2502
|
|
|
2449
|
-
export { AllTags, ArticleTag, ArticleTypeTag, AssetTag, AuthenticationError, BannerTag, ContentfulError, CustomTypeTag, EntryNotFoundError, GlobalTag, LocationTag, NavigationTag, PageTag, PersonTag, RateLimitError, RateLimiter, TagTag, TemplateTag, ValidationError, arrayOrUndefined, articleTag, articleTypeIndexTag, articleTypeTag, assetTag, basePageConverter, calculateBackoffDelay, contentfulAllArticleLinks, contentfulAllArticleTypeLinks, contentfulAllPageLinks, contentfulAllPersonLinks, contentfulAllTagLinks, contentfulArticleRest, contentfulArticleSitemapEntries, contentfulArticleTypeRest, contentfulArticleTypeSitemapEntries, contentfulPageRest, contentfulPageSitemapEntries, contentfulPersonSitemapEntries, contentfulTagSitemapEntries, createBaseConverterContext, createContentfulClient, createContentfulPreviewClient, createResponsiveVisual, createRevalidationHandler, createSitemapProvider, customTypeTag, filterRelatedArticles,
|
|
2503
|
+
export { AllTags, ArticleTag, ArticleTypeTag, AssetTag, AuthenticationError, BannerTag, ContentfulError, CustomTypeTag, EntryNotFoundError, GlobalTag, LocationTag, NavigationTag, PageTag, PersonTag, RateLimitError, RateLimiter, TagTag, TemplateTag, ValidationError, arrayOrUndefined, articleTag, articleTypeIndexTag, articleTypeTag, assetTag, basePageConverter, calculateBackoffDelay, contentfulAllArticleLinks, contentfulAllArticleTypeLinks, contentfulAllPageLinks, contentfulAllPersonLinks, contentfulAllTagLinks, contentfulArticleRest, contentfulArticleSitemapEntries, contentfulArticleTypeRest, contentfulArticleTypeSitemapEntries, contentfulCustomTypeRest, contentfulPageRest, contentfulPageSitemapEntries, contentfulPersonSitemapEntries, contentfulTagRest, contentfulTagSitemapEntries, contentfulTemplateRest, createBaseConverterContext, createContentfulClient, createContentfulPreviewClient, createResponsiveVisual, createRevalidationHandler, createSitemapProvider, customTypeTag, filterRelatedArticles, getAllSitemapEntries, getCacheTags, getCacheTagsForPreview, getCacheTagsForProduction, getContentfulClient, getRetryAfter, isContentfulError, isRateLimitError, isRetryableError, isValidDate, locationTag, lookupAsset, notEmpty, pageTag, personTag, resolveLink, resolveLinks, resolveRichTextDocument, revalidateSingleTag, revalidateTags, safeDate, tagTag, templateTag, withRetry };
|
|
2450
2504
|
//# sourceMappingURL=index.js.map
|
|
2451
2505
|
//# sourceMappingURL=index.js.map
|