@salesforcedevs/dx-components 1.31.9-alpha5 → 1.31.9-alpha8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.31.9-alpha5",
3
+ "version": "1.31.9-alpha8",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -406,6 +406,7 @@ export default class CodeBlock extends LightningElement {
406
406
  ) || this.allLanguages[0];
407
407
  this.selectedLanguageLabel = this.selectedLanguage.label;
408
408
  this.selectedLanguageId = this.selectedLanguage.id;
409
+
409
410
  this.formatCodeBlock();
410
411
  }
411
412
 
@@ -35,7 +35,9 @@ export const createHighlighter = jest.fn().mockImplementation(() => {
35
35
  "text",
36
36
  "handlebars"
37
37
  ]),
38
- loadLanguage: jest.fn().mockResolvedValue(undefined)
38
+ getLoadedThemes: jest.fn().mockReturnValue(["light-plus", "material-theme-darker"]),
39
+ loadLanguage: jest.fn().mockResolvedValue(undefined),
40
+ loadTheme: jest.fn().mockResolvedValue(undefined)
39
41
  });
40
42
  });
41
43
 
@@ -92,7 +94,9 @@ export const createHighlighterCore = jest.fn().mockImplementation(() => {
92
94
  "text",
93
95
  "handlebars"
94
96
  ]),
95
- loadLanguage: jest.fn().mockResolvedValue(undefined)
97
+ getLoadedThemes: jest.fn().mockReturnValue(["light-plus", "material-theme-darker"]),
98
+ loadLanguage: jest.fn().mockResolvedValue(undefined),
99
+ loadTheme: jest.fn().mockResolvedValue(undefined)
96
100
  });
97
101
  });
98
102
 
@@ -107,5 +111,10 @@ export const createOnigurumaEngine = jest.fn().mockImplementation(() => {
107
111
  return Promise.resolve({});
108
112
  });
109
113
 
114
+ // Mock for shiki/engine/javascript
115
+ export const createJavaScriptRegexEngine = jest.fn().mockImplementation(() => {
116
+ return {};
117
+ });
118
+
110
119
  // Mock for shiki/wasm - just return a promise that resolves to a buffer
111
120
  export default Promise.resolve(new ArrayBuffer(0));
@@ -0,0 +1,6 @@
1
+ // Mock default export for individual shiki language grammar files (shiki/langs/*)
2
+ export default {
3
+ name: "mock-lang",
4
+ scopeName: "source.mock",
5
+ patterns: []
6
+ };
@@ -0,0 +1,5 @@
1
+ // Mock default export for individual shiki theme files (shiki/themes/*)
2
+ export default {
3
+ name: "mock-theme",
4
+ type: "light" as const
5
+ };
@@ -10,16 +10,22 @@ import {
10
10
  /**
11
11
  * Dynamic loading version of Shiki.
12
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.
13
+ * Uses createJavaScriptRegexEngine (no WASM) so it works in LWR at runtime.
14
14
  */
15
15
 
16
- let shikiModulePromise: Promise<typeof import("shiki")> | null = null;
16
+ let shikiModulePromise: Promise<{
17
+ createHighlighterCore: any;
18
+ createJavaScriptRegexEngine: any;
19
+ }> | null = null;
17
20
  let bracketsModulePromise: Promise<
18
21
  typeof import("@shikijs/colorized-brackets")
19
22
  > | null = null;
20
23
 
21
24
  async function getShiki() {
22
- return (shikiModulePromise ??= import("shiki"));
25
+ return (shikiModulePromise ??= import("shiki").then((m) => ({
26
+ createHighlighterCore: m.createHighlighterCore,
27
+ createJavaScriptRegexEngine: m.createJavaScriptRegexEngine
28
+ })));
23
29
  }
24
30
 
25
31
  async function getBrackets() {
@@ -29,8 +35,8 @@ async function getBrackets() {
29
35
  const shikiState: ShikiState = createShikiState();
30
36
 
31
37
  async function initializeShiki(): Promise<HighlighterCore> {
32
- const shikiModule = await getShiki();
33
- return initializeHighlighter(shikiState, shikiModule);
38
+ const { createHighlighterCore, createJavaScriptRegexEngine } = await getShiki();
39
+ return initializeHighlighter(shikiState, { createHighlighterCore }, createJavaScriptRegexEngine());
34
40
  }
35
41
 
36
42
  export async function highlightCode(
@@ -2,9 +2,10 @@ import type { BundledLanguage, BundledTheme, HighlighterCore } from "shiki";
2
2
  import { getCustomLanguageGrammars } from "dxUtils/shikiGrammars";
3
3
 
4
4
  export interface ShikiModule {
5
- createHighlighter: (options: {
6
- themes: string[];
7
- langs: BundledLanguage[];
5
+ createHighlighterCore: (options: {
6
+ themes: any[];
7
+ langs: any[];
8
+ engine: any;
8
9
  }) => Promise<HighlighterCore>;
9
10
  }
10
11
 
@@ -94,6 +95,41 @@ const languageLoadPromises = new WeakMap<
94
95
  Map<string, Promise<void>>
95
96
  >();
96
97
 
98
+ const themeLoadPromises = new WeakMap<
99
+ HighlighterCore,
100
+ Map<string, Promise<void>>
101
+ >();
102
+
103
+ export async function loadThemeIfNeeded(
104
+ highlighter: HighlighterCore,
105
+ themeName: BundledTheme
106
+ ): Promise<void> {
107
+ if ((highlighter.getLoadedThemes() as string[]).includes(themeName)) {
108
+ return;
109
+ }
110
+
111
+ if (!themeLoadPromises.has(highlighter)) {
112
+ themeLoadPromises.set(highlighter, new Map());
113
+ }
114
+ const promiseMap = themeLoadPromises.get(highlighter)!;
115
+
116
+ if (promiseMap.has(themeName)) {
117
+ return promiseMap.get(themeName);
118
+ }
119
+
120
+ const loadPromise = (async () => {
121
+ try {
122
+ await highlighter.loadTheme(themeName);
123
+ } catch (error) {
124
+ promiseMap.delete(themeName);
125
+ console.warn(`Failed to load theme ${themeName}:`, error);
126
+ }
127
+ })();
128
+
129
+ promiseMap.set(themeName, loadPromise);
130
+ return loadPromise;
131
+ }
132
+
97
133
  export async function loadLanguageIfNeeded(
98
134
  highlighter: HighlighterCore,
99
135
  language: string
@@ -160,7 +196,10 @@ export function createShikiState(): ShikiState {
160
196
 
161
197
  export async function initializeHighlighter(
162
198
  shikiState: ShikiState,
163
- shikiModule: ShikiModule
199
+ shikiModule: ShikiModule,
200
+ engine: any,
201
+ langs?: any[],
202
+ themes?: any[]
164
203
  ): Promise<HighlighterCore> {
165
204
  if (shikiState.highlighter) {
166
205
  return shikiState.highlighter;
@@ -171,9 +210,10 @@ export async function initializeHighlighter(
171
210
  }
172
211
 
173
212
  shikiState.initPromise = (async () => {
174
- const highlighter = await shikiModule.createHighlighter({
175
- themes: ["light-plus", "material-theme-darker"],
176
- langs: CORE_LANGUAGES
213
+ const highlighter = await shikiModule.createHighlighterCore({
214
+ themes: themes ?? [THEME_MAP.light],
215
+ langs: langs ?? CORE_LANGUAGES,
216
+ engine
177
217
  });
178
218
  shikiState.highlighter = highlighter;
179
219
  shikiState.initialized = true;
@@ -198,7 +238,11 @@ export async function highlightCodeWithShiki(
198
238
  ): Promise<string> {
199
239
  let mappedLanguage = getMappedLanguage(language);
200
240
 
201
- await loadLanguageIfNeeded(highlighter, mappedLanguage);
241
+ const themeName = THEME_MAP[theme];
242
+ await Promise.all([
243
+ loadLanguageIfNeeded(highlighter, mappedLanguage),
244
+ loadThemeIfNeeded(highlighter, themeName)
245
+ ]);
202
246
 
203
247
  const loadedLanguages = highlighter.getLoadedLanguages();
204
248
  if (!loadedLanguages.includes(mappedLanguage)) {
@@ -207,7 +251,7 @@ export async function highlightCodeWithShiki(
207
251
 
208
252
  return highlighter.codeToHtml(code, {
209
253
  lang: mappedLanguage,
210
- theme: THEME_MAP[theme],
254
+ theme: themeName,
211
255
  transformers: [transformerColorizedBrackets()],
212
256
  colorReplacements: THEME_MAP_COLOR_REPLACEMENTS[theme].colorReplacements
213
257
  });
@@ -1,4 +1,4 @@
1
- const dataweaveGrammar = {
1
+ function createDataweaveGrammar() { return {
2
2
  name: "dataweave",
3
3
  scopeName: "source.data-weave",
4
4
  fileTypes: ["dwl"],
@@ -1121,7 +1121,7 @@ const dataweaveGrammar = {
1121
1121
  ]
1122
1122
  }
1123
1123
  }
1124
- };
1124
+ }; }
1125
1125
 
1126
1126
  const ampscriptGrammar = {
1127
1127
  version: "2.0",
@@ -1300,7 +1300,7 @@ const ampscriptGrammar = {
1300
1300
  }
1301
1301
  };
1302
1302
 
1303
- const agentscriptGrammar = {
1303
+ function createAgentscriptGrammar() { return {
1304
1304
  name: "agentscript",
1305
1305
  scopeName: "source.agentscript",
1306
1306
  fileTypes: ["agent"],
@@ -2479,12 +2479,12 @@ const agentscriptGrammar = {
2479
2479
  ]
2480
2480
  }
2481
2481
  }
2482
- };
2482
+ }; }
2483
2483
 
2484
2484
  export function getCustomLanguageGrammars() {
2485
2485
  return {
2486
- dataweave: dataweaveGrammar,
2486
+ dataweave: createDataweaveGrammar,
2487
2487
  ampscript: ampscriptGrammar,
2488
- agentscript: agentscriptGrammar
2488
+ agentscript: createAgentscriptGrammar
2489
2489
  };
2490
2490
  }
@@ -1,6 +1,34 @@
1
- import type { HighlighterCore } from "shiki";
2
- import * as shikiModule from "shiki";
1
+ import type { HighlighterCore } from "shiki/core";
2
+ import { createHighlighterCore } from "shiki/core";
3
+ import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
3
4
  import { transformerColorizedBrackets } from "@shikijs/colorized-brackets";
5
+
6
+ // Individual language grammars — the bundler only processes these ~19 files
7
+ // instead of shiki's bundle-full.mjs which contains all 638 language factories.
8
+ import apex from "shiki/langs/apex.mjs";
9
+ import javascript from "shiki/langs/javascript.mjs";
10
+ import html from "shiki/langs/html.mjs";
11
+ import css from "shiki/langs/css.mjs";
12
+ import json from "shiki/langs/json.mjs";
13
+ import sql from "shiki/langs/sql.mjs";
14
+ import bash from "shiki/langs/bash.mjs";
15
+ import xml from "shiki/langs/xml.mjs";
16
+ import graphql from "shiki/langs/graphql.mjs";
17
+ import jsx from "shiki/langs/jsx.mjs";
18
+ import typescript from "shiki/langs/typescript.mjs";
19
+ import markdown from "shiki/langs/markdown.mjs";
20
+ import python from "shiki/langs/python.mjs";
21
+ import java from "shiki/langs/java.mjs";
22
+ import yaml from "shiki/langs/yaml.mjs";
23
+ import php from "shiki/langs/php.mjs";
24
+ import swift from "shiki/langs/swift.mjs";
25
+ import kotlin from "shiki/langs/kotlin.mjs";
26
+ import handlebars from "shiki/langs/handlebars.mjs";
27
+
28
+ // Individual themes — avoids loading all bundled themes.
29
+ import lightPlusTheme from "shiki/themes/light-plus.mjs";
30
+ import darkTheme from "shiki/themes/material-theme-darker.mjs";
31
+
4
32
  import {
5
33
  createShikiState,
6
34
  initializeHighlighter,
@@ -8,30 +36,41 @@ import {
8
36
  escapeHtml as coreEscapeHtml,
9
37
  ShikiState
10
38
  } from "dxUtils/shikiCore";
39
+ import { getCustomLanguageGrammars } from "dxUtils/shikiGrammars";
11
40
 
12
41
  /**
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.
42
+ * Static loading version of Shiki for SSG.
43
+ * Imports from shiki/core + individual language/theme files so the bundler
44
+ * only processes what is actually used, instead of shiki's bundle-full.mjs
45
+ * (638 language factories).
16
46
  */
17
47
 
48
+ // All languages loaded upfront — custom grammars are grammar objects already.
49
+ const ALL_LANGUAGES = [
50
+ apex, javascript, html, css, json, sql, bash, xml, graphql, jsx,
51
+ typescript, markdown, python, java, yaml, php, swift, kotlin, handlebars,
52
+ getCustomLanguageGrammars().ampscript,
53
+ getCustomLanguageGrammars().dataweave,
54
+ getCustomLanguageGrammars().agentscript
55
+ ];
56
+
57
+ // Both themes loaded upfront so theme switching has no cold-start cost.
58
+ const ALL_THEMES = [lightPlusTheme, darkTheme];
59
+
18
60
  const shikiState: ShikiState = createShikiState();
19
61
 
20
62
  async function initializeShiki(): Promise<HighlighterCore> {
21
- return initializeHighlighter(shikiState, shikiModule);
22
- }
23
-
24
- /**
25
- * Pre-warms the Shiki highlighter. Call once at SSG startup (before pages
26
- * render) so code blocks don't pay the cold-start cost on first render.
27
- */
28
- export async function preloadShiki(): Promise<void> {
29
- await initializeShiki();
63
+ return initializeHighlighter(
64
+ shikiState,
65
+ { createHighlighterCore },
66
+ createJavaScriptRegexEngine(),
67
+ ALL_LANGUAGES,
68
+ ALL_THEMES
69
+ );
30
70
  }
31
71
 
32
- // Eagerly kick off initialization at module import time.
33
- // In SSG, this module is imported during LWR startup — by the time
34
- // the first code block renders, the highlighter will already be ready.
72
+ // Eagerly kick off initialization at module import time so Shiki is ready
73
+ // before the first code block renders.
35
74
  initializeShiki().catch((err) => {
36
75
  console.error("Shiki pre-warming failed:", err);
37
76
  });