@salesforcedevs/dx-components 1.18.6 → 1.18.8-layoutfix-alpha

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.18.6",
3
+ "version": "1.18.8-layoutfix-alpha",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -13,7 +13,7 @@
13
13
  "@coveo/headless": "3.22.2",
14
14
  "@floating-ui/dom": "1.5.1",
15
15
  "@optimizely/optimizely-sdk": "5.3.0",
16
- "@salesforcedevs/sfdocs-wires": "0.6.98",
16
+ "@shikijs/colorized-brackets": "^3.12.2",
17
17
  "@types/throttle-debounce": "5.0.2",
18
18
  "@vimeo/player": "2.22.0",
19
19
  "classnames": "2.5.1",
@@ -26,6 +26,7 @@
26
26
  "lodash.kebabcase": "4.1.1",
27
27
  "memoize-one": "6.0.0",
28
28
  "microtip": "0.2.2",
29
+ "shiki": "^3.12.2",
29
30
  "throttle-debounce": "5.0.0",
30
31
  "uuid": "9.0.1"
31
32
  },
@@ -44,6 +45,5 @@
44
45
  },
45
46
  "volta": {
46
47
  "node": "20.19.0"
47
- },
48
- "gitHead": "a96577b729c567b862754304eee2b3ad489b3765"
48
+ }
49
49
  }
@@ -1,6 +1,5 @@
1
1
  @import "dxHelpers/code";
2
2
  @import "dxHelpers/text";
3
- @import "./darkAndLightThemes.css";
4
3
 
5
4
  :host {
6
5
  position: relative;
@@ -89,6 +88,7 @@ div.dx-theme-light {
89
88
  --dx-c-button-custom-color: #fff;
90
89
  --dx-c-button-custom-color-hover: #fff;
91
90
  --dx-c-button-custom-background-hover: var(--dx-g-blue-natural-10);
91
+ --dx-c-button-inline-color: #fff;
92
92
  }
93
93
 
94
94
  .dx-theme-light .btn {
@@ -98,15 +98,15 @@ div.dx-theme-light {
98
98
  --dx-c-button-custom-color: var(--dx-g-blue-vibrant-20);
99
99
  --dx-c-button-custom-color-hover: var(--dx-g-blue-vibrant-20);
100
100
  --dx-c-button-custom-background-hover: var(--dx-g-gray-60);
101
+ --dx-c-button-inline-color: var(--dx-g-blue-vibrant-20);
101
102
  }
102
103
 
103
104
  div.code-block-content {
104
105
  border-radius: 0 0 0.3em 0.3em;
105
106
  overflow-y: auto;
106
- background: var(--prism-a11y-color-background);
107
107
  }
108
108
 
109
- code[class*="language-"] {
109
+ code[class*="shiki"] {
110
110
  margin-left: -11px;
111
111
  }
112
112
 
@@ -114,14 +114,20 @@ code[class*="language-"] {
114
114
  margin-right: var(--dx-g-spacing-xs);
115
115
  }
116
116
 
117
- pre[class*="language-"] {
117
+ pre[class*="shiki"] {
118
118
  border-radius: 0 0 0.3em 0.3em;
119
- padding-bottom: var(--dx-g-spacing-smd);
120
- padding-top: var(--dx-g-spacing-sm);
121
- }
122
-
123
- pre[class*="language-"].line-numbers {
124
- padding-left: 56px;
119
+ padding: 1em;
120
+ margin: 0.5em 0;
121
+ overflow: auto;
122
+ /* stylelint-disable-next-line */
123
+ .line {
124
+ counter-increment: codeblock-line;
125
+
126
+ &::before {
127
+ content: counter(codeblock-line);
128
+ margin-right: 1.3em;
129
+ }
130
+ }
125
131
  }
126
132
 
127
133
  @media screen and (max-width: 640px) {
@@ -2,35 +2,17 @@ import { LightningElement, api } from "lwc";
2
2
  import { CodeBlockTheme, CodeBlockLanguage } from "typings/custom";
3
3
  import cx from "classnames";
4
4
  import { track as gtmTrack } from "dxUtils/analytics";
5
- import prism from "dxUtils/prismjs";
6
- import { ampscript, sqlDocsTemplate } from "./customLanguages";
5
+ import { highlightCode } from "dxUtils/shiki";
7
6
 
8
7
  /*
9
- Here we create custom syntax highlighting rules for proprietary languages
8
+ Custom language support is handled by the Shiki wrapper module
9
+ which maps proprietary languages to supported ones:
10
+ - AMPScript -> HTML (markup-like syntax)
11
+ - SSJS -> JavaScript
12
+ - GTL -> Handlebars
13
+ - LWC -> JavaScript/JSX
14
+ - SQL Documentation -> SQL
10
15
  */
11
- // AMPScript
12
- prism.languages.ampscript = prism.languages.extend("markup");
13
- prism.languages.insertBefore("ampscript", "comment", { ampscript });
14
-
15
- // SSJS (Server-Side JavaScript)
16
- prism.languages.ssjs = prism.languages.extend("markup");
17
- prism.languages.insertBefore("ssjs", "comment", { ampscript });
18
-
19
- // GTL (Guide Template Language)
20
- prism.languages.gtl = prism.languages.extend(
21
- "markup",
22
- prism.languages.handlebars
23
- );
24
-
25
- // LWC
26
- prism.languages.lwc = prism.languages.extend("jsx");
27
-
28
- /*
29
- Prismjs's SQL native language rules doesn't highlight keyword like "RECURSIVE" and "WINDOW".
30
- Instead of modifying the native SQL language rules, we create a new language called "sql_docs_template"
31
- that treats all uppercase words as keywords.
32
- */
33
- prism.languages.sql_docs_template = sqlDocsTemplate;
34
16
 
35
17
  // Used for remove enclosing <pre> tag's (if occurs)
36
18
  const preTagRegexp: RegExp = /^<pre.*?>(.*)<\/pre>$/is;
@@ -89,7 +71,8 @@ export default class CodeBlock extends LightningElement {
89
71
  { label: "SSJS", id: "ssjs" },
90
72
  { label: "GTL", id: "gtl" },
91
73
  { label: "LWC", id: "lwc" },
92
- { label: "SQL Documentation", id: "sql_docs_template" }
74
+ { label: "SQL Documentation", id: "sql_docs_template" },
75
+ { label: "Agentforce Script", id: "afscript" }
93
76
  ];
94
77
 
95
78
  _codeBlock: string = "";
@@ -135,80 +118,100 @@ export default class CodeBlock extends LightningElement {
135
118
  this.initializeTheme();
136
119
  }
137
120
 
138
- formatCodeBlock() {
121
+ async formatCodeBlock() {
139
122
  const divEl = this.template.querySelector("div.code-block-content");
140
123
  const templateEl = document.createElement("template");
141
124
 
125
+ // Decode HTML entities if the code is already encoded
126
+ let cleanCodeBlock = this.codeBlock;
127
+ if (this.isEncoded) {
128
+ // Create a temporary element to decode HTML entities
129
+ const tempElement = document.createElement("div");
130
+ tempElement.innerHTML = cleanCodeBlock;
131
+ cleanCodeBlock =
132
+ tempElement.textContent ||
133
+ tempElement.innerText ||
134
+ cleanCodeBlock;
135
+ }
136
+
142
137
  // Replace any <var> markup with a temporary nonsense sentinel (but one that is very
143
- // unlikely to affect Prism's tokenization) so that Prism will not strip them but does
144
- // still tokenize correctly. We want to italicize the "variables" ourselves after Prism
138
+ // unlikely to affect Shiki's tokenization) so that Shiki will not strip them but does
139
+ // still tokenize correctly. We want to italicize the "variables" ourselves after Shiki
145
140
  // does its own thing (W-11975205).
146
- let cleanCodeBlock = this.codeBlock.replace(
141
+ cleanCodeBlock = cleanCodeBlock.replace(
147
142
  /<var.*?>(.+?)<\/var>/g,
148
143
  "vvvvv$1vvvvv"
149
144
  );
150
145
 
146
+ // For markup languages, preserve existing HTML comments but don't wrap the whole thing in comments
151
147
  if (
152
148
  !this.isEncoded &&
153
149
  this.markupLangs.includes(this.selectedLanguage.id || "")
154
150
  ) {
155
- // Temporarily replace HTML comment characters, which Prism would also strip
156
- cleanCodeBlock = `<!--${cleanCodeBlock.replace(
151
+ // Temporarily replace HTML comment characters to preserve them during highlighting
152
+ cleanCodeBlock = cleanCodeBlock.replace(
157
153
  /<!--(.*?)-->/gs,
158
- "@@$1##"
159
- )}-->`;
160
- } else {
161
- // If this is a non-encoded markup language, encode angle brackets that Prism would strip
162
- cleanCodeBlock = this.isEncoded
163
- ? cleanCodeBlock
164
- : cleanCodeBlock.replace(/</g, "&lt").replace(/>/g, "&gt");
154
+ "@@COMMENT_START@@$1@@COMMENT_END@@"
155
+ );
165
156
  }
166
157
 
167
- // eslint-disable-next-line
168
- templateEl.innerHTML = `<pre class='codeblock'>${cleanCodeBlock}</pre>`;
158
+ // Determine the language to use for highlighting
159
+ const languageForHighlighting = this.markupLangs.includes(
160
+ this.selectedLanguage.id || ""
161
+ )
162
+ ? "html"
163
+ : this.selectedLanguage.id || "text";
169
164
 
170
- const codeBlockEls = templateEl.content.querySelectorAll("pre");
171
- codeBlockEls.forEach((codeBlockEl) => {
172
- // eslint-disable-next-line
173
- const codeHTML = codeBlockEl.innerHTML;
174
- codeBlockEl.classList.add("line-numbers");
175
- const codeEl = document.createElement("code");
176
- codeEl.classList.add(
177
- `language-${
178
- this.markupLangs.includes(this.selectedLanguage.id || "")
179
- ? "markup"
180
- : this.selectedLanguage.id
181
- }`
165
+ try {
166
+ // Use Shiki to highlight the code with current theme
167
+ const highlightedHtml = await highlightCode(
168
+ cleanCodeBlock,
169
+ languageForHighlighting,
170
+ this.theme as "light" | "dark"
182
171
  );
183
- // for custom markup content, it is a workaround to be refactored later.
184
- // eslint-disable-next-line
185
- this.language !== "text"
186
- ? // eslint-disable-next-line
187
- (codeEl.innerHTML = codeHTML)
188
- : (codeEl.textContent = this._codeBlock.trim());
189
- // eslint-disable-next-line
190
- codeBlockEl.innerHTML = "";
191
- codeBlockEl.appendChild(codeEl);
192
- prism.highlightAllUnder(codeBlockEl);
193
- // Italicize anything marked as a "variable" by the docs team
172
+
173
+ const tempDiv = document.createElement("div");
194
174
  // eslint-disable-next-line
195
- codeBlockEl.innerHTML = codeBlockEl.innerHTML.replace(
196
- /vvvvv(.+?)vvvvv/g,
197
- "<span class='token italic'>$1</span>"
175
+ tempDiv.innerHTML = highlightedHtml;
176
+ const preElement = tempDiv.querySelector("pre");
177
+
178
+ if (preElement) {
179
+ preElement.classList.add("codeblock");
180
+
181
+ // Italicize anything marked as a "variable" by the docs team
182
+ // eslint-disable-next-line
183
+ preElement.innerHTML = preElement.innerHTML.replace(
184
+ /vvvvv(.+?)vvvvv/g,
185
+ "<span class='token italic'>$1</span>"
186
+ );
187
+ // eslint-disable-next-line
188
+ templateEl.innerHTML = preElement.outerHTML;
189
+ } else {
190
+ // Fallback if Shiki fails
191
+ // eslint-disable-next-line
192
+ templateEl.innerHTML = `<pre class='codeblock'><code class='shiki'>${cleanCodeBlock}</code></pre>`;
193
+ }
194
+ } catch (error) {
195
+ console.error(
196
+ "Shiki highlighting failed, falling back to plain text:",
197
+ error
198
198
  );
199
- });
199
+ // Fallback to plain text
200
+ // eslint-disable-next-line
201
+ templateEl.innerHTML = `<pre class='codeblock'><code class='shiki'>${cleanCodeBlock}</code></pre>`;
202
+ }
200
203
 
201
204
  if (divEl) {
202
205
  // eslint-disable-next-line
203
206
  divEl.innerHTML = "";
204
207
  divEl.append(templateEl.content);
205
208
  if (this.markupLangs.includes(this.selectedLanguage.id || "")) {
206
- const res = this.template.querySelector(`code.language-markup`);
209
+ const res = this.template.querySelector(`code`);
207
210
  if (res) {
208
211
  // Restore any temporarily replaced HTML comment characters
209
212
  // eslint-disable-next-line
210
213
  res.innerHTML = res.innerHTML.replace(
211
- /@@(.*?)##/gs,
214
+ /@@COMMENT_START@@(.*?)@@COMMENT_END@@/gs,
212
215
  `<span class="token comment">&lt;!--$1--&gt;</span>`
213
216
  );
214
217
  }
@@ -277,6 +280,13 @@ export default class CodeBlock extends LightningElement {
277
280
  private toggleTheme = () => {
278
281
  this.theme = this.theme === DARK ? LIGHT : DARK;
279
282
  this.storeTheme();
283
+ // Re-render the code block with the new theme
284
+ this.formatCodeBlock().catch((error) => {
285
+ console.error(
286
+ "Failed to re-format code block after theme change:",
287
+ error
288
+ );
289
+ });
280
290
  };
281
291
 
282
292
  private storeTheme = () => {
@@ -3,7 +3,7 @@
3
3
 
4
4
  .toc {
5
5
  display: flex;
6
- flex-direction: row-reverse;
6
+ flex-direction: var(--dx-c-toc-flex-direction, row-reverse);
7
7
  max-width: 240px;
8
8
  min-width: 80px;
9
9
  word-break: break-word;
@@ -1,4 +1,3 @@
1
- /* Custom prism.js stylesheet */
2
1
  /* stylelint-disable selector-pseudo-element-no-unknown */
3
2
  .dx-variant-block dx-button {
4
3
  --dx-c-button-primary-color: var(--dx-g-gray-50);
@@ -21,8 +20,8 @@
21
20
  --dx-c-button-inline-color-hover: var(--dx-g-hot-orange-vibrant-95);
22
21
  }
23
22
 
24
- pre[class*="language-"],
25
- code[class*="language-"] {
23
+ pre[class*="shiki"],
24
+ code[class*="shiki"] {
26
25
  font-size: 14px;
27
26
  text-shadow: none;
28
27
  font-family: var(--dx-g-font-mono);
@@ -36,30 +35,30 @@ code[class*="language-"] {
36
35
  hyphens: none;
37
36
  }
38
37
 
39
- pre[class*="language-"]::selection,
40
- code[class*="language-"]::selection,
41
- pre[class*="language-"]::mozselection,
42
- code[class*="language-"]::mozselection {
38
+ pre[class*="shiki"]::selection,
39
+ code[class*="shiki"]::selection,
40
+ pre[class*="shiki"]::mozselection,
41
+ code[class*="shiki"]::mozselection {
43
42
  text-shadow: none;
44
43
  }
45
44
 
46
- .dx-theme-dark code[class*="language-"] {
45
+ .dx-theme-dark code[class*="shiki"] {
47
46
  color: rgb(255 255 255);
48
47
  }
49
48
 
50
- .dx-theme-light code[class*="language-"] {
49
+ .dx-theme-light code[class*="shiki"] {
51
50
  color: var(--dx-g-gray-10);
52
51
  }
53
52
 
54
- .dx-theme-dark code[class*="language-"]::mozselection {
53
+ .dx-theme-dark code[class*="shiki"]::mozselection {
55
54
  background: rgb(255 255 255);
56
55
  }
57
56
 
58
- .dx-theme-light code[class*="language-"]::mozselection {
57
+ .dx-theme-light code[class*="shiki"]::mozselection {
59
58
  background: var(--dx-g-gray-95);
60
59
  }
61
60
 
62
- .dx-variant-card pre[class*="language-"] {
61
+ .dx-variant-card pre[class*="shiki"] {
63
62
  padding: 1em;
64
63
  border-radius: 0 0 0.3em 0.3em;
65
64
  overflow: auto;
@@ -67,12 +66,12 @@ code[class*="language-"]::mozselection {
67
66
  white-space: pre;
68
67
  }
69
68
 
70
- .dx-variant-card :not(pre) > code[class*="language-"] {
69
+ .dx-variant-card :not(pre) > code[class*="shiki"] {
71
70
  padding: 0.1em 0.3em;
72
71
  border-radius: 0.3em;
73
72
  }
74
73
 
75
- .dx-variant-block pre[class*="language-"] {
74
+ .dx-variant-block pre[class*="shiki"] {
76
75
  padding: 1em;
77
76
  border-radius: 0.3em;
78
77
  overflow: auto;
@@ -81,27 +80,27 @@ code[class*="language-"]::mozselection {
81
80
  width: 94%;
82
81
  }
83
82
 
84
- .dx-variant-block :not(pre) > code[class*="language-"] {
83
+ .dx-variant-block :not(pre) > code[class*="shiki"] {
85
84
  padding: 0.1em 0.3em;
86
85
  border-radius: 0.3em;
87
86
  }
88
87
 
89
- .dx-theme-dark pre[class*="language-"] {
88
+ .dx-theme-dark pre[class*="shiki"] {
90
89
  color: rgb(255 255 255);
91
90
  background: var(--dx-g-blue-vibrant-10);
92
91
  }
93
92
 
94
- .dx-theme-dark :not(pre) > code[class*="language-"] {
93
+ .dx-theme-dark :not(pre) > code[class*="shiki"] {
95
94
  color: rgb(255 255 255);
96
95
  background: var(--dx-g-blue-vibrant-10);
97
96
  }
98
97
 
99
- .dx-theme-light pre[class*="language-"] {
98
+ .dx-theme-light pre[class*="shiki"] {
100
99
  color: var(--dx-g-gray-10);
101
100
  background: var(--dx-g-gray-95);
102
101
  }
103
102
 
104
- .dx-theme-light :not(pre) > code[class*="language-"] {
103
+ .dx-theme-light :not(pre) > code[class*="shiki"] {
105
104
  color: var(--dx-g-gray-10);
106
105
  background: var(--dx-g-gray-95);
107
106
  }
@@ -133,79 +132,12 @@ pre[data-line] {
133
132
  position: relative;
134
133
  }
135
134
 
136
- pre[class*="language-"] > code[class*="language-"] {
135
+ pre[class*="shiki"] > code[class*="shiki"] {
137
136
  position: relative;
138
137
  display: block;
139
138
  z-index: 1;
140
139
  }
141
140
 
142
- .line-highlight {
143
- position: absolute;
144
- left: 0;
145
- right: 0;
146
- padding: inherit 0;
147
- margin-top: 1em;
148
- background: #1e2d50;
149
- box-shadow: inset 5px 0 0 #0176d3;
150
- z-index: 0;
151
- pointer-events: none;
152
- line-height: inherit;
153
- white-space: pre;
154
- }
155
-
156
- .line-numbers .line-highlight::before,
157
- .line-numbers .line-highlight::after {
158
- content: none;
159
- }
160
-
161
- .line-numbers-rows > span::before {
162
- content: counter(linenumber);
163
- color: var(--dx-g-gray-50);
164
- display: block;
165
- padding-right: 0.4em;
166
- text-align: right;
167
- }
168
-
169
- pre[id].linkable-line-numbers span.line-numbers-rows {
170
- pointer-events: all;
171
- }
172
-
173
- pre[id].linkable-line-numbers span.line-numbers-rows > span::before {
174
- cursor: pointer;
175
- }
176
-
177
- pre[id].linkable-line-numbers span.line-numbers-rows > span:hover::before {
178
- background-color: rgb(128 128 128 / 20%);
179
- }
180
-
181
- pre[class*="language-"].line-numbers {
182
- position: relative;
183
- padding-left: 3.8em;
184
- counter-reset: linenumber;
185
- }
186
-
187
- pre[class*="language-"].line-numbers > code {
188
- position: relative;
189
- white-space: inherit;
190
- width: 1px;
191
- }
192
-
193
- .line-numbers .line-numbers-rows {
194
- position: absolute;
195
- pointer-events: none;
196
- top: 0;
197
- font-size: 100%;
198
- left: -3.8em;
199
- width: 3em; /* works for line-numbers below 1000 lines */
200
- letter-spacing: -1px;
201
- user-select: none;
202
- }
203
-
204
- .line-numbers-rows > span {
205
- display: block;
206
- counter-increment: linenumber;
207
- }
208
-
209
141
  .dx-variant-block.code-toolbar {
210
142
  display: flex;
211
143
  }
@@ -0,0 +1,110 @@
1
+ // Mock for shiki module
2
+ export const createHighlighter = jest.fn().mockImplementation(() => {
3
+ return Promise.resolve({
4
+ codeToHtml: jest.fn().mockImplementation((code, options) => {
5
+ // Preserve the original code content and add variable elements if present
6
+ let htmlContent = code;
7
+
8
+ // Check for <var> elements in the code and preserve them
9
+ if (code.includes("<var>")) {
10
+ // Replace <var> elements with tokenized spans
11
+ htmlContent = code.replace(
12
+ /<var>(.*?)<\/var>/g,
13
+ (match, content) =>
14
+ `<span class="token variable"><var>${content}</var></span>`
15
+ );
16
+ }
17
+
18
+ // Add test content for specific test cases
19
+ if (code.includes("Salesforce Functions")) {
20
+ htmlContent = "Connected to Salesforce Functions";
21
+ }
22
+
23
+ return `<pre class="shiki ${
24
+ options?.theme || "light"
25
+ }"><code>${htmlContent}</code></pre>`;
26
+ }),
27
+ getLoadedLanguages: jest
28
+ .fn()
29
+ .mockReturnValue([
30
+ "javascript",
31
+ "typescript",
32
+ "html",
33
+ "css",
34
+ "apex",
35
+ "text",
36
+ "handlebars"
37
+ ])
38
+ });
39
+ });
40
+
41
+ export type Highlighter = {
42
+ codeToHtml: (code: string, options: any) => string;
43
+ getLoadedLanguages: () => string[];
44
+ };
45
+
46
+ export type BundledLanguage = string;
47
+ export type BundledTheme = string;
48
+
49
+ export const codeToHast = jest.fn();
50
+ export const codeToHtml = jest.fn();
51
+ export const codeToTokens = jest.fn();
52
+ export const codeToTokensBase = jest.fn();
53
+ export const codeToTokensWithThemes = jest.fn();
54
+ export const getLastGrammarState = jest.fn();
55
+ export const getSingletonHighlighter = jest.fn();
56
+
57
+ // Mock for shiki/core exports
58
+ export const createHighlighterCore = jest.fn().mockImplementation(() => {
59
+ return Promise.resolve({
60
+ codeToHtml: jest.fn().mockImplementation((code, options) => {
61
+ // Preserve the original code content and add variable elements if present
62
+ let htmlContent = code;
63
+
64
+ // Check for <var> elements in the code and preserve them
65
+ if (code.includes("<var>")) {
66
+ // Replace <var> elements with tokenized spans
67
+ htmlContent = code.replace(
68
+ /<var>(.*?)<\/var>/g,
69
+ (match, content) =>
70
+ `<span class="token variable"><var>${content}</var></span>`
71
+ );
72
+ }
73
+
74
+ // Add test content for specific test cases
75
+ if (code.includes("Salesforce Functions")) {
76
+ htmlContent = "Connected to Salesforce Functions";
77
+ }
78
+
79
+ return `<pre class="shiki ${
80
+ options?.theme || "light"
81
+ }"><code>${htmlContent}</code></pre>`;
82
+ }),
83
+ getLoadedLanguages: jest
84
+ .fn()
85
+ .mockReturnValue([
86
+ "javascript",
87
+ "typescript",
88
+ "html",
89
+ "css",
90
+ "apex",
91
+ "text",
92
+ "handlebars"
93
+ ]),
94
+ loadLanguage: jest.fn().mockResolvedValue(undefined)
95
+ });
96
+ });
97
+
98
+ export type HighlighterCore = {
99
+ codeToHtml: (code: string, options: any) => string;
100
+ getLoadedLanguages: () => string[];
101
+ loadLanguage: (lang: any) => Promise<void>;
102
+ };
103
+
104
+ // Mock for shiki/engine/oniguruma
105
+ export const createOnigurumaEngine = jest.fn().mockImplementation(() => {
106
+ return Promise.resolve({});
107
+ });
108
+
109
+ // Mock for shiki/wasm - just return a promise that resolves to a buffer
110
+ export default Promise.resolve(new ArrayBuffer(0));
@@ -0,0 +1,23 @@
1
+ // Mock for @shikijs/* packages
2
+
3
+ // Mock language modules - return a grammar object
4
+ const mockLanguage = {
5
+ name: "mock-language",
6
+ scopeName: "source.mock",
7
+ patterns: []
8
+ };
9
+
10
+ // Mock theme modules - return a theme object
11
+ const mockTheme = {
12
+ name: "mock-theme",
13
+ type: "light",
14
+ colors: {},
15
+ tokenColors: []
16
+ };
17
+
18
+ // Default export for all @shikijs modules
19
+ export default mockLanguage;
20
+
21
+ // Also export as named export for themes
22
+ export const theme = mockTheme;
23
+ export const lang = mockLanguage;