@griddo/cx 1.75.178 → 1.75.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +22 -14
  2. package/build/index.js +49 -0
  3. package/gatsby-browser.tsx +140 -0
  4. package/gatsby-config.ts +40 -0
  5. package/gatsby-node.ts +130 -0
  6. package/gatsby-ssr.tsx +63 -0
  7. package/index.js +4 -0
  8. package/package.json +119 -100
  9. package/scripts/build-reset.ts +9 -0
  10. package/scripts/griddo-exporter.ts +302 -0
  11. package/src/components/Head.tsx +207 -0
  12. package/src/components/template.tsx +90 -0
  13. package/src/components/types.ts +35 -0
  14. package/src/components/utils.ts +138 -0
  15. package/src/html.tsx +31 -0
  16. package/src/services/auth.ts +64 -0
  17. package/src/services/distributors.ts +153 -0
  18. package/src/services/domains.ts +27 -0
  19. package/src/services/navigation.ts +169 -0
  20. package/src/services/robots.ts +64 -0
  21. package/src/services/settings.ts +52 -0
  22. package/src/services/sites.ts +199 -0
  23. package/src/services/store-with-for-loop.ts +513 -0
  24. package/src/services/store-with-promise-all.ts +515 -0
  25. package/src/services/store.ts +513 -0
  26. package/src/types/api.ts +155 -0
  27. package/src/types/global.ts +72 -0
  28. package/src/types/navigation.ts +25 -0
  29. package/src/types/pages.ts +145 -0
  30. package/src/types/sites.ts +64 -0
  31. package/src/types/templates.ts +11 -0
  32. package/src/utils/api.ts +326 -0
  33. package/src/utils/cache.ts +114 -0
  34. package/src/utils/domains.ts +32 -0
  35. package/src/utils/folders.ts +147 -0
  36. package/src/utils/instance.ts +71 -0
  37. package/src/utils/pages.ts +534 -0
  38. package/src/utils/searches.ts +102 -0
  39. package/src/utils/shared.ts +131 -0
  40. package/src/utils/sites.ts +280 -0
  41. package/.babelrc +0 -7
  42. package/LICENSE +0 -1
  43. package/gatsby-browser.js +0 -115
  44. package/gatsby-config.js +0 -38
  45. package/gatsby-node.js +0 -273
  46. package/gatsby-ssr.js +0 -43
  47. package/scripts/griddo-exporter.js +0 -133
  48. package/src/api/index.js +0 -172
  49. package/src/components/template.js +0 -261
  50. package/src/html.js +0 -30
  51. package/src/images/readme.md +0 -1
  52. package/src/scripts/build-reset.js +0 -12
  53. package/src/services/auth.js +0 -44
  54. package/src/services/distributors.js +0 -85
  55. package/src/services/domains.js +0 -16
  56. package/src/services/navigation.js +0 -104
  57. package/src/services/robots.js +0 -37
  58. package/src/services/settings.js +0 -25
  59. package/src/services/sites.js +0 -110
  60. package/src/utils/cache.js +0 -70
  61. package/src/utils/component-lib-helpers.js +0 -56
  62. package/src/utils/dataLayer.js +0 -47
  63. package/src/utils/delay.js +0 -5
  64. package/src/utils/domains.js +0 -24
  65. package/src/utils/folders.js +0 -123
  66. package/src/utils/helpers.js +0 -144
  67. package/src/utils/index.js +0 -44
  68. package/src/utils/package.js +0 -20
  69. package/src/utils/pages.js +0 -236
  70. package/src/utils/searches.js +0 -62
  71. package/src/utils/sites.js +0 -207
  72. package/static/griddo-full-logo.png +0 -0
@@ -0,0 +1,534 @@
1
+ // Types
2
+ import type { Core, Fields } from "@griddo/core";
3
+ import type {
4
+ APIPageObject,
5
+ GatsbyPageObject,
6
+ GriddoListPage,
7
+ GriddoMultiPage,
8
+ GriddoSinglePage,
9
+ MultiPageElements,
10
+ PageAdditionalInfo,
11
+ } from "../types/pages";
12
+ import type { TemplateWithDistributor } from "../types/templates";
13
+
14
+ // External libraries
15
+ import dotenv from "dotenv";
16
+ import fs from "fs";
17
+ import path from "path";
18
+
19
+ // Utils
20
+ import { formatImage } from "../components/utils";
21
+ import { postSearchInfo } from "./searches";
22
+
23
+ dotenv.config();
24
+
25
+ // Envs
26
+ const GRIDDO_SEARCH_FEATURE = !!JSON.parse(
27
+ process.env.GRIDDO_SEARCH_FEATURE || "false"
28
+ );
29
+ const HAS_ASSET_PREFIX = !!process.env.GRIDDO_ASSET_PREFIX;
30
+
31
+ // Constants
32
+ const DEFAULT_ITEMS_PER_PAGE_FOR_LIST_TEMPLATES = 25;
33
+ const COMPONENT = path.resolve(__dirname, "../../src/components/template.tsx");
34
+
35
+ /**
36
+ * Return an OpenGraph object.
37
+ *
38
+ * @param props.socialTitle The social title.
39
+ * @param props.socialDescription The social description.
40
+ * @param props.socialImage The social image in Cloudinary or DAM url format.
41
+ */
42
+ function getOpenGraph({
43
+ socialTitle,
44
+ socialDescription,
45
+ socialImage,
46
+ }: Pick<
47
+ Core.Page,
48
+ "socialTitle" | "socialDescription" | "socialImage"
49
+ >): Core.Page["openGraph"] {
50
+ return {
51
+ type: "website",
52
+ title: socialTitle,
53
+ description: socialDescription,
54
+ image: socialImage ? formatImage(socialImage, 1280, 768) : "",
55
+ twitterImage: socialImage ? formatImage(socialImage, 1280, 768) : "",
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Get the Page metadata object from a page Object.
61
+ *
62
+ * @param params A Page object
63
+ */
64
+ function getPageMetaData(params: Core.Page): Core.Page["pageMetaData"] {
65
+ const {
66
+ title,
67
+ metaTitle,
68
+ metaDescription,
69
+ canonicalURL,
70
+ locale,
71
+ url,
72
+ isIndexed,
73
+ follow,
74
+ metasAdvanced,
75
+ pageLanguages,
76
+ fullUrl,
77
+ } = params;
78
+
79
+ const metasAdvancedList =
80
+ metasAdvanced
81
+ ?.split(",")
82
+ .filter(Boolean)
83
+ .map((item) => item.trim().toLowerCase()) || [];
84
+
85
+ return {
86
+ title: (metaTitle || title || "").trim(),
87
+ description: metaDescription,
88
+ canonical:
89
+ canonicalURL && canonicalURL.trim() && canonicalURL !== fullUrl
90
+ ? canonicalURL.trim()
91
+ : isIndexed
92
+ ? fullUrl
93
+ : undefined,
94
+ locale,
95
+ url,
96
+ index: isIndexed ? "index" : "noindex",
97
+ follow: follow ? "follow" : "nofollow",
98
+ translate: metasAdvancedList.includes("notranslate") ? "notranslate" : "",
99
+ metasAdvanced: metasAdvancedList
100
+ .filter((item) => item !== "notranslate")
101
+ .join(),
102
+ pageLanguages,
103
+ };
104
+ }
105
+
106
+ /**
107
+ * Create a page object to be processes by Gatsby `createPage()`
108
+ *
109
+ * @param page A page object ready to pass as content of the `pageContext` to use in the React template.
110
+ * @param additionalInfo Additional page info to pass as content of `pageContext` to use in the React template.
111
+ */
112
+ async function createGatsbyPageObject(
113
+ page: GriddoSinglePage | GriddoListPage | GriddoMultiPage,
114
+ additionalInfo: PageAdditionalInfo
115
+ ): Promise<GatsbyPageObject> {
116
+ // Extract some props from page
117
+ const {
118
+ id,
119
+ title,
120
+ fullPath,
121
+ language: languageId,
122
+ breadcrumb,
123
+ socialDescription,
124
+ socialImage,
125
+ socialTitle,
126
+ } = page;
127
+
128
+ // Extract some props from additionalInfo
129
+ const {
130
+ baseUrl,
131
+ BUILD_MODE,
132
+ cloudinaryName,
133
+ griddoVersion,
134
+ siteLangs,
135
+ siteMetadata,
136
+ siteOptions,
137
+ siteScript,
138
+ siteSlug,
139
+ socials,
140
+ theme,
141
+ navigations: { header, footer },
142
+ } = additionalInfo;
143
+
144
+ // Update page object
145
+ page = {
146
+ ...page,
147
+ breadcrumb,
148
+ siteSlug,
149
+ apiUrl: baseUrl,
150
+ publicApiUrl: additionalInfo.publicBaseUrl,
151
+ instance: additionalInfo.instance,
152
+ };
153
+
154
+ const filepath = `${fullPath?.domain}${fullPath?.compose}`;
155
+ const foundLanguage = siteLangs.find(({ id }) => id === page?.language);
156
+ const locale = foundLanguage?.locale.replace(/_/g, "-");
157
+
158
+ // Page Metadata
159
+ const pageMetadata = getPageMetaData(page);
160
+
161
+ // Opengraph
162
+ const openGraph = getOpenGraph({
163
+ socialDescription,
164
+ socialImage,
165
+ socialTitle,
166
+ });
167
+
168
+ const pageObjectForGatsby = {
169
+ matchPath: "",
170
+ path: filepath,
171
+ component: COMPONENT,
172
+ size: 0,
173
+ context: {
174
+ // Page
175
+ id,
176
+ title,
177
+ fullPath,
178
+ locale,
179
+ languageId,
180
+ theme,
181
+
182
+ // PARA <Helmet />
183
+ siteMetadata,
184
+ pageMetadata,
185
+ openGraph,
186
+ socials,
187
+ siteLangs,
188
+ cloudinaryName,
189
+ siteOptions,
190
+ BUILD_MODE,
191
+ griddoVersion,
192
+ siteScript,
193
+
194
+ // Navigation sections
195
+ header,
196
+ footer,
197
+
198
+ // Page template
199
+ page,
200
+ },
201
+ };
202
+
203
+ const assetPrefix =
204
+ fullPath?.domain.startsWith("/pro-") && HAS_ASSET_PREFIX
205
+ ? process.env.GRIDDO_ASSET_PREFIX
206
+ : undefined;
207
+
208
+ if (assetPrefix) {
209
+ pageObjectForGatsby.matchPath = fullPath?.compose as string;
210
+ }
211
+
212
+ if (GRIDDO_SEARCH_FEATURE) {
213
+ const exportFile = path.resolve(
214
+ __dirname,
215
+ "../../dist/",
216
+ `./${filepath}index.html`
217
+ );
218
+ const content = fs.existsSync(exportFile)
219
+ ? fs.readFileSync(exportFile).toString()
220
+ : "";
221
+
222
+ await postSearchInfo({
223
+ title,
224
+ description: openGraph.description || "",
225
+ image: openGraph.image || "",
226
+ pageId: id,
227
+ languageId,
228
+ // Dont know if page.template_id is something old
229
+ // template: page.template_id || page?.template?.templateType || null,
230
+ template: page?.template?.templateType || null,
231
+ siteId: page.site,
232
+ url: page.fullUrl,
233
+ content,
234
+ });
235
+ }
236
+
237
+ return pageObjectForGatsby;
238
+ }
239
+
240
+ /**
241
+ * Create a single Griddo page object.
242
+ *
243
+ * @param page A Griddo single page object.
244
+ * @param additionalInfo Additional page info.
245
+ */
246
+ async function createGriddoSinglePage(
247
+ page: GriddoSinglePage,
248
+ additionalInfo: PageAdditionalInfo
249
+ ) {
250
+ return await createGatsbyPageObject(page, additionalInfo);
251
+ }
252
+
253
+ /**
254
+ * Create multiples pages from one page as list paginated pages
255
+ */
256
+ async function createGriddoListPages(
257
+ {
258
+ page,
259
+ pages,
260
+ isRoot = false,
261
+ defaultLang,
262
+ template,
263
+ totalQueriedItems,
264
+ }: GriddoListPage,
265
+ additionalInfo: PageAdditionalInfo
266
+ ) {
267
+ const allPages = pages.map(async (dataInPage, idx) => {
268
+ const isFirstPage = idx === 0;
269
+ const pageNumber = idx + 1;
270
+ const { domainUrl, compose } = page.fullPath;
271
+
272
+ const paginatedPage = {
273
+ ...page,
274
+ fullPath: {
275
+ ...page.fullPath,
276
+ // Add a page number (tailPageNumber) from page 2 onwards
277
+ compose: addPageNumberToUrl(compose, pageNumber, {
278
+ addEndingSlash: true,
279
+ }),
280
+ },
281
+ fullUrl: addPageNumberToUrl(page.fullUrl, pageNumber, {
282
+ addEndingSlash: true,
283
+ }),
284
+ slug: addPageNumberToUrl(page.slug, pageNumber),
285
+ title: addPageNumberToTitle(page.title, pageNumber),
286
+ metaTitle: addPageNumberToTitle(page.metaTitle || "", pageNumber),
287
+ disableHrefLangs: pageNumber > 1,
288
+ template: {
289
+ ...template,
290
+ isFirstPage,
291
+ pageNumber,
292
+ totalPages: pages.length,
293
+ // The base link, without page number to use in <Pagination />
294
+ // component.
295
+ baseLink: `${domainUrl}${compose}`,
296
+ queriedItems: dataInPage,
297
+ totalQueriedItems: totalQueriedItems?.length,
298
+ },
299
+ isRoot,
300
+ defaultLang,
301
+ };
302
+
303
+ return await createGatsbyPageObject(paginatedPage, additionalInfo);
304
+ });
305
+
306
+ return Promise.all(allPages);
307
+ }
308
+
309
+ /**
310
+ * Create multiples pages from a MultiPage module
311
+ *
312
+ * @param page A Griddo Multipage object.
313
+ * @param additionalInfo Additional page info.
314
+ */
315
+ function createGriddoMultiPages(
316
+ page: GriddoMultiPage,
317
+ additionalInfo: PageAdditionalInfo
318
+ ) {
319
+ const { multiPageElements: multiPageElementsBulk, ...cleanPage } = page;
320
+ // TODO: Use structuredClone() when node 18 is available.
321
+ const multiPageElements: MultiPageElements = JSON.parse(
322
+ JSON.stringify(multiPageElementsBulk)
323
+ );
324
+
325
+ // si no hay un elemento sin slug, como mínimo hay que dibujar una página principal para el conjunto de páginas
326
+ if (
327
+ !multiPageElements.find(
328
+ ({ sectionSlug }: { sectionSlug: string }) => sectionSlug === "/"
329
+ )
330
+ ) {
331
+ // @ts-expect-error
332
+ multiPageElements.push({});
333
+ }
334
+
335
+ // Creates each page based on `multiPageElements` from the schema.
336
+ const allPages = multiPageElements.map(async (pageElement) => {
337
+ // TODO: Use structuredClone() when node 18 is available.
338
+ const paginatedPage: APIPageObject = JSON.parse(JSON.stringify(cleanPage));
339
+ const {
340
+ sectionSlug = "/",
341
+ title: bulkTitle = "",
342
+ metaTitle = "",
343
+ metaDescription = "",
344
+ } = pageElement;
345
+ const title = typeof bulkTitle === "string" ? bulkTitle : bulkTitle.content;
346
+ const compose = paginatedPage.fullPath.compose || "";
347
+ const fullUrl = paginatedPage.fullUrl.endsWith("/")
348
+ ? paginatedPage.fullUrl.slice(0, -1)
349
+ : paginatedPage.fullUrl;
350
+ const rightSectionSlug = sectionSlug?.replace(/\//g, "");
351
+ const slash = compose.endsWith("/") ? "" : "/";
352
+ const newCompose = `${compose}${slash}${rightSectionSlug}`;
353
+
354
+ if (title.trim()) {
355
+ paginatedPage.title = title;
356
+ }
357
+
358
+ if (metaDescription.trim()) {
359
+ paginatedPage.metaDescription = metaDescription;
360
+ }
361
+
362
+ paginatedPage.fullUrl = `${fullUrl}/${rightSectionSlug}`;
363
+ paginatedPage.fullPath.compose = newCompose;
364
+ paginatedPage.slug = newCompose;
365
+ paginatedPage.template.activeSectionSlug = sectionSlug;
366
+ paginatedPage.template.activeSectionBase = fullUrl;
367
+ paginatedPage.metaTitle =
368
+ metaTitle.trim() || title.trim() || paginatedPage.metaTitle;
369
+
370
+ return await createGatsbyPageObject(paginatedPage, additionalInfo);
371
+ });
372
+
373
+ return Promise.all(allPages);
374
+ }
375
+
376
+ /**
377
+ * Get the multi pages elements.
378
+ *
379
+ * @param page The page to get the multipage parts.
380
+ */
381
+ function getMultiPageElements(page: TemplateWithDistributor) {
382
+ const multiPageElements = new Promise((resolve) => {
383
+ // Recursive
384
+ const getMultiPageComponent = (
385
+ // No puede ser Core.Page['template'] porque a medida que va bajando en
386
+ // el árbol ya no es la estructura de un template.
387
+ template: Record<string, any>,
388
+ level = 0
389
+ ) => {
390
+ // If it doesn't have a "template strcuture"
391
+ if (!template || typeof template !== "object") return;
392
+
393
+ // For each prop in the "template"
394
+ for (const key in template) {
395
+ const currentComponent = template[key];
396
+ const isValidComponent =
397
+ currentComponent || typeof currentComponent === "object";
398
+ const hasGriddoMultiPageProp = JSON.stringify(
399
+ currentComponent
400
+ ).includes('"hasGriddoMultiPage":true');
401
+
402
+ if (!isValidComponent) continue;
403
+
404
+ if (!hasGriddoMultiPageProp) continue;
405
+
406
+ const { component, hasGriddoMultiPage, elements } = currentComponent;
407
+
408
+ if (component && hasGriddoMultiPage) resolve(elements || []);
409
+
410
+ // Recursive call
411
+ getMultiPageComponent(currentComponent, level + 1);
412
+ }
413
+
414
+ // resolve promise when...
415
+ if (!level) resolve(null);
416
+ };
417
+
418
+ getMultiPageComponent([page]); // ==> En array para que también revise la propia template como objeto.
419
+ });
420
+
421
+ return multiPageElements as Promise<MultiPageElements>;
422
+ }
423
+
424
+ // -----------------------------------------------------------------------------
425
+ // Private functions
426
+ // -----------------------------------------------------------------------------
427
+
428
+ /**
429
+ * Get `itemsPerPage` elements from the `items` using as offset `page` number.
430
+ * It's a kind of paginator for an array.
431
+ *
432
+ * @param itemsPerPage The items per page.
433
+ * @param items An array of items, the queriedData.
434
+ * @param page The page to be returned.
435
+ *
436
+ * @example
437
+ * getPage(3, ["a", "b", "c", "d", "e", "f", "g", "h"], 2)
438
+ * // -> ["d", "e", "f"]
439
+ */
440
+ function getPage(
441
+ itemsPerPage: number,
442
+ items: Array<Fields.QueriedDataItem>,
443
+ page: number
444
+ ) {
445
+ return items?.slice(itemsPerPage * (page - 1), itemsPerPage * page);
446
+ }
447
+
448
+ /**
449
+ * Takes an array of items and split it grouping in arrays of pages based on `itemsPerPage`.
450
+ *
451
+ * @param itemsPerPage The items per page.
452
+ * @param items An array of items, the queriedData.
453
+ *
454
+ * @example
455
+ * getPageCluster(3, ["a", "b", "c", "d", "e", "f", "g", "h"])
456
+ * // -> [["a", "b", "c"], ["d", "e", "f"], ["g", "h"]]
457
+ */
458
+ function getPageCluster(
459
+ itemsPerPage: number,
460
+ items: Array<Fields.QueriedDataItem>
461
+ ) {
462
+ const totalPagesCount = Math.ceil(items.length / itemsPerPage) || 1;
463
+ const pageNumbers = Array.from({ length: totalPagesCount }, (_, i) => i + 1);
464
+
465
+ return pageNumbers?.map((pageNumber) =>
466
+ getPage(itemsPerPage, items, pageNumber)
467
+ );
468
+ }
469
+
470
+ /**
471
+ * Takes a template object and split the whole queriedItems into separated queriedItems to use in Griddo static list templates.
472
+ *
473
+ * @param listTemplate A template schema with the distributor data included.
474
+ */
475
+ function getPaginatedPages(listTemplate: TemplateWithDistributor) {
476
+ const items = listTemplate.queriedItems || [];
477
+ const itemsPerPage =
478
+ listTemplate?.itemsPerPage || DEFAULT_ITEMS_PER_PAGE_FOR_LIST_TEMPLATES;
479
+ const pageClusters = getPageCluster(itemsPerPage, items);
480
+
481
+ return pageClusters;
482
+ }
483
+
484
+ /**
485
+ * Adds a number to an URL adding optionally an ending slash.
486
+ *
487
+ * @param url The url.
488
+ * @param pageNumber A number to be added to the url.
489
+ * @param options.addEndingSlash Boolean that indicates if return the final url with an end slash or not.
490
+ *
491
+ * @example
492
+ * addPageNumberToUrl("web.com", 3) // "web.com/3"
493
+ * addPageNumberToUrl("web.com", 3, { addEndingSlash: true }) // "web.com/3/"
494
+ */
495
+
496
+ function addPageNumberToUrl(
497
+ url: string,
498
+ pageNumber: number,
499
+ options?: { addEndingSlash: boolean }
500
+ ) {
501
+ const trailingSlash = url.endsWith("/") ? "" : "/";
502
+ const endingSlash = options?.addEndingSlash ? "/" : "";
503
+
504
+ if (pageNumber <= 1) {
505
+ return `${url}${endingSlash}`;
506
+ }
507
+
508
+ return `${url}${trailingSlash}${pageNumber}${endingSlash}`;
509
+ }
510
+
511
+ /**
512
+ * Adds a number to an string with the format "string - number"
513
+ *
514
+ * @param title The title
515
+ * @param pageNumber A number to be added to the title.
516
+ *
517
+ * @example
518
+ * addPageNumberToTitle("The page", 3) // "The page - 3"
519
+ */
520
+ function addPageNumberToTitle(title: string, pageNumber: number) {
521
+ if (!title || pageNumber <= 1) {
522
+ return title;
523
+ }
524
+
525
+ return `${title} - ${pageNumber}`;
526
+ }
527
+
528
+ export {
529
+ createGriddoListPages,
530
+ createGriddoMultiPages,
531
+ createGriddoSinglePage,
532
+ getMultiPageElements,
533
+ getPaginatedPages,
534
+ };
@@ -0,0 +1,102 @@
1
+ // Types
2
+ import type { PostSearchInfoProps } from "../types/global";
3
+
4
+ // API
5
+ import { post } from "./api";
6
+
7
+ // Envs
8
+ const API_URL = process.env.API_URL as string;
9
+
10
+ /**
11
+ * Save in the BBDD the content of a page parsed without HTML tags.
12
+ *
13
+ * @param props Object with parts of the final page object to be saved in the BBDD.
14
+ */
15
+ async function postSearchInfo(props: PostSearchInfoProps) {
16
+ const {
17
+ title,
18
+ description,
19
+ image,
20
+ pageId,
21
+ languageId,
22
+ siteId,
23
+ url,
24
+ content,
25
+ template,
26
+ } = props;
27
+
28
+ const response = await post({
29
+ endpoint: `${API_URL}/search`,
30
+ body: {
31
+ title,
32
+ description,
33
+ image,
34
+ pageId,
35
+ languageId,
36
+ siteId,
37
+ url,
38
+ template,
39
+ content: prepareHTMLContentForSearch(content),
40
+ },
41
+ });
42
+
43
+ return response;
44
+ }
45
+
46
+ /**
47
+ * Remove the every cntent inside some HTML tags including them.
48
+ *
49
+ * @param content A string with the content.
50
+ */
51
+ function prepareHTMLContentForSearch(content: string) {
52
+ const noTagsContent = removeHTMLTags(
53
+ ["meta", "link", "style", "script", "noscript", "nav", "header", "footer"],
54
+ content
55
+ );
56
+ const plainTextContent = stripHTMLTags(noTagsContent);
57
+
58
+ return stripSpaces(plainTextContent);
59
+ }
60
+
61
+ /**
62
+ * Removes (replacing with empty string) the content for the HTML tags and the tags themself from the content string.
63
+ *
64
+ * @param tags An array of HTML tags without the <>.
65
+ * @param content The content string.
66
+ */
67
+ function removeHTMLTags(tags: Array<string>, content: string) {
68
+ let filteredContent = content;
69
+
70
+ tags.forEach((tag) => {
71
+ filteredContent = filteredContent
72
+ // eslint-disable-next-line no-useless-escape
73
+ .replace(new RegExp(`<${tag}.*?>.*?<\/${tag}>`, "gis"), " ")
74
+ .replace(new RegExp(`(<${tag}([^>]+)>)`, "gis"), " ");
75
+ });
76
+
77
+ return filteredContent;
78
+ }
79
+
80
+ /**
81
+ * Remove every HTML tags from the content
82
+ *
83
+ * @param content The string to be processed.
84
+ * @param replaceWith The string to replace the remove HTML tags.
85
+ */
86
+ function stripHTMLTags(content: string) {
87
+ return content.replace(/(<([^>]+)>)/gis, " ");
88
+ }
89
+
90
+ /**
91
+ * Removes duplicate whitespaces
92
+ *
93
+ * @param str The string to remove white spaces
94
+ *
95
+ * @example
96
+ * stripSpaces(" Lorem ipsum dolor ") // " Lorem ipsum dolor "
97
+ */
98
+ function stripSpaces(str: string) {
99
+ return str.replace(/\s+/g, " ");
100
+ }
101
+
102
+ export { postSearchInfo };