@sitecore-content-sdk/content 1.5.0-canary.5

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 (258) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +7 -0
  3. package/client.d.ts +1 -0
  4. package/codegen.d.ts +1 -0
  5. package/config-cli.d.ts +1 -0
  6. package/config.d.ts +1 -0
  7. package/dist/cjs/client/edge-proxy.js +24 -0
  8. package/dist/cjs/client/index.js +14 -0
  9. package/dist/cjs/client/models.js +2 -0
  10. package/dist/cjs/client/sitecore-client.js +420 -0
  11. package/dist/cjs/client/utils.js +53 -0
  12. package/dist/cjs/config/define-config.js +195 -0
  13. package/dist/cjs/config/index.js +7 -0
  14. package/dist/cjs/config/models.js +12 -0
  15. package/dist/cjs/config-cli/define-cli-config.js +23 -0
  16. package/dist/cjs/config-cli/index.js +7 -0
  17. package/dist/cjs/config-cli/models.js +8 -0
  18. package/dist/cjs/constants.js +12 -0
  19. package/dist/cjs/debug.js +21 -0
  20. package/dist/cjs/editing/codegen/index.js +14 -0
  21. package/dist/cjs/editing/codegen/preview.js +277 -0
  22. package/dist/cjs/editing/component-layout-service.js +62 -0
  23. package/dist/cjs/editing/design-library.js +184 -0
  24. package/dist/cjs/editing/editing-service.js +81 -0
  25. package/dist/cjs/editing/index.js +33 -0
  26. package/dist/cjs/editing/models.js +44 -0
  27. package/dist/cjs/editing/utils.js +105 -0
  28. package/dist/cjs/form/form.js +81 -0
  29. package/dist/cjs/form/index.js +7 -0
  30. package/dist/cjs/i18n/dictionary-service.js +144 -0
  31. package/dist/cjs/i18n/index.js +7 -0
  32. package/dist/cjs/i18n/utils.js +16 -0
  33. package/dist/cjs/index.js +47 -0
  34. package/dist/cjs/layout/content-styles.js +73 -0
  35. package/dist/cjs/layout/index.js +24 -0
  36. package/dist/cjs/layout/layout-service.js +68 -0
  37. package/dist/cjs/layout/models.js +39 -0
  38. package/dist/cjs/layout/themes.js +77 -0
  39. package/dist/cjs/layout/utils.js +117 -0
  40. package/dist/cjs/media/index.js +38 -0
  41. package/dist/cjs/media/media-api.js +100 -0
  42. package/dist/cjs/models.js +2 -0
  43. package/dist/cjs/personalize/index.js +15 -0
  44. package/dist/cjs/personalize/layout-personalizer.js +98 -0
  45. package/dist/cjs/personalize/personalize-service.js +109 -0
  46. package/dist/cjs/personalize/utils.js +143 -0
  47. package/dist/cjs/site/error-pages-service.js +82 -0
  48. package/dist/cjs/site/index.js +26 -0
  49. package/dist/cjs/site/models.js +2 -0
  50. package/dist/cjs/site/redirects-service.js +109 -0
  51. package/dist/cjs/site/robots-service.js +74 -0
  52. package/dist/cjs/site/site-resolver.js +73 -0
  53. package/dist/cjs/site/siteinfo-service.js +94 -0
  54. package/dist/cjs/site/sitemap-xml-service.js +92 -0
  55. package/dist/cjs/site/sitepath-service.js +201 -0
  56. package/dist/cjs/site/utils.js +55 -0
  57. package/dist/cjs/sitecore-service-base.js +33 -0
  58. package/dist/cjs/tools/codegen/component-generation.js +49 -0
  59. package/dist/cjs/tools/codegen/extract-files.js +105 -0
  60. package/dist/cjs/tools/codegen/import-map.js +411 -0
  61. package/dist/cjs/tools/codegen/utils.js +418 -0
  62. package/dist/cjs/tools/generate-map.js +2 -0
  63. package/dist/cjs/tools/generateSites.js +59 -0
  64. package/dist/cjs/tools/index.js +30 -0
  65. package/dist/cjs/tools/scaffold.js +62 -0
  66. package/dist/cjs/tools/templating/components.js +96 -0
  67. package/dist/cjs/tools/templating/index.js +6 -0
  68. package/dist/esm/client/edge-proxy.js +19 -0
  69. package/dist/esm/client/index.js +4 -0
  70. package/dist/esm/client/models.js +1 -0
  71. package/dist/esm/client/sitecore-client.js +416 -0
  72. package/dist/esm/client/utils.js +49 -0
  73. package/dist/esm/config/define-config.js +189 -0
  74. package/dist/esm/config/index.js +2 -0
  75. package/dist/esm/config/models.js +9 -0
  76. package/dist/esm/config-cli/define-cli-config.js +19 -0
  77. package/dist/esm/config-cli/index.js +2 -0
  78. package/dist/esm/config-cli/models.js +5 -0
  79. package/dist/esm/constants.js +9 -0
  80. package/dist/esm/debug.js +19 -0
  81. package/dist/esm/editing/codegen/index.js +1 -0
  82. package/dist/esm/editing/codegen/preview.js +263 -0
  83. package/dist/esm/editing/component-layout-service.js +55 -0
  84. package/dist/esm/editing/design-library.js +172 -0
  85. package/dist/esm/editing/editing-service.js +74 -0
  86. package/dist/esm/editing/index.js +6 -0
  87. package/dist/esm/editing/models.js +41 -0
  88. package/dist/esm/editing/utils.js +98 -0
  89. package/dist/esm/form/form.js +72 -0
  90. package/dist/esm/form/index.js +1 -0
  91. package/dist/esm/i18n/dictionary-service.js +137 -0
  92. package/dist/esm/i18n/index.js +2 -0
  93. package/dist/esm/i18n/utils.js +13 -0
  94. package/dist/esm/index.js +5 -0
  95. package/dist/esm/layout/content-styles.js +65 -0
  96. package/dist/esm/layout/index.js +6 -0
  97. package/dist/esm/layout/layout-service.js +61 -0
  98. package/dist/esm/layout/models.js +36 -0
  99. package/dist/esm/layout/themes.js +72 -0
  100. package/dist/esm/layout/utils.js +109 -0
  101. package/dist/esm/media/index.js +2 -0
  102. package/dist/esm/media/media-api.js +90 -0
  103. package/dist/esm/models.js +1 -0
  104. package/dist/esm/personalize/index.js +3 -0
  105. package/dist/esm/personalize/layout-personalizer.js +93 -0
  106. package/dist/esm/personalize/personalize-service.js +102 -0
  107. package/dist/esm/personalize/utils.js +135 -0
  108. package/dist/esm/site/error-pages-service.js +75 -0
  109. package/dist/esm/site/index.js +8 -0
  110. package/dist/esm/site/models.js +1 -0
  111. package/dist/esm/site/redirects-service.js +102 -0
  112. package/dist/esm/site/robots-service.js +67 -0
  113. package/dist/esm/site/site-resolver.js +69 -0
  114. package/dist/esm/site/siteinfo-service.js +87 -0
  115. package/dist/esm/site/sitemap-xml-service.js +85 -0
  116. package/dist/esm/site/sitepath-service.js +193 -0
  117. package/dist/esm/site/utils.js +49 -0
  118. package/dist/esm/sitecore-service-base.js +29 -0
  119. package/dist/esm/tools/codegen/component-generation.js +44 -0
  120. package/dist/esm/tools/codegen/extract-files.js +99 -0
  121. package/dist/esm/tools/codegen/import-map.js +368 -0
  122. package/dist/esm/tools/codegen/utils.js +373 -0
  123. package/dist/esm/tools/generate-map.js +1 -0
  124. package/dist/esm/tools/generateSites.js +52 -0
  125. package/dist/esm/tools/index.js +6 -0
  126. package/dist/esm/tools/scaffold.js +54 -0
  127. package/dist/esm/tools/templating/components.js +59 -0
  128. package/dist/esm/tools/templating/index.js +1 -0
  129. package/editing.d.ts +1 -0
  130. package/i18n.d.ts +1 -0
  131. package/layout.d.ts +1 -0
  132. package/media.d.ts +1 -0
  133. package/package.json +157 -0
  134. package/personalize.d.ts +1 -0
  135. package/site.d.ts +1 -0
  136. package/tools.d.ts +1 -0
  137. package/types/client/edge-proxy.d.ts +17 -0
  138. package/types/client/edge-proxy.d.ts.map +1 -0
  139. package/types/client/index.d.ts +7 -0
  140. package/types/client/index.d.ts.map +1 -0
  141. package/types/client/models.d.ts +21 -0
  142. package/types/client/models.d.ts.map +1 -0
  143. package/types/client/sitecore-client.d.ts +338 -0
  144. package/types/client/sitecore-client.d.ts.map +1 -0
  145. package/types/client/utils.d.ts +15 -0
  146. package/types/client/utils.d.ts.map +1 -0
  147. package/types/config/define-config.d.ts +20 -0
  148. package/types/config/define-config.d.ts.map +1 -0
  149. package/types/config/index.d.ts +3 -0
  150. package/types/config/index.d.ts.map +1 -0
  151. package/types/config/models.d.ts +287 -0
  152. package/types/config/models.d.ts.map +1 -0
  153. package/types/config-cli/define-cli-config.d.ts +9 -0
  154. package/types/config-cli/define-cli-config.d.ts.map +1 -0
  155. package/types/config-cli/index.d.ts +3 -0
  156. package/types/config-cli/index.d.ts.map +1 -0
  157. package/types/config-cli/models.d.ts +6 -0
  158. package/types/config-cli/models.d.ts.map +1 -0
  159. package/types/constants.d.ts +10 -0
  160. package/types/constants.d.ts.map +1 -0
  161. package/types/debug.d.ts +19 -0
  162. package/types/debug.d.ts.map +1 -0
  163. package/types/editing/codegen/index.d.ts +2 -0
  164. package/types/editing/codegen/index.d.ts.map +1 -0
  165. package/types/editing/codegen/preview.d.ts +256 -0
  166. package/types/editing/codegen/preview.d.ts.map +1 -0
  167. package/types/editing/component-layout-service.d.ts +84 -0
  168. package/types/editing/component-layout-service.d.ts.map +1 -0
  169. package/types/editing/design-library.d.ts +111 -0
  170. package/types/editing/design-library.d.ts.map +1 -0
  171. package/types/editing/editing-service.d.ts +71 -0
  172. package/types/editing/editing-service.d.ts.map +1 -0
  173. package/types/editing/index.d.ts +7 -0
  174. package/types/editing/index.d.ts.map +1 -0
  175. package/types/editing/models.d.ts +103 -0
  176. package/types/editing/models.d.ts.map +1 -0
  177. package/types/editing/utils.d.ts +82 -0
  178. package/types/editing/utils.d.ts.map +1 -0
  179. package/types/form/form.d.ts +25 -0
  180. package/types/form/form.d.ts.map +1 -0
  181. package/types/form/index.d.ts +2 -0
  182. package/types/form/index.d.ts.map +1 -0
  183. package/types/i18n/dictionary-service.d.ts +133 -0
  184. package/types/i18n/dictionary-service.d.ts.map +1 -0
  185. package/types/i18n/index.d.ts +3 -0
  186. package/types/i18n/index.d.ts.map +1 -0
  187. package/types/i18n/utils.d.ts +9 -0
  188. package/types/i18n/utils.d.ts.map +1 -0
  189. package/types/index.d.ts +7 -0
  190. package/types/index.d.ts.map +1 -0
  191. package/types/layout/content-styles.d.ts +20 -0
  192. package/types/layout/content-styles.d.ts.map +1 -0
  193. package/types/layout/index.d.ts +6 -0
  194. package/types/layout/index.d.ts.map +1 -0
  195. package/types/layout/layout-service.d.ts +45 -0
  196. package/types/layout/layout-service.d.ts.map +1 -0
  197. package/types/layout/models.d.ts +174 -0
  198. package/types/layout/models.d.ts.map +1 -0
  199. package/types/layout/themes.d.ts +13 -0
  200. package/types/layout/themes.d.ts.map +1 -0
  201. package/types/layout/utils.d.ts +56 -0
  202. package/types/layout/utils.d.ts.map +1 -0
  203. package/types/media/index.d.ts +3 -0
  204. package/types/media/index.d.ts.map +1 -0
  205. package/types/media/media-api.d.ts +60 -0
  206. package/types/media/media-api.d.ts.map +1 -0
  207. package/types/models.d.ts +32 -0
  208. package/types/models.d.ts.map +1 -0
  209. package/types/personalize/index.d.ts +4 -0
  210. package/types/personalize/index.d.ts.map +1 -0
  211. package/types/personalize/layout-personalizer.d.ts +29 -0
  212. package/types/personalize/layout-personalizer.d.ts.map +1 -0
  213. package/types/personalize/personalize-service.d.ts +89 -0
  214. package/types/personalize/personalize-service.d.ts.map +1 -0
  215. package/types/personalize/utils.d.ts +78 -0
  216. package/types/personalize/utils.d.ts.map +1 -0
  217. package/types/site/error-pages-service.d.ts +64 -0
  218. package/types/site/error-pages-service.d.ts.map +1 -0
  219. package/types/site/index.d.ts +10 -0
  220. package/types/site/index.d.ts.map +1 -0
  221. package/types/site/models.d.ts +23 -0
  222. package/types/site/models.d.ts.map +1 -0
  223. package/types/site/redirects-service.d.ts +91 -0
  224. package/types/site/redirects-service.d.ts.map +1 -0
  225. package/types/site/robots-service.d.ts +57 -0
  226. package/types/site/robots-service.d.ts.map +1 -0
  227. package/types/site/site-resolver.d.ts +28 -0
  228. package/types/site/site-resolver.d.ts.map +1 -0
  229. package/types/site/siteinfo-service.d.ts +64 -0
  230. package/types/site/siteinfo-service.d.ts.map +1 -0
  231. package/types/site/sitemap-xml-service.d.ts +63 -0
  232. package/types/site/sitemap-xml-service.d.ts.map +1 -0
  233. package/types/site/sitepath-service.d.ts +137 -0
  234. package/types/site/sitepath-service.d.ts.map +1 -0
  235. package/types/site/utils.d.ts +41 -0
  236. package/types/site/utils.d.ts.map +1 -0
  237. package/types/sitecore-service-base.d.ts +31 -0
  238. package/types/sitecore-service-base.d.ts.map +1 -0
  239. package/types/tools/codegen/component-generation.d.ts +50 -0
  240. package/types/tools/codegen/component-generation.d.ts.map +1 -0
  241. package/types/tools/codegen/extract-files.d.ts +24 -0
  242. package/types/tools/codegen/extract-files.d.ts.map +1 -0
  243. package/types/tools/codegen/import-map.d.ts +103 -0
  244. package/types/tools/codegen/import-map.d.ts.map +1 -0
  245. package/types/tools/codegen/utils.d.ts +76 -0
  246. package/types/tools/codegen/utils.d.ts.map +1 -0
  247. package/types/tools/generate-map.d.ts +36 -0
  248. package/types/tools/generate-map.d.ts.map +1 -0
  249. package/types/tools/generateSites.d.ts +25 -0
  250. package/types/tools/generateSites.d.ts.map +1 -0
  251. package/types/tools/index.d.ts +8 -0
  252. package/types/tools/index.d.ts.map +1 -0
  253. package/types/tools/scaffold.d.ts +27 -0
  254. package/types/tools/scaffold.d.ts.map +1 -0
  255. package/types/tools/templating/components.d.ts +104 -0
  256. package/types/tools/templating/components.d.ts.map +1 -0
  257. package/types/tools/templating/index.d.ts +2 -0
  258. package/types/tools/templating/index.d.ts.map +1 -0
@@ -0,0 +1,65 @@
1
+ import { normalizeUrl } from '@sitecore-content-sdk/core/tools';
2
+ import { constants } from '@sitecore-content-sdk/core';
3
+ const { SITECORE_EDGE_URL_DEFAULT } = constants;
4
+ /**
5
+ * Regular expression to check if the content styles are used in the field value
6
+ */
7
+ const CLASS_REGEXP = /class=".*(\bck-content\b).*"/g;
8
+ /**
9
+ * Get the content styles link to be loaded from the Sitecore Edge Platform
10
+ * @param {LayoutServiceData} layoutData Layout service data
11
+ * @param {string} sitecoreEdgeContextId Sitecore Edge Context ID
12
+ * @param {string} [sitecoreEdgeUrl] Sitecore Edge Platform URL. Default is https://edge-platform.sitecorecloud.io
13
+ * @returns {HTMLLink | null} content styles link, null if no styles are used in layout
14
+ * @public
15
+ */
16
+ export const getContentStylesheetLink = (layoutData, sitecoreEdgeContextId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) => {
17
+ if (!layoutData.sitecore.route)
18
+ return null;
19
+ const config = { loadStyles: false };
20
+ traverseComponent(layoutData.sitecore.route, config);
21
+ if (!config.loadStyles)
22
+ return null;
23
+ return {
24
+ href: getContentStylesheetUrl(sitecoreEdgeContextId, sitecoreEdgeUrl),
25
+ rel: 'stylesheet',
26
+ };
27
+ };
28
+ export const getContentStylesheetUrl = (sitecoreEdgeContextId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) => `${normalizeUrl(sitecoreEdgeUrl)}/v1/files/pages/styles/content-styles.css?sitecoreContextId=${sitecoreEdgeContextId}`;
29
+ export const traversePlaceholder = (components, config) => {
30
+ if (config.loadStyles)
31
+ return;
32
+ components.forEach((component) => {
33
+ traverseComponent(component, config);
34
+ });
35
+ };
36
+ export const traverseField = (field, config) => {
37
+ if (!field || typeof field !== 'object' || config.loadStyles)
38
+ return;
39
+ if ('value' in field && typeof field.value === 'string') {
40
+ config.loadStyles = CLASS_REGEXP.test(field.value);
41
+ }
42
+ else if ('fields' in field) {
43
+ Object.values(field.fields).forEach((field) => {
44
+ traverseField(field, config);
45
+ });
46
+ }
47
+ else if (Array.isArray(field)) {
48
+ field.forEach((field) => {
49
+ traverseField(field, config);
50
+ });
51
+ }
52
+ };
53
+ export const traverseComponent = (component, config) => {
54
+ if (config.loadStyles)
55
+ return;
56
+ if ('fields' in component && component.fields) {
57
+ Object.values(component.fields).forEach((field) => {
58
+ traverseField(field, config);
59
+ });
60
+ }
61
+ const placeholders = component.placeholders || {};
62
+ Object.keys(placeholders).forEach((placeholder) => {
63
+ traversePlaceholder(placeholders[placeholder], config);
64
+ });
65
+ };
@@ -0,0 +1,6 @@
1
+ // layout
2
+ export { LayoutServicePageState, EditMode, RenderingType, EDITING_COMPONENT_PLACEHOLDER, EDITING_COMPONENT_ID, } from './models';
3
+ export { getFieldValue, getChildPlaceholder, isFieldValueEmpty, isDynamicPlaceholder, getDynamicPlaceholderPattern, EMPTY_DATE_FIELD_VALUE, } from './utils';
4
+ export { getContentStylesheetLink } from './content-styles';
5
+ export { LayoutService, GRAPHQL_LAYOUT_QUERY_NAME } from './layout-service';
6
+ export { getDesignLibraryStylesheetLinks } from './themes';
@@ -0,0 +1,61 @@
1
+ import { SitecoreServiceBase } from '../sitecore-service-base';
2
+ import debug from '../debug';
3
+ /**
4
+ * GraphQL layout query name
5
+ * @internal
6
+ */
7
+ export const GRAPHQL_LAYOUT_QUERY_NAME = 'ContentSdkLayoutQuery';
8
+ /**
9
+ * Service that fetch layout data using Sitecore's GraphQL API.
10
+ * @augments LayoutServiceBase
11
+ * @mixes GraphQLRequestClient
12
+ * @public
13
+ */
14
+ export class LayoutService extends SitecoreServiceBase {
15
+ /**
16
+ * Fetch layout data using the Sitecore GraphQL endpoint.
17
+ * @param {LayoutServiceConfig} serviceConfig configuration
18
+ */
19
+ constructor(serviceConfig) {
20
+ super(serviceConfig);
21
+ this.serviceConfig = serviceConfig;
22
+ }
23
+ /**
24
+ * Fetch layout data for an item.
25
+ * @param {string} itemPath item path to fetch layout data for.
26
+ * @param {RouteOptions} [routeOptions] Request options like language and site to retrieve data for
27
+ * @param {FetchOptions} [fetchOptions] Options to override graphQL client details like retries and fetch implementation
28
+ * @returns {Promise<LayoutServiceData>} layout service data
29
+ */
30
+ async fetchLayoutData(itemPath, routeOptions, fetchOptions) {
31
+ var _a, _b;
32
+ const site = routeOptions.site;
33
+ const query = this.getLayoutQuery(itemPath, site, routeOptions === null || routeOptions === void 0 ? void 0 : routeOptions.locale);
34
+ debug.layout('fetching layout data for %s %s %s', itemPath, routeOptions === null || routeOptions === void 0 ? void 0 : routeOptions.locale, site);
35
+ const data = await this.graphQLClient.request(query, {}, fetchOptions);
36
+ // If `rendered` is empty -> not found
37
+ return (((_b = (_a = data === null || data === void 0 ? void 0 : data.layout) === null || _a === void 0 ? void 0 : _a.item) === null || _b === void 0 ? void 0 : _b.rendered) || {
38
+ sitecore: { context: { pageEditing: false, language: routeOptions === null || routeOptions === void 0 ? void 0 : routeOptions.locale }, route: null },
39
+ });
40
+ }
41
+ /**
42
+ * Returns GraphQL Layout query
43
+ * @param {string} itemPath page route
44
+ * @param {string} [site] site name
45
+ * @param {string} [language] language
46
+ * @returns {string} GraphQL query
47
+ */
48
+ getLayoutQuery(itemPath, site, language) {
49
+ const languageVariable = language ? `, language:"${language}"` : '';
50
+ const layoutQuery = this.serviceConfig.formatLayoutQuery
51
+ ? this.serviceConfig.formatLayoutQuery(site, itemPath, language)
52
+ : `layout(site:"${site}", routePath:"${itemPath}"${languageVariable})`;
53
+ return `query ${GRAPHQL_LAYOUT_QUERY_NAME} {
54
+ ${layoutQuery}{
55
+ item {
56
+ rendered
57
+ }
58
+ }
59
+ }`;
60
+ }
61
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Layout Service page state enum
3
+ * @public
4
+ */
5
+ export var LayoutServicePageState;
6
+ (function (LayoutServicePageState) {
7
+ LayoutServicePageState["Preview"] = "preview";
8
+ LayoutServicePageState["Edit"] = "edit";
9
+ LayoutServicePageState["Normal"] = "normal";
10
+ })(LayoutServicePageState || (LayoutServicePageState = {}));
11
+ /**
12
+ * Represents the edit mode for rendering content in Sitecore Editors
13
+ * @public
14
+ */
15
+ export var EditMode;
16
+ (function (EditMode) {
17
+ EditMode["Metadata"] = "metadata";
18
+ })(EditMode || (EditMode = {}));
19
+ /**
20
+ * Editing rendering type
21
+ * @public
22
+ */
23
+ export var RenderingType;
24
+ (function (RenderingType) {
25
+ RenderingType["Component"] = "component";
26
+ })(RenderingType || (RenderingType = {}));
27
+ /**
28
+ * Static placeholder name used for component rendering
29
+ * @internal
30
+ */
31
+ export const EDITING_COMPONENT_PLACEHOLDER = 'editing-componentmode-placeholder';
32
+ /**
33
+ * Id of wrapper for component rendering
34
+ * @internal
35
+ */
36
+ export const EDITING_COMPONENT_ID = 'editing-component';
@@ -0,0 +1,72 @@
1
+ import { normalizeUrl } from '@sitecore-content-sdk/core/tools';
2
+ import { constants } from '@sitecore-content-sdk/core';
3
+ import { getFieldValue } from '.';
4
+ const { SITECORE_EDGE_URL_DEFAULT } = constants;
5
+ /**
6
+ * Pattern for library ids
7
+ * @example -library--foo
8
+ */
9
+ const STYLES_LIBRARY_ID_REGEX = /-library--([^\s]+)/;
10
+ /**
11
+ * Walks through rendering tree and returns list of links of all FEAAS, BYOC or SXA Design Library Stylesheets that are used
12
+ * @param {LayoutServiceData} layoutData Layout service data
13
+ * @param {string} sitecoreEdgeContextId Sitecore Edge Context ID
14
+ * @param {string} [sitecoreEdgeUrl] Sitecore Edge Platform URL. Default is https://edge-platform.sitecorecloud.io
15
+ * @returns {HTMLLink[]} library stylesheet links
16
+ * @public
17
+ */
18
+ export function getDesignLibraryStylesheetLinks(layoutData, sitecoreEdgeContextId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) {
19
+ const ids = new Set();
20
+ if (!layoutData.sitecore.route)
21
+ return [];
22
+ traverseComponent(layoutData.sitecore.route, ids);
23
+ return [...ids].map((id) => ({
24
+ href: getStylesheetUrl(id, sitecoreEdgeContextId, sitecoreEdgeUrl),
25
+ rel: 'stylesheet',
26
+ }));
27
+ }
28
+ export const getStylesheetUrl = (id, sitecoreEdgeContextId, sitecoreEdgeUrl = SITECORE_EDGE_URL_DEFAULT) => {
29
+ return `${normalizeUrl(sitecoreEdgeUrl)}/v1/files/components/styles/${id}.css?sitecoreContextId=${sitecoreEdgeContextId}`;
30
+ };
31
+ /**
32
+ * Traverse placeholder and components to add library ids
33
+ * @param {ComponentRendering[]} components
34
+ * @param {Set<string>} ids library ids
35
+ */
36
+ const traversePlaceholder = (components, ids) => {
37
+ components.map((component) => {
38
+ return traverseComponent(component, ids);
39
+ });
40
+ };
41
+ /**
42
+ * Traverse component and children to add library ids
43
+ * @param {RouteData | ComponentRendering | HtmlElementRendering} component component data
44
+ * @param {Set<string>} ids library ids
45
+ */
46
+ const traverseComponent = (component, ids) => {
47
+ var _a, _b, _c, _d, _e, _f;
48
+ let libraryId = undefined;
49
+ if ('params' in component && component.params) {
50
+ // LibraryID in css class name takes precedence over LibraryId attribute
51
+ libraryId =
52
+ ((_b = (_a = component.params.CSSStyles) === null || _a === void 0 ? void 0 : _a.match(STYLES_LIBRARY_ID_REGEX)) === null || _b === void 0 ? void 0 : _b[1]) ||
53
+ ((_d = (_c = component.params.Styles) === null || _c === void 0 ? void 0 : _c.match(STYLES_LIBRARY_ID_REGEX)) === null || _d === void 0 ? void 0 : _d[1]) ||
54
+ component.params.LibraryId ||
55
+ undefined;
56
+ }
57
+ // if params are empty we try to fall back to data source
58
+ if (!libraryId && 'fields' in component && component.fields) {
59
+ libraryId =
60
+ ((_e = getFieldValue(component.fields, 'CSSStyles', '').match(STYLES_LIBRARY_ID_REGEX)) === null || _e === void 0 ? void 0 : _e[1]) ||
61
+ ((_f = getFieldValue(component.fields, 'Styles', '').match(STYLES_LIBRARY_ID_REGEX)) === null || _f === void 0 ? void 0 : _f[1]) ||
62
+ getFieldValue(component.fields, 'LibraryId', '') ||
63
+ undefined;
64
+ }
65
+ if (libraryId) {
66
+ ids.add(libraryId);
67
+ }
68
+ const placeholders = component.placeholders || {};
69
+ Object.keys(placeholders).forEach((placeholder) => {
70
+ traversePlaceholder(placeholders[placeholder], ids);
71
+ });
72
+ };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @param {ComponentRendering | Fields} renderingOrFields the rendering or fields object to extract the field from
3
+ * @param {string} fieldName the name of the field to extract
4
+ * @param {T} [defaultValue] the default value to return if the field is not defined
5
+ * @returns {Field | T} the field value or the default value if the field is not defined
6
+ * @public
7
+ */
8
+ // eslint-disable-next-line no-redeclare
9
+ export function getFieldValue(renderingOrFields, fieldName, defaultValue) {
10
+ if (!renderingOrFields || !fieldName) {
11
+ return defaultValue;
12
+ }
13
+ const fields = renderingOrFields;
14
+ const field = fields[fieldName];
15
+ if (field && typeof field.value !== 'undefined') {
16
+ return field.value;
17
+ }
18
+ const rendering = renderingOrFields;
19
+ if (!rendering.fields ||
20
+ !rendering.fields[fieldName] ||
21
+ typeof rendering.fields[fieldName].value === 'undefined') {
22
+ return defaultValue;
23
+ }
24
+ return rendering.fields[fieldName].value;
25
+ }
26
+ /**
27
+ * Gets rendering definitions in a given child placeholder under a current rendering.
28
+ * @param {ComponentRendering} rendering
29
+ * @param {string} placeholderName
30
+ * @returns {ComponentRendering[]} child placeholder
31
+ * @public
32
+ */
33
+ export function getChildPlaceholder(rendering, placeholderName) {
34
+ if (!rendering ||
35
+ !placeholderName ||
36
+ !rendering.placeholders ||
37
+ !rendering.placeholders[placeholderName]) {
38
+ return [];
39
+ }
40
+ return rendering.placeholders[placeholderName];
41
+ }
42
+ /**
43
+ * Returns a regular expression pattern for a dynamic placeholder name.
44
+ * @param {string} placeholder Placeholder name with a dynamic segment (e.g. 'main-{*}')
45
+ * @returns Regular expression pattern for the dynamic segment
46
+ * @internal
47
+ */
48
+ export const getDynamicPlaceholderPattern = (placeholder) => {
49
+ return new RegExp(`^${placeholder.replace(/\{\*\}+/i, '\\d+')}$`);
50
+ };
51
+ /**
52
+ * Checks if the placeholder name is dynamic.
53
+ * @param {string} placeholder Placeholder name
54
+ * @returns True if the placeholder name is dynamic
55
+ * @internal
56
+ */
57
+ export const isDynamicPlaceholder = (placeholder) => placeholder.indexOf('{*}') !== -1;
58
+ /**
59
+ * The default value for an empty Date field.
60
+ * This value is defined as a default one by .NET
61
+ * @internal
62
+ */
63
+ export const EMPTY_DATE_FIELD_VALUE = '0001-01-01T00:00:00Z';
64
+ /**
65
+ * Determines if the passed in field object's value is empty.
66
+ * @param {GenericFieldValue | Partial<Field>} field the field object.
67
+ * Partial<T> type is used here because _field.value_ could be required or optional for the different field types
68
+ * @returns True if the field value is empty
69
+ * @public
70
+ */
71
+ export function isFieldValueEmpty(field) {
72
+ if (!field)
73
+ return true;
74
+ const isImageFieldEmpty = (fieldValue) => !fieldValue.src;
75
+ const isFileFieldEmpty = (fieldValue) => !fieldValue.src;
76
+ const isLinkFieldEmpty = (fieldValue) => !fieldValue.href;
77
+ const isDateFieldEmpty = (fieldValue) => {
78
+ if (typeof fieldValue === 'string') {
79
+ return fieldValue === EMPTY_DATE_FIELD_VALUE;
80
+ }
81
+ else {
82
+ return !(typeof (fieldValue === null || fieldValue === void 0 ? void 0 : fieldValue.getMonth) === 'function' &&
83
+ !isNaN(fieldValue === null || fieldValue === void 0 ? void 0 : fieldValue.getMonth()));
84
+ }
85
+ };
86
+ const isEmpty = (fieldValue) => {
87
+ if (fieldValue === null || fieldValue === undefined) {
88
+ return true;
89
+ }
90
+ if (typeof fieldValue === 'object') {
91
+ return (isImageFieldEmpty(fieldValue) &&
92
+ isFileFieldEmpty(fieldValue) &&
93
+ isLinkFieldEmpty(fieldValue) &&
94
+ isDateFieldEmpty(fieldValue));
95
+ }
96
+ else if (typeof fieldValue === 'number' || typeof fieldValue === 'boolean') {
97
+ // Avoid returning true for 0 and false values
98
+ return false;
99
+ }
100
+ else {
101
+ return !fieldValue || isDateFieldEmpty(fieldValue);
102
+ }
103
+ };
104
+ const dynamicField = field;
105
+ if (dynamicField.value !== undefined) {
106
+ return isEmpty(dynamicField.value);
107
+ }
108
+ return isEmpty(field);
109
+ }
@@ -0,0 +1,2 @@
1
+ import * as mediaApi from './media-api';
2
+ export { mediaApi };
@@ -0,0 +1,90 @@
1
+ import URL from 'url-parse';
2
+ // finds the Sitecore media URL prefix
3
+ const mediaUrlPrefixRegex = /\/([-~]{1})\/media\//i;
4
+ /**
5
+ * Get required query string params which should be merged with user params
6
+ * @param {object} qs layout service parsed query string
7
+ * @returns {object} requiredParams
8
+ * @public
9
+ */
10
+ export const getRequiredParams = (qs) => {
11
+ const { rev, db, la, vs, ts } = qs;
12
+ return { rev, db, la, vs, ts };
13
+ };
14
+ /**
15
+ * Replace `/~/media` or `/-/media` with `/~/jssmedia` or `/-/jssmedia`, respectively.
16
+ * Can use `mediaUrlPrefix` in order to use a custom prefix.
17
+ * @param {string} url The URL to replace the media URL prefix in
18
+ * @param {RegExp} [mediaUrlPrefix] The regex to match the media URL prefix
19
+ * @returns {string} The URL with the media URL prefix replaced
20
+ * @public
21
+ */
22
+ export const replaceMediaUrlPrefix = (url, mediaUrlPrefix = mediaUrlPrefixRegex) => {
23
+ const parsed = URL(url, {}, true);
24
+ const match = mediaUrlPrefix.exec(parsed.pathname);
25
+ if (match && match.length > 1) {
26
+ // regex will provide us with /-/ or /~/ type
27
+ parsed.set('pathname', parsed.pathname.replace(mediaUrlPrefix, `/${match[1]}/jssmedia/`));
28
+ }
29
+ return parsed.toString();
30
+ };
31
+ /**
32
+ * Prepares a Sitecore media URL with `params` for use by the Content SDK media handler.
33
+ * This is done by replacing `/~/media` or `/-/media` with `/~/jssmedia` or `/-/jssmedia`, respectively.
34
+ * Provided `params` are used as the querystring parameters for the media URL.
35
+ * Can use `mediaUrlPrefix` in order to use a custom prefix.
36
+ * If no `params` are sent, the original media URL is returned.
37
+ * @param {string} url The URL to prepare
38
+ * @param {object} [params] The querystring parameters to use
39
+ * @param {RegExp} [mediaUrlPrefix] The regex to match the media URL prefix
40
+ * @returns {string} The prepared URL
41
+ * @public
42
+ */
43
+ export const updateImageUrl = (url, params, mediaUrlPrefix = mediaUrlPrefixRegex) => {
44
+ if (!params || Object.keys(params).length === 0) {
45
+ // if params aren't supplied, no need to run it through Content SDK media handler
46
+ return url;
47
+ }
48
+ // polyfill node `global` in browser to workaround https://github.com/unshiftio/url-parse/issues/150
49
+ if (typeof window !== 'undefined' && !window.global) {
50
+ window.global = {};
51
+ }
52
+ const parsed = URL(replaceMediaUrlPrefix(url, mediaUrlPrefix), {}, true);
53
+ const requiredParams = getRequiredParams(parsed.query);
54
+ const query = Object.assign({}, params);
55
+ Object.entries(requiredParams).forEach(([key, param]) => {
56
+ if (param) {
57
+ query[key] = param;
58
+ }
59
+ });
60
+ parsed.set('query', query);
61
+ return parsed.toString();
62
+ };
63
+ /**
64
+ * Receives an array of `srcSet` parameters that are iterated and used as parameters to generate
65
+ * a corresponding set of updated Sitecore media URLs via @see updateImageUrl. The result is a comma-delimited
66
+ * list of media URLs with respective dimension parameters.
67
+ * @example
68
+ * // returns '/ipsum.jpg?h=1000&w=1000 1000w, /ipsum.jpg?mh=250&mw=250 250w'
69
+ * getSrcSet('/ipsum.jpg', [{ h: 1000, w: 1000 }, { mh: 250, mw: 250 } ])
70
+ * More information about `srcSet`: {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img}
71
+ * @param {string} url The URL to prepare
72
+ * @param {Array} srcSet The array of parameters to use
73
+ * @param {object} [imageParams] The querystring parameters to use
74
+ * @param {RegExp} [mediaUrlPrefix] The regex to match the media URL prefix
75
+ * @returns {string} The prepared URL
76
+ * @public
77
+ */
78
+ export const getSrcSet = (url, srcSet, imageParams, mediaUrlPrefix) => {
79
+ return srcSet
80
+ .map((params) => {
81
+ const newParams = Object.assign(Object.assign({}, imageParams), params);
82
+ const imageWidth = newParams.w || newParams.mw;
83
+ if (!imageWidth) {
84
+ return null;
85
+ }
86
+ return `${updateImageUrl(url, newParams, mediaUrlPrefix)} ${imageWidth}w`;
87
+ })
88
+ .filter((value) => value)
89
+ .join(', ');
90
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export { personalizeLayout } from './layout-personalizer';
2
+ export { PersonalizeService, } from './personalize-service';
3
+ export { getPersonalizedRewrite, getPersonalizedRewriteData, getGroomedVariantIds, normalizePersonalizedRewrite, CdpHelper, DEFAULT_VARIANT, VARIANT_PREFIX, } from './utils';
@@ -0,0 +1,93 @@
1
+ import { HIDDEN_RENDERING_NAME } from '../constants';
2
+ const transformToHiddenRenderingVariant = (component) => (Object.assign(Object.assign({}, component), { componentName: HIDDEN_RENDERING_NAME, experiences: {} }));
3
+ /**
4
+ * Apply personalization to layout data. This will recursively go through all placeholders/components, check experiences nodes and replace default with object from specific experience.
5
+ * @param {LayoutServiceData} layout Layout data
6
+ * @param {string} variantId variant id
7
+ * @param {string[]} [componentVariantIds] component variant ids
8
+ * @public
9
+ */
10
+ export function personalizeLayout(layout, variantId, componentVariantIds) {
11
+ var _a;
12
+ // Add (page-level) variantId to Sitecore context so that it is accessible here
13
+ layout.sitecore.context.variantId = variantId;
14
+ const placeholders = ((_a = layout.sitecore.route) === null || _a === void 0 ? void 0 : _a.placeholders) || {};
15
+ if (Object.keys(placeholders).length === 0) {
16
+ return undefined;
17
+ }
18
+ const isEditing = layout.sitecore.context.pageEditing;
19
+ if (placeholders) {
20
+ Object.keys(placeholders).forEach((placeholder) => {
21
+ placeholders[placeholder] = personalizePlaceholder(placeholders[placeholder], [variantId, ...(componentVariantIds || [])], isEditing);
22
+ });
23
+ }
24
+ return placeholders;
25
+ }
26
+ /**
27
+ * @param {Array} components components within placeholder
28
+ * @param {string[]} variantIds variant ids
29
+ * @param {boolean} isEditing indicates if page is rendered in metadata edit mode
30
+ * @returns {ComponentRendering[]} components with personalization applied
31
+ */
32
+ export function personalizePlaceholder(components, variantIds, isEditing) {
33
+ return components
34
+ .map((component) => {
35
+ const rendering = component;
36
+ if (rendering.experiences !== undefined) {
37
+ return personalizeComponent(rendering, variantIds, isEditing);
38
+ }
39
+ else if (rendering.placeholders) {
40
+ const placeholders = rendering.placeholders;
41
+ Object.keys(placeholders).forEach((placeholder) => {
42
+ placeholders[placeholder] = personalizePlaceholder(placeholders[placeholder], variantIds, isEditing);
43
+ });
44
+ }
45
+ return component;
46
+ })
47
+ .filter(Boolean);
48
+ }
49
+ /**
50
+ * @param {ComponentRenderingWithExperiences} component component with experiences
51
+ * @param {string[]} variantIds variant ids
52
+ * @param {boolean} isEditing indicates if page is rendered in metadata edit mode
53
+ * @returns {ComponentRendering | null} component with personalization applied or null if hidden
54
+ */
55
+ export function personalizeComponent(component, variantIds, isEditing) {
56
+ // Check if we have a page/component experience matching any of the variants (there should be at most 1)
57
+ const match = Object.keys(component.experiences).find((variantId) => variantIds.includes(variantId));
58
+ const variant = match && component.experiences[match];
59
+ // variant and componentName can be undefined or null
60
+ if (!variant && !component.componentName) {
61
+ // DEFAULT IS HIDDEN
62
+ if (isEditing) {
63
+ component = transformToHiddenRenderingVariant(component);
64
+ }
65
+ else {
66
+ return null;
67
+ }
68
+ }
69
+ else if (variant && variant.componentName === null && variant.dataSource === null) {
70
+ // VARIANT IS HIDDEN
71
+ if (isEditing) {
72
+ component = transformToHiddenRenderingVariant(component);
73
+ }
74
+ else {
75
+ return null;
76
+ }
77
+ }
78
+ else if (variant) {
79
+ component = variant;
80
+ }
81
+ // remove unused experiences from layout data
82
+ if (component.experiences) {
83
+ component.experiences = {};
84
+ }
85
+ if (!component.placeholders)
86
+ return component;
87
+ Object.keys(component === null || component === void 0 ? void 0 : component.placeholders).forEach((placeholder) => {
88
+ if (component.placeholders) {
89
+ component.placeholders[placeholder] = personalizePlaceholder(component.placeholders[placeholder], variantIds);
90
+ }
91
+ });
92
+ return component;
93
+ }
@@ -0,0 +1,102 @@
1
+ import { MemoryCacheClient, } from '@sitecore-content-sdk/core';
2
+ import { isTimeoutError } from '@sitecore-content-sdk/core/tools';
3
+ import debug from '../debug';
4
+ /**
5
+ * Fetch personalize data using the Sitecore GraphQL endpoint.
6
+ * @public
7
+ */
8
+ export class PersonalizeService {
9
+ /**
10
+ * Fetch personalize data using the Sitecore GraphQL endpoint.
11
+ * @param {PersonalizeServiceConfig} config
12
+ */
13
+ constructor(config) {
14
+ this.config = config;
15
+ this.config.timeout = config.timeout || 400;
16
+ this.graphQLClient = this.getGraphQLClient();
17
+ this.cache = this.getCacheClient();
18
+ }
19
+ get query() {
20
+ return /* GraphQL */ `
21
+ query ($siteName: String!, $language: String!, $itemPath: String!) {
22
+ layout(site: $siteName, routePath: $itemPath, language: $language) {
23
+ item {
24
+ id
25
+ version
26
+ personalization {
27
+ variantIds
28
+ }
29
+ }
30
+ }
31
+ }
32
+ `;
33
+ }
34
+ /**
35
+ * Get personalize information for a route
36
+ * @param {string} itemPath page route
37
+ * @param {string} language language
38
+ * @param {string} siteName site name
39
+ * @returns {Promise<PersonalizeInfo | undefined>} the personalize information or undefined (if itemPath / language not found)
40
+ */
41
+ async getPersonalizeInfo(itemPath, language, siteName) {
42
+ var _a;
43
+ // while other graphql services can use fetchOptions, personalize is more sensitive
44
+ // we don't allow retries in it since we need to be fast
45
+ debug.personalize('fetching personalize info for %s %s %s', siteName, itemPath, language);
46
+ const cacheKey = this.getCacheKey(itemPath, language, siteName);
47
+ let data = this.cache.getCacheValue(cacheKey);
48
+ if (!data) {
49
+ try {
50
+ data = await this.graphQLClient.request(this.query, {
51
+ siteName,
52
+ itemPath,
53
+ language,
54
+ });
55
+ this.cache.setCacheValue(cacheKey, data);
56
+ }
57
+ catch (error) {
58
+ if (isTimeoutError(error)) {
59
+ return undefined;
60
+ }
61
+ throw error;
62
+ }
63
+ }
64
+ return ((_a = data === null || data === void 0 ? void 0 : data.layout) === null || _a === void 0 ? void 0 : _a.item)
65
+ ? {
66
+ pageId: data.layout.item.id,
67
+ variantIds: data.layout.item.personalization.variantIds,
68
+ }
69
+ : undefined;
70
+ }
71
+ /**
72
+ * Gets cache client implementation
73
+ * Override this method if custom cache needs to be used
74
+ * @returns CacheClient instance
75
+ */
76
+ getCacheClient() {
77
+ var _a, _b;
78
+ return new MemoryCacheClient({
79
+ cacheEnabled: (_a = this.config.cacheEnabled) !== null && _a !== void 0 ? _a : true,
80
+ cacheTimeout: (_b = this.config.cacheTimeout) !== null && _b !== void 0 ? _b : 10,
81
+ });
82
+ }
83
+ getCacheKey(itemPath, language, siteName) {
84
+ return `${siteName}-${itemPath}-${language}`;
85
+ }
86
+ /**
87
+ * Gets a GraphQL client that can make requests to the API. Uses graphql-request as the default
88
+ * library for fetching graphql data (@see GraphQLRequestClient). Override this method if you
89
+ * want to use something else.
90
+ * @returns {GraphQLClient} implementation
91
+ */
92
+ getGraphQLClient() {
93
+ if (!this.config.clientFactory) {
94
+ throw new Error('clientFactory needs to be provided when initializing GraphQL client.');
95
+ }
96
+ return this.config.clientFactory({
97
+ debugger: debug.personalize,
98
+ fetch: this.config.fetch,
99
+ timeout: this.config.timeout,
100
+ });
101
+ }
102
+ }