@salesforcedevs/dx-components 1.30.0 → 1.30.1-node22-2

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/lwc.config.json CHANGED
@@ -140,6 +140,9 @@
140
140
  "dxUtils/recentSearches",
141
141
  "dxUtils/regexps",
142
142
  "dxUtils/withTypedRefs",
143
- "dxUtils/wordpress"
143
+ "dxUtils/wordpress",
144
+ "dxUtils/shiki",
145
+ "dxUtils/shikiStatic",
146
+ "dxUtils/shikiCore"
144
147
  ]
145
148
  }
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.30.0",
3
+ "version": "1.30.1-node22-2",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
7
- "node": "20.x"
7
+ "node": ">=22.0.0"
8
+ },
9
+ "volta": {
10
+ "node": "22.22.0",
11
+ "yarn": "1.22.22"
8
12
  },
9
13
  "publishConfig": {
10
14
  "access": "public"
@@ -44,5 +48,5 @@
44
48
  "luxon": "3.4.4",
45
49
  "msw": "^2.12.4"
46
50
  },
47
- "gitHead": "4027270163b2eb9610b911a09bfa31f536061fe4"
51
+ "gitHead": "db460ac1fb9b1f752d0c129dfe19012c8a085867"
48
52
  }
@@ -3,7 +3,7 @@
3
3
  <img class={imageClassName} src={imageAssetPath} alt={imageAlt} />
4
4
  <img
5
5
  class="image-alt-small"
6
- src="https://a.sfdcstatic.com/developer-website/prod/images/binary-cloud-circle-small.svg"
6
+ src="https://developer.salesforce.com/ns-assets/images/binary-cloud-circle-small.svg"
7
7
  alt="Cloud with binary code floating above"
8
8
  lwc:if={altVariant}
9
9
  />
@@ -60,10 +60,10 @@ export default class EmptyState extends LightningElement {
60
60
 
61
61
  get imageAssetPath() {
62
62
  return this.variant === "base"
63
- ? `https://a.sfdcstatic.com/developer-website/prod/images/docs-empty-state${
63
+ ? `https://developer.salesforce.com/ns-assets/images/docs-empty-state${
64
64
  this.size === "small" ? "-small" : ""
65
65
  }.svg`
66
- : `https://a.sfdcstatic.com/developer-website/prod/images/binary-cloud-circle${
66
+ : `https://developer.salesforce.com/ns-assets/images/binary-cloud-circle${
67
67
  this.size === "small" ? "-small" : ""
68
68
  }.svg`;
69
69
  }
@@ -8,9 +8,9 @@
8
8
 
9
9
  .error_container {
10
10
  background-color: #3a49da;
11
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/bottom-right.svg"),
12
- url("https://a.sfdcstatic.com/developer-website/prod/images/lower-left.svg"),
13
- url("https://a.sfdcstatic.com/developer-website/prod/images/top-right.svg");
11
+ background-image: url("https://developer.salesforce.com/ns-assets/images/bottom-right.svg"),
12
+ url("https://developer.salesforce.com/ns-assets/images/lower-left.svg"),
13
+ url("https://developer.salesforce.com/ns-assets/images/top-right.svg");
14
14
  background-position: right bottom, left 90%, right top;
15
15
  background-repeat: no-repeat;
16
16
  padding: var(--dx-g-spacing-3xl) calc(var(--dx-g-spacing-3xl) + 20px) 130px
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="error-container">
3
3
  <img
4
- src="https://a.sfdcstatic.com/developer-website/prod/images/error-fallback.svg"
4
+ src="https://developer.salesforce.com/ns-assets/images/error-fallback.svg"
5
5
  alt="error fallback image"
6
6
  class="error-image"
7
7
  />
@@ -3,7 +3,7 @@
3
3
 
4
4
  :host {
5
5
  --dx-c-feature-img-box-shadow: 0 6px 30px 0 rgb(0 20 45 / 40%);
6
- --dx-c-feature-description-left-img-src: url("https://a.sfdcstatic.com/developer-website/prod/images/feature-backdrop1.svg");
6
+ --dx-c-feature-description-left-img-src: url("https://developer.salesforce.com/ns-assets/images/feature-backdrop1.svg");
7
7
  --dx-c-feature-description-max-width: 31.75rem;
8
8
  --dx-c-feature-img-margin-left: auto;
9
9
  --dx-c-feature-img-container-padding: 4rem;
@@ -83,7 +83,7 @@ section {
83
83
 
84
84
  .description-right .image {
85
85
  margin-right: auto;
86
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/feature-backdrop2.svg");
86
+ background-image: url("https://developer.salesforce.com/ns-assets/images/feature-backdrop2.svg");
87
87
  }
88
88
 
89
89
  .image-display-container {
@@ -21,7 +21,7 @@
21
21
  <div if:true={isDisplay} class="image-display-container">
22
22
  <img
23
23
  class="image-display"
24
- src="https://a.sfdcstatic.com/developer-website/prod/images/featured-demo-art-blank.svg"
24
+ src="https://developer.salesforce.com/ns-assets/images/featured-demo-art-blank.svg"
25
25
  alt={header}
26
26
  />
27
27
  <div class="image-container">
@@ -221,8 +221,8 @@
221
221
 
222
222
  .custom-bg-trial::after {
223
223
  content: "";
224
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/trial-left.svg"),
225
- url("https://a.sfdcstatic.com/developer-website/prod/images/trial-right.svg");
224
+ background-image: url("https://developer.salesforce.com/ns-assets/images/trial-left.svg"),
225
+ url("https://developer.salesforce.com/ns-assets/images/trial-right.svg");
226
226
  background-position: var(--dx-g-page-padding-horizontal) 50px,
227
227
  right 15px top;
228
228
  background-repeat: no-repeat;
@@ -235,7 +235,7 @@
235
235
 
236
236
  @media screen and (max-width: 1024px) {
237
237
  .custom-bg-trial::after {
238
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/trial-left.svg");
238
+ background-image: url("https://developer.salesforce.com/ns-assets/images/trial-left.svg");
239
239
  background-position: 48px 30px;
240
240
  background-size: contain;
241
241
  }
@@ -243,7 +243,7 @@
243
243
 
244
244
  .custom-bg-big-moon::after {
245
245
  content: "";
246
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/big-moon.svg");
246
+ background-image: url("https://developer.salesforce.com/ns-assets/images/big-moon.svg");
247
247
  background-position: top right;
248
248
  background-repeat: no-repeat;
249
249
  position: absolute;
@@ -258,7 +258,7 @@
258
258
  justify-content: center;
259
259
  align-items: center;
260
260
  position: absolute;
261
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/blue-circle.svg");
261
+ background-image: url("https://developer.salesforce.com/ns-assets/images/blue-circle.svg");
262
262
  top: 110px;
263
263
  right: 230px;
264
264
  left: unset;
@@ -6,10 +6,10 @@ const treesMobile =
6
6
 
7
7
  // These codey-* ones are a bit of a hack for now: we were only given a PNG and limited time, so we're wrapping the PNG in an SVG.
8
8
  const codeyDesktop =
9
- '<svg class="codey-desktop" width="381" height="337" viewBox="0 0 381 337" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image width="381" height="337" xlink:href="https://a.sfdcstatic.com/developer-website/prod/images/podcast-bear.png" />';
9
+ '<svg class="codey-desktop" width="381" height="337" viewBox="0 0 381 337" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image width="381" height="337" xlink:href="https://developer.salesforce.com/ns-assets/images/podcast-bear.png" />';
10
10
 
11
11
  const codeyMobile =
12
- '<svg class="codey-mobile" width="381" height="337" viewBox="0 0 381 337" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image width="381" height="337" xlink:href="https://a.sfdcstatic.com/developer-website/prod/images/podcast-bear.png" />';
12
+ '<svg class="codey-mobile" width="381" height="337" viewBox="0 0 381 337" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><image width="381" height="337" xlink:href="https://developer.salesforce.com/ns-assets/images/podcast-bear.png" />';
13
13
 
14
14
  const moonDesktop =
15
15
  '<svg width="1221" height="507" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M745.819 45.482c0 24.567-19.915 44.482-44.482 44.482s-44.483-19.915-44.483-44.482C656.854 20.916 676.77 1 701.337 1c24.567 0 44.482 19.916 44.482 44.482"/><path d="M745.819 45.482c0 24.567-19.915 44.482-44.482 44.482s-44.483-19.915-44.483-44.482C656.854 20.916 676.77 1 701.337 1c24.567 0 44.482 19.916 44.482 44.482Z" stroke="#90D0FE" stroke-width="2"/><path d="M476.154 420.627a4.095 4.095 0 1 1-8.191 0 4.095 4.095 0 1 1 8.19 0ZM99.154 150.627a4.095 4.095 0 1 1-8.191 0 4.095 4.095 0 1 1 8.19 0ZM1210.142 97.587l-1.518 4.1a1.063 1.063 0 0 1-.631.633l-4.102 1.518c-.933.346-.933 1.664 0 2.009l4.102 1.517c.293.109.523.34.63.633l1.519 4.102c.346.93 1.664.93 2.009 0l1.517-4.102c.109-.293.34-.524.633-.633l4.102-1.517c.932-.345.932-1.663 0-2.01l-4.102-1.517a1.068 1.068 0 0 1-.633-.632l-1.517-4.101c-.345-.933-1.663-.933-2.01 0ZM8.142 490.372l-1.518 4.1a1.067 1.067 0 0 1-.632.633l-4.1 1.518c-.934.345-.934 1.664 0 2.009l4.1 1.517c.293.109.524.34.632.633l1.518 4.1c.345.933 1.664.933 2.01 0l1.516-4.1c.11-.293.34-.524.633-.633l4.101-1.517c.932-.345.932-1.664 0-2.01l-4.1-1.517a1.071 1.071 0 0 1-.634-.632l-1.517-4.101c-.345-.933-1.664-.933-2.009 0ZM127.142 115.587l-1.518 4.1a1.064 1.064 0 0 1-.632.633l-4.1 1.518c-.934.346-.934 1.664 0 2.009l4.1 1.517c.293.109.524.34.632.633l1.518 4.102c.345.93 1.664.93 2.01 0l1.516-4.102c.11-.293.34-.524.633-.633l4.101-1.517c.932-.345.932-1.663 0-2.01l-4.1-1.517a1.068 1.068 0 0 1-.634-.632l-1.517-4.101c-.345-.933-1.664-.933-2.009 0ZM909.009 306.108c-5.999-11.612-9.387-24.793-9.387-38.765 0-11.403 2.257-22.279 6.348-32.206M1067.92 255.215c.568 3.96.862 8.01.862 12.129 0 46.713-37.867 84.58-84.58 84.58-28.474 0-53.664-14.071-68.99-35.64M911.555 224.004c14.768-24.701 41.776-41.24 72.647-41.24 38.302 0 70.658 25.459 81.068 60.378M1055.511 147.787l-3.452 9.329a2.439 2.439 0 0 1-1.44 1.44l-9.329 3.452c-2.121.784-2.121 3.784 0 4.569l9.329 3.452a2.436 2.436 0 0 1 1.44 1.44l3.452 9.329c.785 2.12 3.785 2.12 4.569 0l3.452-9.33a2.441 2.441 0 0 1 1.44-1.44l9.329-3.451c2.121-.785 2.121-3.785 0-4.57l-9.329-3.451a2.444 2.444 0 0 1-1.44-1.44l-3.452-9.33c-.784-2.12-3.784-2.12-4.569 0ZM919.251 376.385c0 5.69-4.614 10.304-10.306 10.304-5.69 0-10.305-4.613-10.305-10.305 0-5.692 4.614-10.306 10.305-10.306 5.692 0 10.306 4.615 10.306 10.307Z" stroke="#90D0FE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M984.116 224.502a5.027 5.027 0 1 1-10.054 0 5.027 5.027 0 0 1 10.054 0" fill="#90D0FE"/><path stroke="#90D0FE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M1046.716 254.771h29.772M1087.929 254.771h7.089M902.279 225.33h23.242M870.108 225.33h10.053"/><path d="M893.055 225.33a2.01 2.01 0 1 1-4.021 0 2.01 2.01 0 0 1 4.02 0" fill="#90D0FE"/><path stroke="#90D0FE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M893.425 315.627h31.409"/><path d="M936.898 315.627a2.011 2.011 0 1 1-4.023 0 2.011 2.011 0 0 1 4.023 0" fill="#90D0FE"/><path stroke="#90D0FE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M1013.52 292.398v-16.036M1021.537 284.382l-16.051.002"/></g></svg>';
@@ -113,7 +113,7 @@ footer.signup-variant-no-signup {
113
113
  height: 112px;
114
114
  width: 110px;
115
115
  margin-right: var(--dx-g-spacing-lg);
116
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/footer-graphic-trees.svg");
116
+ background-image: url("https://developer.salesforce.com/ns-assets/images/footer-graphic-trees.svg");
117
117
  filter: var(--dx-g-svg-filter);
118
118
  }
119
119
 
@@ -121,7 +121,7 @@ footer.signup-variant-no-signup {
121
121
  height: 96px;
122
122
  width: 220px;
123
123
  margin-right: var(--dx-g-spacing-lg);
124
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/footer-graphic-mountains-2.svg");
124
+ background-image: url("https://developer.salesforce.com/ns-assets/images/footer-graphic-mountains-2.svg");
125
125
  filter: var(--dx-g-svg-filter);
126
126
  }
127
127
 
@@ -132,7 +132,7 @@ footer.signup-variant-no-signup {
132
132
  bottom: 0;
133
133
  height: 56px;
134
134
  width: 100px;
135
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/footer-graphic-mountains-small-2.svg");
135
+ background-image: url("https://developer.salesforce.com/ns-assets/images/footer-graphic-mountains-small-2.svg");
136
136
  filter: var(--dx-g-svg-filter);
137
137
  }
138
138
 
@@ -140,7 +140,7 @@ footer.signup-variant-no-signup {
140
140
  height: 66px;
141
141
  width: 52px;
142
142
  margin-left: var(--dx-g-spacing-lg);
143
- background-image: url("https://a.sfdcstatic.com/developer-website/prod/images/footer-graphic-trees-small.svg");
143
+ background-image: url("https://developer.salesforce.com/ns-assets/images/footer-graphic-trees-small.svg");
144
144
  filter: var(--dx-g-svg-filter);
145
145
  }
146
146
 
@@ -56,7 +56,7 @@
56
56
  >
57
57
  <a class="logo" href="/">
58
58
  <img
59
- src="https://a.sfdcstatic.com/developer-website/prod/images/salesforce-logo-corporate.svg"
59
+ src="https://developer.salesforce.com/ns-assets/images/salesforce-logo-corporate.svg"
60
60
  alt="Salesforce logo"
61
61
  />
62
62
  </a>
@@ -288,7 +288,7 @@ function augmentWithNonMFEFooterFunctionality(FooterClass: typeof Footer) {
288
288
  link.href = "#";
289
289
  link.onclick = this.openOneTrustInfoDisplay;
290
290
  } else if (item.title === "Your Privacy Choices") {
291
- link.img = "https://a.sfdcstatic.com/developer-website/prod/images/privacyoptions.svg";
291
+ link.img = "https://developer.salesforce.com/ns-assets/images/privacyoptions.svg";
292
292
  }
293
293
 
294
294
  return link;
@@ -195,7 +195,7 @@ export default class Input extends LightningElement {
195
195
  }
196
196
 
197
197
  private get shortcutImgSrc() {
198
- return `https://a.sfdcstatic.com/developer-website/prod/images/${this.commandKey}.svg`;
198
+ return `https://developer.salesforce.com/ns-assets/images/${this.commandKey}.svg`;
199
199
  }
200
200
 
201
201
  private get shortcutImgAlt() {
@@ -3,7 +3,7 @@ import { LightningElement, api } from "lwc";
3
3
  export default class Logo extends LightningElement {
4
4
  @api href: string = "/";
5
5
  @api imgSrc: string =
6
- "https://a.sfdcstatic.com/developer-website/prod/images/salesforce-cloud.svg";
6
+ "https://developer.salesforce.com/ns-assets/images/salesforce-cloud.svg";
7
7
  @api imgAlt: string = "Salesforce logo";
8
8
  @api label!: string;
9
9
  }
@@ -9,7 +9,7 @@ export default html`
9
9
  <div class="coveo-show-if-no-results">
10
10
  <div class="no-results">
11
11
  <img
12
- src="https://a.sfdcstatic.com/developer-website/prod/images/binary-cloud-circle-small.svg"
12
+ src="https://developer.salesforce.com/ns-assets/images/binary-cloud-circle-small.svg"
13
13
  alt="purple cloud with floating binary numbers above"
14
14
  />
15
15
  <div class="no-results-info">
@@ -311,7 +311,7 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
311
311
 
312
312
  .dx-search-header {
313
313
  padding: var(--dx-g-spacing-xl);
314
- background: url("https://a.sfdcstatic.com/developer-website/prod/images/binary-cloud-trees.svg")
314
+ background: url("https://developer.salesforce.com/ns-assets/images/binary-cloud-trees.svg")
315
315
  no-repeat 100% 0,
316
316
  linear-gradient(
317
317
  77deg,
@@ -352,7 +352,7 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
352
352
 
353
353
  @media (min-width: 928px) and (max-width: 1024px) {
354
354
  .dx-search-header {
355
- background: url("https://a.sfdcstatic.com/developer-website/prod/images/binary-cloud-trees.svg")
355
+ background: url("https://developer.salesforce.com/ns-assets/images/binary-cloud-trees.svg")
356
356
  no-repeat 200% 0,
357
357
  linear-gradient(
358
358
  77deg,
@@ -380,7 +380,7 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
380
380
 
381
381
  @media (min-width: 768px) and (max-width: 928px) {
382
382
  .dx-search-header {
383
- background: url("https://a.sfdcstatic.com/developer-website/prod/images/binary-trees.svg")
383
+ background: url("https://developer.salesforce.com/ns-assets/images/binary-trees.svg")
384
384
  no-repeat 90% 50%,
385
385
  linear-gradient(
386
386
  77deg,
@@ -392,7 +392,7 @@ li.coveo-dynamic-facet-breadcrumb-value-list-item {
392
392
 
393
393
  @media (max-width: 768px) {
394
394
  .dx-search-header {
395
- background: url("https://a.sfdcstatic.com/developer-website/prod/images/binary.svg")
395
+ background: url("https://developer.salesforce.com/ns-assets/images/binary.svg")
396
396
  no-repeat 90% 50%,
397
397
  linear-gradient(
398
398
  77deg,
@@ -3,7 +3,7 @@
3
3
  <img
4
4
  if:false={hideTopGraphic}
5
5
  class="graphic"
6
- src="https://a.sfdcstatic.com/developer-website/prod/images/dx-section-banner-graphic-1.svg"
6
+ src="https://developer.salesforce.com/ns-assets/images/dx-section-banner-graphic-1.svg"
7
7
  alt=""
8
8
  />
9
9
  <div class="content">
@@ -69,7 +69,7 @@
69
69
  <img
70
70
  lwc:if={isSearchLoading}
71
71
  class="loading-skeleton padding-horizontal"
72
- src="https://a.sfdcstatic.com/developer-website/prod/images/sidebar-loading.svg"
72
+ src="https://developer.salesforce.com/ns-assets/images/sidebar-loading.svg"
73
73
  alt="loading"
74
74
  />
75
75
  <template
@@ -16,7 +16,7 @@
16
16
  <img
17
17
  if:true={showChildrenLoading}
18
18
  class="tree-children-loading"
19
- src="https://a.sfdcstatic.com/developer-website/prod/images/sidebar-item-loading.svg"
19
+ src="https://developer.salesforce.com/ns-assets/images/sidebar-item-loading.svg"
20
20
  alt="childrenLoading"
21
21
  />
22
22
  <template if:true={showChildren} tabindex="0">
@@ -34,7 +34,8 @@ export const createHighlighter = jest.fn().mockImplementation(() => {
34
34
  "apex",
35
35
  "text",
36
36
  "handlebars"
37
- ])
37
+ ]),
38
+ loadLanguage: jest.fn().mockResolvedValue(undefined)
38
39
  });
39
40
  });
40
41
 
@@ -21,3 +21,9 @@ export default mockLanguage;
21
21
  // Also export as named export for themes
22
22
  export const theme = mockTheme;
23
23
  export const lang = mockLanguage;
24
+
25
+ // Mock for @shikijs/colorized-brackets
26
+ export const transformerColorizedBrackets = () => ({
27
+ name: "colorized-brackets",
28
+ preprocess: (code: string) => code
29
+ });
@@ -1,5 +1,17 @@
1
- import type { BundledLanguage, BundledTheme, HighlighterCore } from "shiki";
2
- import { getCustomLanguageGrammars } from "dxUtils/shikiGrammars";
1
+ import type { HighlighterCore } from "shiki";
2
+ import {
3
+ createShikiState,
4
+ initializeHighlighter,
5
+ highlightCodeWithShiki,
6
+ escapeHtml as coreEscapeHtml,
7
+ ShikiState
8
+ } from "dxUtils/shikiCore";
9
+
10
+ /**
11
+ * Dynamic loading version of Shiki.
12
+ * Uses dynamic import() for code splitting - shiki is lazy loaded on first use.
13
+ * Note: May not work with SSG. Use dxUtils/shikiStatic for SSG compatibility.
14
+ */
3
15
 
4
16
  let shikiModulePromise: Promise<typeof import("shiki")> | null = null;
5
17
  let bracketsModulePromise: Promise<
@@ -14,156 +26,13 @@ async function getBrackets() {
14
26
  return (bracketsModulePromise ??= import("@shikijs/colorized-brackets"));
15
27
  }
16
28
 
17
- interface ShikiSingleton {
18
- highlighter: HighlighterCore | null;
19
- initialized: boolean;
20
- initPromise: Promise<HighlighterCore> | null;
21
- }
22
-
23
- const shikiInstance: ShikiSingleton = {
24
- highlighter: null,
25
- initialized: false,
26
- initPromise: null
27
- };
28
-
29
- // Theme mapping for light/dark modes
30
- const THEME_MAP: Record<string, BundledTheme> = {
31
- light: "light-plus",
32
- dark: "material-theme-darker"
33
- };
34
-
35
- const THEME_MAP_COLOR_REPLACEMENTS: Record<
36
- string,
37
- { colorReplacements: Record<string, string> }
38
- > = {
39
- light: {
40
- colorReplacements: {}
41
- },
42
- dark: {
43
- colorReplacements: {
44
- "#545454": "#8A8A8A" // Replace comment color for WCAG 2.1 compliance
45
- }
46
- }
47
- };
48
-
49
- // Language mapping for custom languages to supported ones
50
- const LANGUAGE_MAP: Record<string, BundledLanguage> = {
51
- ssjs: "javascript", // Server-Side JavaScript
52
- gtl: "handlebars", // Guide Template Language similar to Handlebars
53
- lwc: "jsx",
54
- sql_docs_template: "sql", // Custom SQL variant
55
- visualforce: "html", // Visualforce uses HTML-like syntax
56
- js: "javascript",
57
- ts: "typescript",
58
- yml: "yaml",
59
- md: "markdown",
60
- sh: "bash"
61
- };
62
-
63
- // Core languages loaded eagerly (keep minimal; load others on demand)
64
- const CORE_LANGUAGES: BundledLanguage[] = [
65
- "apex",
66
- "javascript",
67
- "html",
68
- "css",
69
- "json",
70
- "sql",
71
- "bash",
72
- "xml",
73
- "graphql",
74
- "jsx",
75
- getCustomLanguageGrammars().ampscript
76
- ];
29
+ const shikiState: ShikiState = createShikiState();
77
30
 
78
- // Non-critical languages that can be loaded asynchronously when needed
79
- const OPTIONAL_LANGUAGES: Record<string, any> = {
80
- // @ts-ignore
81
- typescript: "typescript",
82
- // @ts-ignore
83
- markdown: "markdown",
84
- // @ts-ignore
85
- python: "python",
86
- // @ts-ignore
87
- java: "java",
88
- // @ts-ignore
89
- yaml: "yaml",
90
- // @ts-ignore
91
- php: "php",
92
- // @ts-ignore
93
- swift: "swift",
94
- // @ts-ignore
95
- kotlin: "kotlin",
96
- // @ts-ignore
97
- handlebars: "handlebars",
98
- // @ts-ignore
99
- dataweave: getCustomLanguageGrammars().dataweave,
100
- // @ts-ignore
101
- agentscript: getCustomLanguageGrammars().agentscript
102
- };
103
-
104
- // Initialize Shiki highlighter (lazy-load module and keep initial set minimal)
105
31
  async function initializeShiki(): Promise<HighlighterCore> {
106
- if (shikiInstance.highlighter) {
107
- return shikiInstance.highlighter;
108
- }
109
-
110
- if (shikiInstance.initPromise) {
111
- return shikiInstance.initPromise;
112
- }
113
-
114
- // Assign promise IMMEDIATELY before any async work to prevent race conditions
115
- shikiInstance.initPromise = (async () => {
116
- const shiki = await getShiki();
117
- const highlighter = await shiki.createHighlighter({
118
- themes: ["light-plus", "material-theme-darker"],
119
- langs: CORE_LANGUAGES
120
- });
121
- shikiInstance.highlighter = highlighter;
122
- shikiInstance.initialized = true;
123
- return highlighter;
124
- })();
125
-
126
- try {
127
- return await shikiInstance.initPromise;
128
- } catch (error) {
129
- console.error("Failed to initialize Shiki:", error);
130
- shikiInstance.initPromise = null;
131
- throw error;
132
- }
133
- }
134
-
135
- // Async function to load additional languages when needed
136
- async function loadLanguageIfNeeded(
137
- highlighter: HighlighterCore,
138
- language: string
139
- ): Promise<void> {
140
- const loadedLanguages = highlighter.getLoadedLanguages();
141
-
142
- if (!loadedLanguages.includes(language as BundledLanguage)) {
143
- // Check if it's an optional language that needs to be loaded
144
- const languageLoader = OPTIONAL_LANGUAGES[language];
145
-
146
- if (languageLoader) {
147
- try {
148
- await highlighter.loadLanguage(languageLoader);
149
- } catch (error) {
150
- console.warn(
151
- `Failed to load optional language ${language}:`,
152
- error
153
- );
154
- }
155
- }
156
- }
32
+ const shikiModule = await getShiki();
33
+ return initializeHighlighter(shikiState, shikiModule);
157
34
  }
158
35
 
159
- // Get the mapped language or fallback to the original
160
- function getMappedLanguage(language: string): BundledLanguage {
161
- const mapped =
162
- LANGUAGE_MAP[language.toLowerCase()] || language.toLowerCase();
163
- return mapped as BundledLanguage;
164
- }
165
-
166
- // Highlight code with Shiki
167
36
  export async function highlightCode(
168
37
  code: string,
169
38
  language: string,
@@ -171,39 +40,20 @@ export async function highlightCode(
171
40
  ): Promise<string> {
172
41
  try {
173
42
  const highlighter = await initializeShiki();
174
- let mappedLanguage = getMappedLanguage(language);
175
-
176
- // Try to load the language asynchronously if it's not already loaded
177
- await loadLanguageIfNeeded(highlighter, mappedLanguage);
178
-
179
- // Check if the language is supported after potential async loading
180
- const loadedLanguages = highlighter.getLoadedLanguages();
181
- if (!loadedLanguages.includes(mappedLanguage)) {
182
- mappedLanguage = "text" as BundledLanguage;
183
- }
184
-
185
43
  const { transformerColorizedBrackets } = await getBrackets();
186
-
187
- return highlighter.codeToHtml(code, {
188
- lang: mappedLanguage,
189
- theme: THEME_MAP[theme],
190
- transformers: [transformerColorizedBrackets()],
191
- colorReplacements:
192
- THEME_MAP_COLOR_REPLACEMENTS[theme].colorReplacements
193
- });
44
+ return highlightCodeWithShiki(
45
+ code,
46
+ language,
47
+ theme,
48
+ highlighter,
49
+ transformerColorizedBrackets
50
+ );
194
51
  } catch (error) {
195
52
  console.error("Failed to highlight code with Shiki:", error);
196
- // Fallback to plain text on error
197
- return `<pre class="shiki ${theme}"><code>${escapeHtml(
198
- code
199
- )}</code></pre>`;
53
+ return `<pre class="shiki ${theme}"><code>${escapeHtml(code)}</code></pre>`;
200
54
  }
201
55
  }
202
56
 
203
- // Utility function to escape HTML
204
57
  export function escapeHtml(text: string): string {
205
- const div = document.createElement("div");
206
- div.textContent = text;
207
- // eslint-disable-next-line @lwc/lwc/no-inner-html
208
- return div.innerHTML;
58
+ return coreEscapeHtml(text);
209
59
  }
@@ -0,0 +1,188 @@
1
+ import type { BundledLanguage, BundledTheme, HighlighterCore } from "shiki";
2
+ import { getCustomLanguageGrammars } from "dxUtils/shikiGrammars";
3
+
4
+ export interface ShikiModule {
5
+ createHighlighter: (options: {
6
+ themes: string[];
7
+ langs: BundledLanguage[];
8
+ }) => Promise<HighlighterCore>;
9
+ }
10
+
11
+ export interface BracketsModule {
12
+ transformerColorizedBrackets: () => any;
13
+ }
14
+
15
+ export interface ShikiState {
16
+ highlighter: HighlighterCore | null;
17
+ initialized: boolean;
18
+ initPromise: Promise<HighlighterCore> | null;
19
+ }
20
+
21
+ export const THEME_MAP: Record<string, BundledTheme> = {
22
+ light: "light-plus",
23
+ dark: "material-theme-darker"
24
+ };
25
+
26
+ export const THEME_MAP_COLOR_REPLACEMENTS: Record<
27
+ string,
28
+ { colorReplacements: Record<string, string> }
29
+ > = {
30
+ light: {
31
+ colorReplacements: {}
32
+ },
33
+ dark: {
34
+ colorReplacements: {
35
+ "#545454": "#8A8A8A"
36
+ }
37
+ }
38
+ };
39
+
40
+ export const LANGUAGE_MAP: Record<string, BundledLanguage> = {
41
+ ssjs: "javascript",
42
+ gtl: "handlebars",
43
+ lwc: "jsx",
44
+ sql_docs_template: "sql",
45
+ visualforce: "html",
46
+ js: "javascript",
47
+ ts: "typescript",
48
+ yml: "yaml",
49
+ md: "markdown",
50
+ sh: "bash"
51
+ };
52
+
53
+ export const CORE_LANGUAGES: BundledLanguage[] = [
54
+ "apex",
55
+ "javascript",
56
+ "html",
57
+ "css",
58
+ "json",
59
+ "sql",
60
+ "bash",
61
+ "xml",
62
+ "graphql",
63
+ "jsx",
64
+ getCustomLanguageGrammars().ampscript
65
+ ];
66
+
67
+ export const OPTIONAL_LANGUAGES: Record<string, any> = {
68
+ // @ts-ignore
69
+ typescript: "typescript",
70
+ // @ts-ignore
71
+ markdown: "markdown",
72
+ // @ts-ignore
73
+ python: "python",
74
+ // @ts-ignore
75
+ java: "java",
76
+ // @ts-ignore
77
+ yaml: "yaml",
78
+ // @ts-ignore
79
+ php: "php",
80
+ // @ts-ignore
81
+ swift: "swift",
82
+ // @ts-ignore
83
+ kotlin: "kotlin",
84
+ // @ts-ignore
85
+ handlebars: "handlebars",
86
+ // @ts-ignore
87
+ dataweave: getCustomLanguageGrammars().dataweave,
88
+ // @ts-ignore
89
+ agentscript: getCustomLanguageGrammars().agentscript
90
+ };
91
+
92
+ export async function loadLanguageIfNeeded(
93
+ highlighter: HighlighterCore,
94
+ language: string
95
+ ): Promise<void> {
96
+ const loadedLanguages = highlighter.getLoadedLanguages();
97
+
98
+ if (!loadedLanguages.includes(language as BundledLanguage)) {
99
+ const languageLoader = OPTIONAL_LANGUAGES[language];
100
+
101
+ if (languageLoader) {
102
+ try {
103
+ await highlighter.loadLanguage(languageLoader);
104
+ } catch (error) {
105
+ console.warn(
106
+ `Failed to load optional language ${language}:`,
107
+ error
108
+ );
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ export function getMappedLanguage(language: string): BundledLanguage {
115
+ const mapped =
116
+ LANGUAGE_MAP[language.toLowerCase()] || language.toLowerCase();
117
+ return mapped as BundledLanguage;
118
+ }
119
+
120
+ export function escapeHtml(text: string): string {
121
+ const div = document.createElement("div");
122
+ div.textContent = text;
123
+ // eslint-disable-next-line @lwc/lwc/no-inner-html
124
+ return div.innerHTML;
125
+ }
126
+
127
+ export function createShikiState(): ShikiState {
128
+ return {
129
+ highlighter: null,
130
+ initialized: false,
131
+ initPromise: null
132
+ };
133
+ }
134
+
135
+ export async function initializeHighlighter(
136
+ shikiState: ShikiState,
137
+ shikiModule: ShikiModule
138
+ ): Promise<HighlighterCore> {
139
+ if (shikiState.highlighter) {
140
+ return shikiState.highlighter;
141
+ }
142
+
143
+ if (shikiState.initPromise) {
144
+ return shikiState.initPromise;
145
+ }
146
+
147
+ shikiState.initPromise = (async () => {
148
+ const highlighter = await shikiModule.createHighlighter({
149
+ themes: ["light-plus", "material-theme-darker"],
150
+ langs: CORE_LANGUAGES
151
+ });
152
+ shikiState.highlighter = highlighter;
153
+ shikiState.initialized = true;
154
+ return highlighter;
155
+ })();
156
+
157
+ try {
158
+ return await shikiState.initPromise;
159
+ } catch (error) {
160
+ console.error("Failed to initialize Shiki:", error);
161
+ shikiState.initPromise = null;
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ export async function highlightCodeWithShiki(
167
+ code: string,
168
+ language: string,
169
+ theme: "light" | "dark",
170
+ highlighter: HighlighterCore,
171
+ transformerColorizedBrackets: () => any
172
+ ): Promise<string> {
173
+ let mappedLanguage = getMappedLanguage(language);
174
+
175
+ await loadLanguageIfNeeded(highlighter, mappedLanguage);
176
+
177
+ const loadedLanguages = highlighter.getLoadedLanguages();
178
+ if (!loadedLanguages.includes(mappedLanguage)) {
179
+ mappedLanguage = "text" as BundledLanguage;
180
+ }
181
+
182
+ return highlighter.codeToHtml(code, {
183
+ lang: mappedLanguage,
184
+ theme: THEME_MAP[theme],
185
+ transformers: [transformerColorizedBrackets()],
186
+ colorReplacements: THEME_MAP_COLOR_REPLACEMENTS[theme].colorReplacements
187
+ });
188
+ }
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <!-- This is a utility module for Shiki syntax highlighting (static imports) -->
3
+ </template>
@@ -0,0 +1,46 @@
1
+ import type { HighlighterCore } from "shiki";
2
+ import * as shikiModule from "shiki";
3
+ import { transformerColorizedBrackets } from "@shikijs/colorized-brackets";
4
+ import {
5
+ createShikiState,
6
+ initializeHighlighter,
7
+ highlightCodeWithShiki,
8
+ escapeHtml as coreEscapeHtml,
9
+ ShikiState
10
+ } from "dxUtils/shikiCore";
11
+
12
+ /**
13
+ * Static loading version of Shiki.
14
+ * Uses static imports - shiki is bundled with this module.
15
+ * Use this for SSG compatibility and it is very specific to SSG generated components using LWR.
16
+ */
17
+
18
+ const shikiState: ShikiState = createShikiState();
19
+
20
+ async function initializeShiki(): Promise<HighlighterCore> {
21
+ return initializeHighlighter(shikiState, shikiModule);
22
+ }
23
+
24
+ export async function highlightCode(
25
+ code: string,
26
+ language: string,
27
+ theme: "light" | "dark" = "light"
28
+ ): Promise<string> {
29
+ try {
30
+ const highlighter = await initializeShiki();
31
+ return highlightCodeWithShiki(
32
+ code,
33
+ language,
34
+ theme,
35
+ highlighter,
36
+ transformerColorizedBrackets
37
+ );
38
+ } catch (error) {
39
+ console.error("Failed to highlight code with Shiki:", error);
40
+ return `<pre class="shiki ${theme}"><code>${escapeHtml(code)}</code></pre>`;
41
+ }
42
+ }
43
+
44
+ export function escapeHtml(text: string): string {
45
+ return coreEscapeHtml(text);
46
+ }