@shikijs/core 4.0.2 → 4.1.0
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/dist/index.mjs +31 -42
- package/dist/textmate.mjs +2 -3
- package/dist/types.mjs +2 -3
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -2,10 +2,9 @@ import { ShikiError as ShikiError$1 } from "@shikijs/types";
|
|
|
2
2
|
import { ShikiError, applyColorReplacements, codeToTokensBase as codeToTokensBase$1, codeToTokensWithThemes, codeToTokensWithThemes as codeToTokensWithThemes$1, createShikiInternal, createShikiInternalSync, createShikiPrimitive, createShikiPrimitive as createShikiPrimitive$1, createShikiPrimitiveAsync, createShikiPrimitiveAsync as createShikiPrimitiveAsync$1, getLastGrammarState, getLastGrammarStateFromMap, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, normalizeGetter, normalizeTheme, resolveColorReplacements, setLastGrammarStateToMap, splitLines, splitLines as splitLines$1, toArray, tokenizeWithTheme } from "@shikijs/primitive";
|
|
3
3
|
import { FontStyle } from "@shikijs/vscode-textmate";
|
|
4
4
|
import { toHtml } from "hast-util-to-html";
|
|
5
|
-
|
|
6
|
-
export * from "@shikijs/types"
|
|
7
|
-
|
|
5
|
+
export * from "@shikijs/types";
|
|
8
6
|
//#region src/utils/hast.ts
|
|
7
|
+
const RE_WHITESPACE = /\s+/g;
|
|
9
8
|
/**
|
|
10
9
|
* Utility to append class to a hast node
|
|
11
10
|
*
|
|
@@ -15,15 +14,18 @@ function addClassToHast(node, className) {
|
|
|
15
14
|
if (!className) return node;
|
|
16
15
|
node.properties ||= {};
|
|
17
16
|
node.properties.class ||= [];
|
|
18
|
-
if (typeof node.properties.class === "string") node.properties.class = node.properties.class.split(
|
|
17
|
+
if (typeof node.properties.class === "string") node.properties.class = node.properties.class.split(RE_WHITESPACE);
|
|
19
18
|
if (!Array.isArray(node.properties.class)) node.properties.class = [];
|
|
20
|
-
const targets = Array.isArray(className) ? className : className.split(
|
|
19
|
+
const targets = Array.isArray(className) ? className : className.split(RE_WHITESPACE);
|
|
21
20
|
for (const c of targets) if (c && !node.properties.class.includes(c)) node.properties.class.push(c);
|
|
22
21
|
return node;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
23
|
//#endregion
|
|
26
24
|
//#region src/utils/strings.ts
|
|
25
|
+
const RE_LANG_ATTR = /:?lang=["']([^"']+)["']/g;
|
|
26
|
+
const RE_CODE_FENCE = /(?:```|~~~)([\w-]+)/g;
|
|
27
|
+
const RE_LATEX_BEGIN = /\\begin\{([\w-]+)\}/g;
|
|
28
|
+
const RE_SCRIPT_LANG = /<script\s+(?:type|lang)=["']([^"']+)["']/gi;
|
|
27
29
|
/**
|
|
28
30
|
* Creates a converter between index and position in a code block.
|
|
29
31
|
*
|
|
@@ -34,7 +36,7 @@ function createPositionConverter(code) {
|
|
|
34
36
|
function indexToPos(index) {
|
|
35
37
|
if (index === code.length) return {
|
|
36
38
|
line: lines.length - 1,
|
|
37
|
-
character: lines
|
|
39
|
+
character: lines.at(-1).length
|
|
38
40
|
};
|
|
39
41
|
let character = index;
|
|
40
42
|
let line = 0;
|
|
@@ -81,33 +83,28 @@ function createPositionConverter(code) {
|
|
|
81
83
|
*/
|
|
82
84
|
function guessEmbeddedLanguages(code, _lang, highlighter) {
|
|
83
85
|
const langs = /* @__PURE__ */ new Set();
|
|
84
|
-
for (const match of code.matchAll(
|
|
86
|
+
for (const match of code.matchAll(RE_LANG_ATTR)) {
|
|
85
87
|
const lang = match[1].toLowerCase().trim();
|
|
86
88
|
if (lang) langs.add(lang);
|
|
87
89
|
}
|
|
88
|
-
for (const match of code.matchAll(
|
|
90
|
+
for (const match of code.matchAll(RE_CODE_FENCE)) {
|
|
89
91
|
const lang = match[1].toLowerCase().trim();
|
|
90
92
|
if (lang) langs.add(lang);
|
|
91
93
|
}
|
|
92
|
-
for (const match of code.matchAll(
|
|
94
|
+
for (const match of code.matchAll(RE_LATEX_BEGIN)) {
|
|
93
95
|
const lang = match[1].toLowerCase().trim();
|
|
94
96
|
if (lang) langs.add(lang);
|
|
95
97
|
}
|
|
96
|
-
for (const match of code.matchAll(
|
|
98
|
+
for (const match of code.matchAll(RE_SCRIPT_LANG)) {
|
|
97
99
|
const fullType = match[1].toLowerCase().trim();
|
|
98
100
|
const lang = fullType.includes("/") ? fullType.split("/").pop() : fullType;
|
|
99
101
|
if (lang) langs.add(lang);
|
|
100
102
|
}
|
|
101
|
-
if (!highlighter) return
|
|
103
|
+
if (!highlighter) return [...langs];
|
|
102
104
|
const bundle = highlighter.getBundledLanguages();
|
|
103
|
-
return
|
|
105
|
+
return [...langs].filter((l) => l && bundle[l]);
|
|
104
106
|
}
|
|
105
|
-
|
|
106
|
-
//#endregion
|
|
107
|
-
//#region src/utils/constants.ts
|
|
108
|
-
const DEFAULT_COLOR_LIGHT_DARK = "light-dark()";
|
|
109
107
|
const COLOR_KEYS = ["color", "background-color"];
|
|
110
|
-
|
|
111
108
|
//#endregion
|
|
112
109
|
//#region src/utils/tokens.ts
|
|
113
110
|
/**
|
|
@@ -137,7 +134,7 @@ function splitToken(token, offsets) {
|
|
|
137
134
|
* Split 2D tokens array by given breakpoints.
|
|
138
135
|
*/
|
|
139
136
|
function splitTokens(tokens, breakpoints) {
|
|
140
|
-
const sorted =
|
|
137
|
+
const sorted = [...breakpoints instanceof Set ? breakpoints : new Set(breakpoints)].sort((a, b) => a - b);
|
|
141
138
|
if (!sorted.length) return tokens;
|
|
142
139
|
return tokens.map((line) => {
|
|
143
140
|
return line.flatMap((token) => {
|
|
@@ -163,7 +160,7 @@ function flatTokenVariants(merged, variantsOrder, cssVariablePrefix, defaultColo
|
|
|
163
160
|
styles.forEach((cur, idx) => {
|
|
164
161
|
for (const key of styleKeys) {
|
|
165
162
|
const value = cur[key] || "inherit";
|
|
166
|
-
if (idx === 0 && defaultColor && COLOR_KEYS.includes(key)) if (defaultColor ===
|
|
163
|
+
if (idx === 0 && defaultColor && COLOR_KEYS.includes(key)) if (defaultColor === "light-dark()" && styles.length > 1) {
|
|
167
164
|
const lightIndex = variantsOrder.findIndex((t) => t === "light");
|
|
168
165
|
const darkIndex = variantsOrder.findIndex((t) => t === "dark");
|
|
169
166
|
if (lightIndex === -1 || darkIndex === -1) throw new ShikiError$1("When using `defaultColor: \"light-dark()\"`, you must provide both `light` and `dark` themes");
|
|
@@ -194,7 +191,6 @@ function stringifyTokenStyle(token) {
|
|
|
194
191
|
if (typeof token === "string") return token;
|
|
195
192
|
return Object.entries(token).map(([key, value]) => `${key}:${value}`).join(";");
|
|
196
193
|
}
|
|
197
|
-
|
|
198
194
|
//#endregion
|
|
199
195
|
//#region src/transformer-decorations.ts
|
|
200
196
|
/**
|
|
@@ -248,7 +244,7 @@ function transformerDecorations() {
|
|
|
248
244
|
code(codeEl) {
|
|
249
245
|
if (!this.options.decorations?.length) return;
|
|
250
246
|
const ctx = getContext(this);
|
|
251
|
-
const lines =
|
|
247
|
+
const lines = [...codeEl.children].filter((i) => i.type === "element" && i.tagName === "span");
|
|
252
248
|
if (lines.length !== ctx.converter.lines.length) throw new ShikiError$1(`Number of lines in code element (${lines.length}) does not match the number of lines in the source (${ctx.converter.lines.length}). Failed to apply decorations.`);
|
|
253
249
|
function applyLineSection(line, start, end, decoration) {
|
|
254
250
|
const lineEl = lines[line];
|
|
@@ -335,7 +331,6 @@ function stringify(el) {
|
|
|
335
331
|
if (el.type === "element") return el.children.map(stringify).join("");
|
|
336
332
|
return "";
|
|
337
333
|
}
|
|
338
|
-
|
|
339
334
|
//#endregion
|
|
340
335
|
//#region src/highlight/_get-transformers.ts
|
|
341
336
|
const builtInTransformers = [/* @__PURE__ */ transformerDecorations()];
|
|
@@ -367,7 +362,6 @@ function sortTransformersByEnforcement(transformers) {
|
|
|
367
362
|
normal
|
|
368
363
|
};
|
|
369
364
|
}
|
|
370
|
-
|
|
371
365
|
//#endregion
|
|
372
366
|
//#region ../../node_modules/.pnpm/ansi-sequence-parser@1.1.3/node_modules/ansi-sequence-parser/dist/index.js
|
|
373
367
|
var namedColors = [
|
|
@@ -603,9 +597,10 @@ function createColorPalette(namedColorsMap = defaultNamedColorsMap) {
|
|
|
603
597
|
}
|
|
604
598
|
return { value };
|
|
605
599
|
}
|
|
606
|
-
|
|
607
600
|
//#endregion
|
|
608
601
|
//#region src/highlight/code-to-tokens-ansi.ts
|
|
602
|
+
const RE_HEX_COLOR = /#([0-9a-f]{3,8})/i;
|
|
603
|
+
const RE_CSS_VAR_ANSI = /var\((--[\w-]+-ansi-[\w-]+)\)/;
|
|
609
604
|
/**
|
|
610
605
|
* Default ANSI palette (VSCode compatible fallbacks)
|
|
611
606
|
* Used when the theme does not define terminal.ansi* colors.
|
|
@@ -667,7 +662,7 @@ function tokenizeAnsiWithTheme(theme, fileContents, options) {
|
|
|
667
662
|
* Adds 50% alpha to a hex color string or the "-dim" postfix to a CSS variable
|
|
668
663
|
*/
|
|
669
664
|
function dimColor(color) {
|
|
670
|
-
const hexMatch = color.match(
|
|
665
|
+
const hexMatch = color.match(RE_HEX_COLOR);
|
|
671
666
|
if (hexMatch) {
|
|
672
667
|
const hex = hexMatch[1];
|
|
673
668
|
if (hex.length === 8) {
|
|
@@ -687,11 +682,10 @@ function dimColor(color) {
|
|
|
687
682
|
return `#${r}${r}${g}${g}${b}${b}80`;
|
|
688
683
|
}
|
|
689
684
|
}
|
|
690
|
-
const cssVarMatch = color.match(
|
|
685
|
+
const cssVarMatch = color.match(RE_CSS_VAR_ANSI);
|
|
691
686
|
if (cssVarMatch) return `var(${cssVarMatch[1]}-dim)`;
|
|
692
687
|
return color;
|
|
693
688
|
}
|
|
694
|
-
|
|
695
689
|
//#endregion
|
|
696
690
|
//#region src/highlight/code-to-tokens-base.ts
|
|
697
691
|
/**
|
|
@@ -707,7 +701,6 @@ function codeToTokensBase(primitive, code, options = {}) {
|
|
|
707
701
|
}
|
|
708
702
|
return codeToTokensBase$1(primitive, code, options);
|
|
709
703
|
}
|
|
710
|
-
|
|
711
704
|
//#endregion
|
|
712
705
|
//#region src/highlight/code-to-tokens.ts
|
|
713
706
|
/**
|
|
@@ -731,7 +724,7 @@ function codeToTokens(primitive, code, options) {
|
|
|
731
724
|
if (themes.length === 0) throw new ShikiError$1("`themes` option must not be empty");
|
|
732
725
|
const themeTokens = codeToTokensWithThemes$1(primitive, code, options, codeToTokensBase);
|
|
733
726
|
grammarState = getLastGrammarStateFromMap(themeTokens);
|
|
734
|
-
if (defaultColor &&
|
|
727
|
+
if (defaultColor && "light-dark()" !== defaultColor && !themes.some((t) => t.color === defaultColor)) throw new ShikiError$1(`\`themes\` option must contain the defaultColor key \`${defaultColor}\``);
|
|
735
728
|
const themeRegs = themes.map((t) => primitive.getTheme(t.theme));
|
|
736
729
|
const themesOrder = themes.map((t) => t.color);
|
|
737
730
|
tokens = themeTokens.map((line) => line.map((token) => flatTokenVariants(token, themesOrder, cssVariablePrefix, defaultColor, colorsRendering)));
|
|
@@ -764,7 +757,7 @@ function mapThemeColors(themes, themeRegs, themeColorReplacements, cssVariablePr
|
|
|
764
757
|
const value = applyColorReplacements(themeRegs[idx][property], themeColorReplacements[idx]) || "inherit";
|
|
765
758
|
const cssVar = `${cssVariablePrefix + t.color}${property === "bg" ? "-bg" : ""}:${value}`;
|
|
766
759
|
if (idx === 0 && defaultColor) {
|
|
767
|
-
if (defaultColor ===
|
|
760
|
+
if (defaultColor === "light-dark()" && themes.length > 1) {
|
|
768
761
|
const lightIndex = themes.findIndex((t) => t.color === "light");
|
|
769
762
|
const darkIndex = themes.findIndex((t) => t.color === "dark");
|
|
770
763
|
if (lightIndex === -1 || darkIndex === -1) throw new ShikiError$1("When using `defaultColor: \"light-dark()\"`, you must provide both `light` and `dark` themes");
|
|
@@ -776,9 +769,10 @@ function mapThemeColors(themes, themeRegs, themeColorReplacements, cssVariablePr
|
|
|
776
769
|
return null;
|
|
777
770
|
}).filter((i) => !!i).join(";");
|
|
778
771
|
}
|
|
779
|
-
|
|
780
772
|
//#endregion
|
|
781
773
|
//#region src/highlight/code-to-hast.ts
|
|
774
|
+
const RE_WHITESPACE_ONLY = /^\s+$/;
|
|
775
|
+
const RE_LEADING_TRAILING_WHITESPACE = /^(\s*)(.*?)(\s*)$/;
|
|
782
776
|
function codeToHast(primitive, code, options, transformerContext = {
|
|
783
777
|
meta: {},
|
|
784
778
|
options,
|
|
@@ -957,7 +951,7 @@ function mergeWhitespaceTokens(tokens) {
|
|
|
957
951
|
let firstOffset;
|
|
958
952
|
line.forEach((token, idx) => {
|
|
959
953
|
const couldMerge = !(token.fontStyle && (token.fontStyle & FontStyle.Underline || token.fontStyle & FontStyle.Strikethrough));
|
|
960
|
-
if (couldMerge && token.content
|
|
954
|
+
if (couldMerge && RE_WHITESPACE_ONLY.test(token.content) && line[idx + 1]) {
|
|
961
955
|
if (firstOffset === void 0) firstOffset = token.offset;
|
|
962
956
|
carryOnContent += token.content;
|
|
963
957
|
} else if (carryOnContent) {
|
|
@@ -980,8 +974,8 @@ function mergeWhitespaceTokens(tokens) {
|
|
|
980
974
|
function splitWhitespaceTokens(tokens) {
|
|
981
975
|
return tokens.map((line) => {
|
|
982
976
|
return line.flatMap((token) => {
|
|
983
|
-
if (token.content
|
|
984
|
-
const match = token.content.match(
|
|
977
|
+
if (RE_WHITESPACE_ONLY.test(token.content)) return token;
|
|
978
|
+
const match = token.content.match(RE_LEADING_TRAILING_WHITESPACE);
|
|
985
979
|
if (!match) return token;
|
|
986
980
|
const [, leading, content, trailing] = match;
|
|
987
981
|
if (!leading && !trailing) return token;
|
|
@@ -1010,7 +1004,7 @@ function mergeAdjacentStyledTokens(tokens) {
|
|
|
1010
1004
|
newLine.push({ ...token });
|
|
1011
1005
|
continue;
|
|
1012
1006
|
}
|
|
1013
|
-
const prevToken = newLine
|
|
1007
|
+
const prevToken = newLine.at(-1);
|
|
1014
1008
|
const prevStyle = stringifyTokenStyle(prevToken.htmlStyle || getTokenStyleObject(prevToken));
|
|
1015
1009
|
const currentStyle = stringifyTokenStyle(token.htmlStyle || getTokenStyleObject(token));
|
|
1016
1010
|
const isPrevDecorated = prevToken.fontStyle && (prevToken.fontStyle & FontStyle.Underline || prevToken.fontStyle & FontStyle.Strikethrough);
|
|
@@ -1021,7 +1015,6 @@ function mergeAdjacentStyledTokens(tokens) {
|
|
|
1021
1015
|
return newLine;
|
|
1022
1016
|
});
|
|
1023
1017
|
}
|
|
1024
|
-
|
|
1025
1018
|
//#endregion
|
|
1026
1019
|
//#region src/highlight/code-to-html.ts
|
|
1027
1020
|
const hastToHtml = toHtml;
|
|
@@ -1039,7 +1032,6 @@ function codeToHtml(primitive, code, options) {
|
|
|
1039
1032
|
for (const transformer of getTransformers(options)) result = transformer.postprocess?.call(context, result, options) || result;
|
|
1040
1033
|
return result;
|
|
1041
1034
|
}
|
|
1042
|
-
|
|
1043
1035
|
//#endregion
|
|
1044
1036
|
//#region src/constructors/highlighter.ts
|
|
1045
1037
|
/**
|
|
@@ -1105,7 +1097,6 @@ function makeSingletonHighlighterCore(createHighlighter) {
|
|
|
1105
1097
|
return getSingletonHighlighterCore;
|
|
1106
1098
|
}
|
|
1107
1099
|
const getSingletonHighlighterCore = /* @__PURE__ */ makeSingletonHighlighterCore(createHighlighterCore);
|
|
1108
|
-
|
|
1109
1100
|
//#endregion
|
|
1110
1101
|
//#region src/constructors/bundle-factory.ts
|
|
1111
1102
|
function createBundledHighlighter(options) {
|
|
@@ -1216,7 +1207,6 @@ function createSingletonShorthands(createHighlighter, config) {
|
|
|
1216
1207
|
}
|
|
1217
1208
|
};
|
|
1218
1209
|
}
|
|
1219
|
-
|
|
1220
1210
|
//#endregion
|
|
1221
1211
|
//#region src/theme-css-variables.ts
|
|
1222
1212
|
/**
|
|
@@ -1412,6 +1402,5 @@ function createCssVariablesTheme(options = {}) {
|
|
|
1412
1402
|
});
|
|
1413
1403
|
return theme;
|
|
1414
1404
|
}
|
|
1415
|
-
|
|
1416
1405
|
//#endregion
|
|
1417
|
-
export { ShikiError, addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createBundledHighlighter, createCssVariablesTheme, createHighlighterCore, createHighlighterCoreSync, createPositionConverter, createShikiInternal, createShikiInternalSync, createShikiPrimitive, createShikiPrimitiveAsync, createSingletonShorthands, flatTokenVariants, getLastGrammarState, getSingletonHighlighterCore, getTokenStyleObject, guessEmbeddedLanguages, hastToHtml, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeGetter, normalizeTheme, resolveColorReplacements, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations };
|
|
1406
|
+
export { ShikiError, addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createBundledHighlighter, createCssVariablesTheme, createHighlighterCore, createHighlighterCoreSync, createPositionConverter, createShikiInternal, createShikiInternalSync, createShikiPrimitive, createShikiPrimitiveAsync, createSingletonShorthands, flatTokenVariants, getLastGrammarState, getSingletonHighlighterCore, getTokenStyleObject, guessEmbeddedLanguages, hastToHtml, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeGetter, normalizeTheme, resolveColorReplacements, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations };
|
package/dist/textmate.mjs
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export * from "@shikijs/vscode-textmate"
|
|
2
|
-
|
|
3
|
-
export { };
|
|
1
|
+
export * from "@shikijs/vscode-textmate";
|
|
2
|
+
export {};
|
package/dist/types.mjs
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export * from "@shikijs/types"
|
|
2
|
-
|
|
3
|
-
export { };
|
|
1
|
+
export * from "@shikijs/types";
|
|
2
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shikijs/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0
|
|
4
|
+
"version": "4.1.0",
|
|
5
5
|
"description": "Core of Shiki",
|
|
6
6
|
"author": "Pine Wu <octref@gmail.com>; Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"@shikijs/vscode-textmate": "^10.0.2",
|
|
50
50
|
"@types/hast": "^3.0.4",
|
|
51
51
|
"hast-util-to-html": "^9.0.5",
|
|
52
|
-
"@shikijs/primitive": "4.0
|
|
53
|
-
"@shikijs/types": "4.0
|
|
52
|
+
"@shikijs/primitive": "4.1.0",
|
|
53
|
+
"@shikijs/types": "4.1.0"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsdown",
|