@salesforcedevs/dx-components 1.31.8-alpha.1 → 1.31.9-alpha10
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/logs.txt +49007 -0
- package/package.json +2 -3
- package/src/modules/dx/codeBlock/codeBlock.css +7 -0
- package/src/modules/dx/codeBlock/codeBlock.ts +1 -0
- package/src/modules/dxUtils/shiki/__mocks__/shiki.ts +11 -2
- package/src/modules/dxUtils/shiki/__mocks__/shikiLang.ts +6 -0
- package/src/modules/dxUtils/shiki/__mocks__/shikiTheme.ts +5 -0
- package/src/modules/dxUtils/shiki/shiki.ts +11 -5
- package/src/modules/dxUtils/shikiCore/shikiCore.ts +97 -27
- package/src/modules/dxUtils/shikiGrammars/shikiGrammars.ts +6 -6
- package/src/modules/dxUtils/shikiStatic/shikiStatic.ts +60 -6
- package/LICENSE +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/dx-components",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.9-alpha10",
|
|
4
4
|
"description": "DX Lightning web components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -43,6 +43,5 @@
|
|
|
43
43
|
"eventsourcemock": "2.0.0",
|
|
44
44
|
"luxon": "3.4.4",
|
|
45
45
|
"msw": "^2.12.4"
|
|
46
|
-
}
|
|
47
|
-
"gitHead": "603ae2f74f050fb351c48981ce44926b8dedb4f9"
|
|
46
|
+
}
|
|
48
47
|
}
|
|
@@ -143,6 +143,13 @@ code[class*="shiki"] {
|
|
|
143
143
|
padding: 0 var(--dx-g-spacing-md) 0 var(--dx-g-spacing-sm);
|
|
144
144
|
text-align: right;
|
|
145
145
|
user-select: none;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.dx-theme-light .code-line-number {
|
|
149
|
+
color: var(--dx-g-gray-40);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.dx-theme-dark .code-line-number {
|
|
146
153
|
color: var(--dx-g-gray-60);
|
|
147
154
|
}
|
|
148
155
|
|
|
@@ -35,7 +35,9 @@ export const createHighlighter = jest.fn().mockImplementation(() => {
|
|
|
35
35
|
"text",
|
|
36
36
|
"handlebars"
|
|
37
37
|
]),
|
|
38
|
-
|
|
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
|
-
|
|
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));
|
|
@@ -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
|
-
*
|
|
13
|
+
* Uses createJavaScriptRegexEngine (no WASM) so it works in LWR at runtime.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
let shikiModulePromise: Promise<
|
|
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
|
|
33
|
-
return initializeHighlighter(shikiState,
|
|
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
|
-
|
|
6
|
-
themes:
|
|
7
|
-
langs:
|
|
5
|
+
createHighlighterCore: (options: {
|
|
6
|
+
themes: any[];
|
|
7
|
+
langs: any[];
|
|
8
|
+
engine: any;
|
|
8
9
|
}) => Promise<HighlighterCore>;
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -89,26 +90,86 @@ export const OPTIONAL_LANGUAGES: Record<string, any> = {
|
|
|
89
90
|
agentscript: getCustomLanguageGrammars().agentscript
|
|
90
91
|
};
|
|
91
92
|
|
|
93
|
+
const languageLoadPromises = new WeakMap<
|
|
94
|
+
HighlighterCore,
|
|
95
|
+
Map<string, Promise<void>>
|
|
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
|
+
|
|
92
133
|
export async function loadLanguageIfNeeded(
|
|
93
134
|
highlighter: HighlighterCore,
|
|
94
135
|
language: string
|
|
95
136
|
): Promise<void> {
|
|
96
|
-
|
|
137
|
+
// Fast path: already loaded
|
|
138
|
+
if (highlighter.getLoadedLanguages().includes(language as BundledLanguage)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
97
141
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
`Failed to load optional language ${language}:`,
|
|
107
|
-
error
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
142
|
+
const languageLoader = OPTIONAL_LANGUAGES[language];
|
|
143
|
+
if (!languageLoader) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Get or create the promise map for this highlighter instance
|
|
148
|
+
if (!languageLoadPromises.has(highlighter)) {
|
|
149
|
+
languageLoadPromises.set(highlighter, new Map());
|
|
111
150
|
}
|
|
151
|
+
const promiseMap = languageLoadPromises.get(highlighter)!;
|
|
152
|
+
|
|
153
|
+
// Reuse in-flight promise — prevents duplicate loadLanguage() calls
|
|
154
|
+
// when multiple code blocks request the same optional language concurrently
|
|
155
|
+
if (promiseMap.has(language)) {
|
|
156
|
+
return promiseMap.get(language);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const loadPromise = (async () => {
|
|
160
|
+
try {
|
|
161
|
+
await highlighter.loadLanguage(languageLoader);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
promiseMap.delete(language); // allow retry on next call
|
|
164
|
+
console.warn(
|
|
165
|
+
`Failed to load optional language ${language}:`,
|
|
166
|
+
error
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
|
|
171
|
+
promiseMap.set(language, loadPromise);
|
|
172
|
+
return loadPromise;
|
|
112
173
|
}
|
|
113
174
|
|
|
114
175
|
export function getMappedLanguage(language: string): BundledLanguage {
|
|
@@ -118,10 +179,11 @@ export function getMappedLanguage(language: string): BundledLanguage {
|
|
|
118
179
|
}
|
|
119
180
|
|
|
120
181
|
export function escapeHtml(text: string): string {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
182
|
+
return text
|
|
183
|
+
.replace(/&/g, "&")
|
|
184
|
+
.replace(/</g, "<")
|
|
185
|
+
.replace(/>/g, ">")
|
|
186
|
+
.replace(/"/g, """);
|
|
125
187
|
}
|
|
126
188
|
|
|
127
189
|
export function createShikiState(): ShikiState {
|
|
@@ -134,7 +196,10 @@ export function createShikiState(): ShikiState {
|
|
|
134
196
|
|
|
135
197
|
export async function initializeHighlighter(
|
|
136
198
|
shikiState: ShikiState,
|
|
137
|
-
shikiModule: ShikiModule
|
|
199
|
+
shikiModule: ShikiModule,
|
|
200
|
+
engine: any,
|
|
201
|
+
langs?: any[],
|
|
202
|
+
themes?: any[]
|
|
138
203
|
): Promise<HighlighterCore> {
|
|
139
204
|
if (shikiState.highlighter) {
|
|
140
205
|
return shikiState.highlighter;
|
|
@@ -145,9 +210,10 @@ export async function initializeHighlighter(
|
|
|
145
210
|
}
|
|
146
211
|
|
|
147
212
|
shikiState.initPromise = (async () => {
|
|
148
|
-
const highlighter = await shikiModule.
|
|
149
|
-
themes: [
|
|
150
|
-
langs: CORE_LANGUAGES
|
|
213
|
+
const highlighter = await shikiModule.createHighlighterCore({
|
|
214
|
+
themes: themes ?? [THEME_MAP.light],
|
|
215
|
+
langs: langs ?? CORE_LANGUAGES,
|
|
216
|
+
engine
|
|
151
217
|
});
|
|
152
218
|
shikiState.highlighter = highlighter;
|
|
153
219
|
shikiState.initialized = true;
|
|
@@ -172,7 +238,11 @@ export async function highlightCodeWithShiki(
|
|
|
172
238
|
): Promise<string> {
|
|
173
239
|
let mappedLanguage = getMappedLanguage(language);
|
|
174
240
|
|
|
175
|
-
|
|
241
|
+
const themeName = THEME_MAP[theme];
|
|
242
|
+
await Promise.all([
|
|
243
|
+
loadLanguageIfNeeded(highlighter, mappedLanguage),
|
|
244
|
+
loadThemeIfNeeded(highlighter, themeName)
|
|
245
|
+
]);
|
|
176
246
|
|
|
177
247
|
const loadedLanguages = highlighter.getLoadedLanguages();
|
|
178
248
|
if (!loadedLanguages.includes(mappedLanguage)) {
|
|
@@ -181,7 +251,7 @@ export async function highlightCodeWithShiki(
|
|
|
181
251
|
|
|
182
252
|
return highlighter.codeToHtml(code, {
|
|
183
253
|
lang: mappedLanguage,
|
|
184
|
-
theme:
|
|
254
|
+
theme: themeName,
|
|
185
255
|
transformers: [transformerColorizedBrackets()],
|
|
186
256
|
colorReplacements: THEME_MAP_COLOR_REPLACEMENTS[theme].colorReplacements
|
|
187
257
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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:
|
|
2486
|
+
dataweave: createDataweaveGrammar,
|
|
2487
2487
|
ampscript: ampscriptGrammar,
|
|
2488
|
-
agentscript:
|
|
2488
|
+
agentscript: createAgentscriptGrammar
|
|
2489
2489
|
};
|
|
2490
2490
|
}
|
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
import type { HighlighterCore } from "shiki";
|
|
2
|
-
import
|
|
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,19 +36,45 @@ 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
|
-
*
|
|
15
|
-
*
|
|
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(
|
|
63
|
+
return initializeHighlighter(
|
|
64
|
+
shikiState,
|
|
65
|
+
{ createHighlighterCore },
|
|
66
|
+
createJavaScriptRegexEngine(),
|
|
67
|
+
ALL_LANGUAGES,
|
|
68
|
+
ALL_THEMES
|
|
69
|
+
);
|
|
22
70
|
}
|
|
23
71
|
|
|
72
|
+
// Eagerly kick off initialization at module import time so Shiki is ready
|
|
73
|
+
// before the first code block renders.
|
|
74
|
+
initializeShiki().catch((err) => {
|
|
75
|
+
console.error("Shiki pre-warming failed:", err);
|
|
76
|
+
});
|
|
77
|
+
|
|
24
78
|
export async function highlightCode(
|
|
25
79
|
code: string,
|
|
26
80
|
language: string,
|
package/LICENSE
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2020, Salesforce.com, Inc.
|
|
2
|
-
All rights reserved.
|
|
3
|
-
|
|
4
|
-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
5
|
-
|
|
6
|
-
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
-
|
|
8
|
-
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
9
|
-
|
|
10
|
-
* Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
11
|
-
|
|
12
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|