full site update

This commit is contained in:
2025-07-24 18:46:24 +02:00
parent bfe2b90d8d
commit 37a6e0ab31
6912 changed files with 540482 additions and 361712 deletions

View File

@@ -1,41 +1,30 @@
import { ShikiError as ShikiError$1 } from '@shikijs/types';
export * from '@shikijs/types';
import { createOnigurumaEngine as createOnigurumaEngine$1, loadWasm as loadWasm$1, getDefaultWasmLoader } from '@shikijs/engine-oniguruma';
import { w as warnDeprecated } from './shared/core.Bn_XU0Iv.mjs';
export { e as enableDeprecationWarnings } from './shared/core.Bn_XU0Iv.mjs';
import { FontStyle, INITIAL, EncodedTokenMetadata, Registry as Registry$1, Theme } from '@shikijs/vscode-textmate';
export { FontStyle, EncodedTokenMetadata as StackElementMetadata } from '@shikijs/vscode-textmate';
import { toHtml } from 'hast-util-to-html';
export { toHtml as hastToHtml } from 'hast-util-to-html';
import { createJavaScriptRegexEngine as createJavaScriptRegexEngine$1, defaultJavaScriptRegexConstructor as defaultJavaScriptRegexConstructor$1 } from '@shikijs/engine-javascript';
function createOnigurumaEngine(options) {
warnDeprecated("import `createOnigurumaEngine` from `@shikijs/engine-oniguruma` or `shiki/engine/oniguruma` instead");
return createOnigurumaEngine$1(options);
function resolveColorReplacements(theme, options) {
const replacements = typeof theme === "string" ? {} : { ...theme.colorReplacements };
const themeName = typeof theme === "string" ? theme : theme.name;
for (const [key, value] of Object.entries(options?.colorReplacements || {})) {
if (typeof value === "string")
replacements[key] = value;
else if (key === themeName)
Object.assign(replacements, value);
}
return replacements;
}
function createWasmOnigEngine(options) {
warnDeprecated("import `createOnigurumaEngine` from `@shikijs/engine-oniguruma` or `shiki/engine/oniguruma` instead");
return createOnigurumaEngine$1(options);
}
function loadWasm(options) {
warnDeprecated("import `loadWasm` from `@shikijs/engine-oniguruma` or `shiki/engine/oniguruma` instead");
return loadWasm$1(options);
function applyColorReplacements(color, replacements) {
if (!color)
return color;
return replacements?.[color?.toLowerCase()] || color;
}
function toArray(x) {
return Array.isArray(x) ? x : [x];
}
function splitLines(code, preserveEnding = false) {
const parts = code.split(/(\r?\n)/g);
let index = 0;
const lines = [];
for (let i = 0; i < parts.length; i += 2) {
const line = preserveEnding ? parts[i] + (parts[i + 1] || "") : parts[i];
lines.push([line, index]);
index += parts[i].length;
index += parts[i + 1]?.length || 0;
}
return lines;
async function normalizeGetter(p) {
return Promise.resolve(typeof p === "function" ? p() : p).then((r) => r.default || r);
}
function isPlainLang(lang) {
return !lang || ["plaintext", "txt", "text", "plain"].includes(lang);
@@ -49,6 +38,7 @@ function isNoneTheme(theme) {
function isSpecialTheme(theme) {
return isNoneTheme(theme);
}
function addClassToHast(node, className) {
if (!className)
return node;
@@ -65,6 +55,71 @@ function addClassToHast(node, className) {
}
return node;
}
function splitLines(code, preserveEnding = false) {
const parts = code.split(/(\r?\n)/g);
let index = 0;
const lines = [];
for (let i = 0; i < parts.length; i += 2) {
const line = preserveEnding ? parts[i] + (parts[i + 1] || "") : parts[i];
lines.push([line, index]);
index += parts[i].length;
index += parts[i + 1]?.length || 0;
}
return lines;
}
function createPositionConverter(code) {
const lines = splitLines(code, true).map(([line]) => line);
function indexToPos(index) {
if (index === code.length) {
return {
line: lines.length - 1,
character: lines[lines.length - 1].length
};
}
let character = index;
let line = 0;
for (const lineText of lines) {
if (character < lineText.length)
break;
character -= lineText.length;
line++;
}
return { line, character };
}
function posToIndex(line, character) {
let index = 0;
for (let i = 0; i < line; i++)
index += lines[i].length;
index += character;
return index;
}
return {
lines,
indexToPos,
posToIndex
};
}
function guessEmbeddedLanguages(code, _lang, highlighter) {
const langs = /* @__PURE__ */ new Set();
for (const match of code.matchAll(/lang=["']([\w-]+)["']/g)) {
langs.add(match[1]);
}
for (const match of code.matchAll(/(?:```|~~~)([\w-]+)/g)) {
langs.add(match[1]);
}
for (const match of code.matchAll(/\\begin\{([\w-]+)\}/g)) {
langs.add(match[1]);
}
if (!highlighter)
return Array.from(langs);
const bundle = highlighter.getBundledLanguages();
return Array.from(langs).filter((l) => l && bundle[l]);
}
const DEFAULT_COLOR_LIGHT_DARK = "light-dark()";
const COLOR_KEYS = ["color", "background-color"];
function splitToken(token, offsets) {
let lastOffset = 0;
const tokens = [];
@@ -100,24 +155,44 @@ function splitTokens(tokens, breakpoints) {
});
});
}
async function normalizeGetter(p) {
return Promise.resolve(typeof p === "function" ? p() : p).then((r) => r.default || r);
}
function resolveColorReplacements(theme, options) {
const replacements = typeof theme === "string" ? {} : { ...theme.colorReplacements };
const themeName = typeof theme === "string" ? theme : theme.name;
for (const [key, value] of Object.entries(options?.colorReplacements || {})) {
if (typeof value === "string")
replacements[key] = value;
else if (key === themeName)
Object.assign(replacements, value);
}
return replacements;
}
function applyColorReplacements(color, replacements) {
if (!color)
return color;
return replacements?.[color?.toLowerCase()] || color;
function flatTokenVariants(merged, variantsOrder, cssVariablePrefix, defaultColor, colorsRendering = "css-vars") {
const token = {
content: merged.content,
explanation: merged.explanation,
offset: merged.offset
};
const styles = variantsOrder.map((t) => getTokenStyleObject(merged.variants[t]));
const styleKeys = new Set(styles.flatMap((t) => Object.keys(t)));
const mergedStyles = {};
const varKey = (idx, key) => {
const keyName = key === "color" ? "" : key === "background-color" ? "-bg" : `-${key}`;
return cssVariablePrefix + variantsOrder[idx] + (key === "color" ? "" : keyName);
};
styles.forEach((cur, idx) => {
for (const key of styleKeys) {
const value = cur[key] || "inherit";
if (idx === 0 && defaultColor && COLOR_KEYS.includes(key)) {
if (defaultColor === DEFAULT_COLOR_LIGHT_DARK && styles.length > 1) {
const lightIndex = variantsOrder.findIndex((t) => t === "light");
const darkIndex = variantsOrder.findIndex((t) => t === "dark");
if (lightIndex === -1 || darkIndex === -1)
throw new ShikiError$1('When using `defaultColor: "light-dark()"`, you must provide both `light` and `dark` themes');
const lightValue = styles[lightIndex][key] || "inherit";
const darkValue = styles[darkIndex][key] || "inherit";
mergedStyles[key] = `light-dark(${lightValue}, ${darkValue})`;
if (colorsRendering === "css-vars")
mergedStyles[varKey(idx, key)] = value;
} else {
mergedStyles[key] = value;
}
} else {
if (colorsRendering === "css-vars")
mergedStyles[varKey(idx, key)] = value;
}
}
});
token.htmlStyle = mergedStyles;
return token;
}
function getTokenStyleObject(token) {
const styles = {};
@@ -130,8 +205,13 @@ function getTokenStyleObject(token) {
styles["font-style"] = "italic";
if (token.fontStyle & FontStyle.Bold)
styles["font-weight"] = "bold";
const decorations = [];
if (token.fontStyle & FontStyle.Underline)
styles["text-decoration"] = "underline";
decorations.push("underline");
if (token.fontStyle & FontStyle.Strikethrough)
decorations.push("line-through");
if (decorations.length)
styles["text-decoration"] = decorations.join(" ");
}
return styles;
}
@@ -140,45 +220,6 @@ function stringifyTokenStyle(token) {
return token;
return Object.entries(token).map(([key, value]) => `${key}:${value}`).join(";");
}
function createPositionConverter(code) {
const lines = splitLines(code, true).map(([line]) => line);
function indexToPos(index) {
if (index === code.length) {
return {
line: lines.length - 1,
character: lines[lines.length - 1].length
};
}
let character = index;
let line = 0;
for (const lineText of lines) {
if (character < lineText.length)
break;
character -= lineText.length;
line++;
}
return { line, character };
}
function posToIndex(line, character) {
let index = 0;
for (let i = 0; i < line; i++)
index += lines[i].length;
index += character;
return index;
}
return {
lines,
indexToPos,
posToIndex
};
}
class ShikiError extends Error {
constructor(message) {
super(message);
this.name = "ShikiError";
}
}
const _grammarStateMap = /* @__PURE__ */ new WeakMap();
function setLastGrammarStateToMap(keys, state) {
@@ -229,13 +270,6 @@ class GrammarState {
getInternalStack(theme = this.theme) {
return this._stacks[theme];
}
/**
* @deprecated use `getScopes` instead
*/
get scopes() {
warnDeprecated("GrammarState.scopes is deprecated, use GrammarState.getScopes() instead");
return getScopes(this._stacks[this.theme]);
}
getScopes(theme = this.theme) {
return getScopes(this._stacks[theme]);
}
@@ -244,7 +278,7 @@ class GrammarState {
lang: this.lang,
theme: this.theme,
themes: this.themes,
scopes: this.scopes
scopes: this.getScopes()
};
}
}
@@ -266,7 +300,7 @@ function getScopes(stack) {
}
function getGrammarStack(state, theme) {
if (!(state instanceof GrammarState))
throw new ShikiError("Invalid grammar state");
throw new ShikiError$1("Invalid grammar state");
return state.getInternalStack(theme);
}
@@ -277,17 +311,17 @@ function transformerDecorations() {
let normalizePosition = function(p) {
if (typeof p === "number") {
if (p < 0 || p > shiki.source.length)
throw new ShikiError(`Invalid decoration offset: ${p}. Code length: ${shiki.source.length}`);
throw new ShikiError$1(`Invalid decoration offset: ${p}. Code length: ${shiki.source.length}`);
return {
...converter.indexToPos(p),
offset: p
};
} else {
const line = converter.lines[p.line];
if (line === undefined)
throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Lines length: ${converter.lines.length}`);
if (line === void 0)
throw new ShikiError$1(`Invalid decoration position ${JSON.stringify(p)}. Lines length: ${converter.lines.length}`);
if (p.character < 0 || p.character > line.length)
throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Line ${p.line} length: ${line.length}`);
throw new ShikiError$1(`Invalid decoration position ${JSON.stringify(p)}. Line ${p.line} length: ${line.length}`);
return {
...p,
offset: converter.posToIndex(p.line, p.character)
@@ -325,7 +359,7 @@ function transformerDecorations() {
const ctx = getContext(this);
const lines = Array.from(codeEl.children).filter((i) => i.type === "element" && i.tagName === "span");
if (lines.length !== ctx.converter.lines.length)
throw new ShikiError(`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.`);
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.`);
function applyLineSection(line, start, end, decoration) {
const lineEl = lines[line];
let text = "";
@@ -347,9 +381,9 @@ function transformerDecorations() {
}
}
if (startIndex === -1)
throw new ShikiError(`Failed to find start index for decoration ${JSON.stringify(decoration.start)}`);
throw new ShikiError$1(`Failed to find start index for decoration ${JSON.stringify(decoration.start)}`);
if (endIndex === -1)
throw new ShikiError(`Failed to find end index for decoration ${JSON.stringify(decoration.end)}`);
throw new ShikiError$1(`Failed to find end index for decoration ${JSON.stringify(decoration.end)}`);
const children = lineEl.children.slice(startIndex, endIndex);
if (!decoration.alwaysWrap && children.length === lineEl.children.length) {
applyDecoration(lineEl, decoration, "line");
@@ -384,7 +418,7 @@ function transformerDecorations() {
return el;
}
const lineApplies = [];
const sorted = ctx.decorations.sort((a, b) => b.start.offset - a.start.offset);
const sorted = ctx.decorations.sort((a, b) => b.start.offset - a.start.offset || a.end.offset - b.end.offset);
for (const decoration of sorted) {
const { start, end } = decoration;
if (start.line === end.line) {
@@ -404,19 +438,23 @@ function verifyIntersections(items) {
for (let i = 0; i < items.length; i++) {
const foo = items[i];
if (foo.start.offset > foo.end.offset)
throw new ShikiError(`Invalid decoration range: ${JSON.stringify(foo.start)} - ${JSON.stringify(foo.end)}`);
throw new ShikiError$1(`Invalid decoration range: ${JSON.stringify(foo.start)} - ${JSON.stringify(foo.end)}`);
for (let j = i + 1; j < items.length; j++) {
const bar = items[j];
const isFooHasBarStart = foo.start.offset < bar.start.offset && bar.start.offset < foo.end.offset;
const isFooHasBarEnd = foo.start.offset < bar.end.offset && bar.end.offset < foo.end.offset;
const isBarHasFooStart = bar.start.offset < foo.start.offset && foo.start.offset < bar.end.offset;
const isBarHasFooEnd = bar.start.offset < foo.end.offset && foo.end.offset < bar.end.offset;
const isFooHasBarStart = foo.start.offset <= bar.start.offset && bar.start.offset < foo.end.offset;
const isFooHasBarEnd = foo.start.offset < bar.end.offset && bar.end.offset <= foo.end.offset;
const isBarHasFooStart = bar.start.offset <= foo.start.offset && foo.start.offset < bar.end.offset;
const isBarHasFooEnd = bar.start.offset < foo.end.offset && foo.end.offset <= bar.end.offset;
if (isFooHasBarStart || isFooHasBarEnd || isBarHasFooStart || isBarHasFooEnd) {
if (isFooHasBarEnd && isFooHasBarEnd)
if (isFooHasBarStart && isFooHasBarEnd)
continue;
if (isBarHasFooStart && isBarHasFooEnd)
continue;
throw new ShikiError(`Decorations ${JSON.stringify(foo.start)} and ${JSON.stringify(bar.start)} intersect.`);
if (isBarHasFooStart && foo.start.offset === foo.end.offset)
continue;
if (isFooHasBarEnd && bar.start.offset === bar.end.offset)
continue;
throw new ShikiError$1(`Decorations ${JSON.stringify(foo.start)} and ${JSON.stringify(bar.start)} intersect.`);
}
}
}
@@ -466,52 +504,52 @@ var decorations = {
3: "italic",
4: "underline",
7: "reverse",
8: "hidden",
9: "strikethrough"
};
// src/parser.ts
function findSequence(value, position) {
const nextEscape = value.indexOf("\x1B[", position);
const nextEscape = value.indexOf("\x1B", position);
if (nextEscape !== -1) {
const nextClose = value.indexOf("m", nextEscape);
return {
sequence: value.substring(nextEscape + 2, nextClose).split(";"),
startPosition: nextEscape,
position: nextClose + 1
};
if (value[nextEscape + 1] === "[") {
const nextClose = value.indexOf("m", nextEscape);
if (nextClose !== -1) {
return {
sequence: value.substring(nextEscape + 2, nextClose).split(";"),
startPosition: nextEscape,
position: nextClose + 1
};
}
}
}
return {
position: value.length
};
}
function parseColor(sequence, index) {
let offset = 1;
const colorMode = sequence[index + offset++];
let color;
function parseColor(sequence) {
const colorMode = sequence.shift();
if (colorMode === "2") {
const rgb = [
sequence[index + offset++],
sequence[index + offset++],
sequence[index + offset]
].map((x) => Number.parseInt(x));
if (rgb.length === 3 && !rgb.some((x) => Number.isNaN(x))) {
color = {
type: "rgb",
rgb
};
}
const rgb = sequence.splice(0, 3).map((x) => Number.parseInt(x));
if (rgb.length !== 3 || rgb.some((x) => Number.isNaN(x)))
return;
return {
type: "rgb",
rgb
};
} else if (colorMode === "5") {
const colorIndex = Number.parseInt(sequence[index + offset]);
if (!Number.isNaN(colorIndex)) {
color = { type: "table", index: Number(colorIndex) };
const index = sequence.shift();
if (index) {
return { type: "table", index: Number(index) };
}
}
return [offset, color];
}
function parseSequence(sequence) {
const commands = [];
for (let i = 0; i < sequence.length; i++) {
const code = sequence[i];
while (sequence.length > 0) {
const code = sequence.shift();
if (!code)
continue;
const codeInt = Number.parseInt(code);
if (Number.isNaN(codeInt))
continue;
@@ -532,6 +570,12 @@ function parseSequence(sequence) {
type: "resetDecoration",
value: decoration
});
if (decoration === "dim") {
commands.push({
type: "resetDecoration",
value: "bold"
});
}
}
} else if (codeInt <= 37) {
commands.push({
@@ -539,14 +583,13 @@ function parseSequence(sequence) {
value: { type: "named", name: namedColors[codeInt - 30] }
});
} else if (codeInt === 38) {
const [offset, color] = parseColor(sequence, i);
const color = parseColor(sequence);
if (color) {
commands.push({
type: "setForegroundColor",
value: color
});
}
i += offset;
} else if (codeInt === 39) {
commands.push({
type: "resetForegroundColor"
@@ -557,18 +600,27 @@ function parseSequence(sequence) {
value: { type: "named", name: namedColors[codeInt - 40] }
});
} else if (codeInt === 48) {
const [offset, color] = parseColor(sequence, i);
const color = parseColor(sequence);
if (color) {
commands.push({
type: "setBackgroundColor",
value: color
});
}
i += offset;
} else if (codeInt === 49) {
commands.push({
type: "resetBackgroundColor"
});
} else if (codeInt === 53) {
commands.push({
type: "setDecoration",
value: "overline"
});
} else if (codeInt === 55) {
commands.push({
type: "resetDecoration",
value: "overline"
});
} else if (codeInt >= 90 && codeInt <= 97) {
commands.push({
type: "setForegroundColor",
@@ -722,7 +774,7 @@ function tokenizeAnsiWithTheme(theme, fileContents, options) {
bgColor = token.foreground ? colorPalette.value(token.foreground) : theme.fg;
} else {
color = token.foreground ? colorPalette.value(token.foreground) : theme.fg;
bgColor = token.background ? colorPalette.value(token.background) : undefined;
bgColor = token.background ? colorPalette.value(token.background) : void 0;
}
color = applyColorReplacements(color, colorReplacements);
bgColor = applyColorReplacements(bgColor, colorReplacements);
@@ -735,6 +787,8 @@ function tokenizeAnsiWithTheme(theme, fileContents, options) {
fontStyle |= FontStyle.Italic;
if (token.decorations.has("underline"))
fontStyle |= FontStyle.Underline;
if (token.decorations.has("strikethrough"))
fontStyle |= FontStyle.Strikethrough;
return {
content: token.value,
offset: line[1],
@@ -830,8 +884,8 @@ function _tokenizeWithTheme(code, grammar, theme, colorMap, options) {
colorMap,
{
...options,
grammarState: undefined,
grammarContextCode: undefined
grammarState: void 0,
grammarContextCode: void 0
}
).stateStack : INITIAL;
let actual = [];
@@ -857,7 +911,7 @@ function _tokenizeWithTheme(code, grammar, theme, colorMap, options) {
let tokensWithScopes;
let tokensWithScopesIndex;
if (options.includeExplanation) {
resultWithScopes = grammar.tokenizeLine(line, stateStack);
resultWithScopes = grammar.tokenizeLine(line, stateStack, tokenizeTimeLimit);
tokensWithScopes = resultWithScopes.tokens;
tokensWithScopesIndex = 0;
}
@@ -1020,7 +1074,7 @@ function codeToTokensWithThemes(internal, code, options) {
const mergedGrammarState = themedTokens[0].state ? new GrammarState(
Object.fromEntries(themedTokens.map((s) => [s.theme, s.state?.getInternalStack(s.theme)])),
themedTokens[0].state.lang
) : undefined;
) : void 0;
if (mergedGrammarState)
setLastGrammarStateToMap(mergedTokens, mergedGrammarState);
return mergedTokens;
@@ -1069,7 +1123,8 @@ function codeToTokens(internal, code, options) {
if ("themes" in options) {
const {
defaultColor = "light",
cssVariablePrefix = "--shiki-"
cssVariablePrefix = "--shiki-",
colorsRendering = "css-vars"
} = options;
const themes = Object.entries(options.themes).filter((i) => i[1]).map((i) => ({ color: i[0], theme: i[1] })).sort((a, b) => a.color === defaultColor ? -1 : b.color === defaultColor ? 1 : 0);
if (themes.length === 0)
@@ -1080,18 +1135,18 @@ function codeToTokens(internal, code, options) {
options
);
grammarState = getLastGrammarStateFromMap(themeTokens);
if (defaultColor && !themes.find((t) => t.color === defaultColor))
if (defaultColor && DEFAULT_COLOR_LIGHT_DARK !== defaultColor && !themes.find((t) => t.color === defaultColor))
throw new ShikiError$1(`\`themes\` option must contain the defaultColor key \`${defaultColor}\``);
const themeRegs = themes.map((t) => internal.getTheme(t.theme));
const themesOrder = themes.map((t) => t.color);
tokens = themeTokens.map((line) => line.map((token) => mergeToken(token, themesOrder, cssVariablePrefix, defaultColor)));
tokens = themeTokens.map((line) => line.map((token) => flatTokenVariants(token, themesOrder, cssVariablePrefix, defaultColor, colorsRendering)));
if (grammarState)
setLastGrammarStateToMap(tokens, grammarState);
const themeColorReplacements = themes.map((t) => resolveColorReplacements(t.theme, options));
fg = themes.map((t, idx) => (idx === 0 && defaultColor ? "" : `${cssVariablePrefix + t.color}:`) + (applyColorReplacements(themeRegs[idx].fg, themeColorReplacements[idx]) || "inherit")).join(";");
bg = themes.map((t, idx) => (idx === 0 && defaultColor ? "" : `${cssVariablePrefix + t.color}-bg:`) + (applyColorReplacements(themeRegs[idx].bg, themeColorReplacements[idx]) || "inherit")).join(";");
fg = mapThemeColors(themes, themeRegs, themeColorReplacements, cssVariablePrefix, defaultColor, "fg", colorsRendering);
bg = mapThemeColors(themes, themeRegs, themeColorReplacements, cssVariablePrefix, defaultColor, "bg", colorsRendering);
themeName = `shiki-themes ${themeRegs.map((t) => t.name).join(" ")}`;
rootStyle = defaultColor ? undefined : [fg, bg].join(";");
rootStyle = defaultColor ? void 0 : [fg, bg].join(";");
} else if ("theme" in options) {
const colorReplacements = resolveColorReplacements(options.theme, options);
tokens = codeToTokensBase(
@@ -1116,29 +1171,27 @@ function codeToTokens(internal, code, options) {
grammarState
};
}
function mergeToken(merged, variantsOrder, cssVariablePrefix, defaultColor) {
const token = {
content: merged.content,
explanation: merged.explanation,
offset: merged.offset
};
const styles = variantsOrder.map((t) => getTokenStyleObject(merged.variants[t]));
const styleKeys = new Set(styles.flatMap((t) => Object.keys(t)));
const mergedStyles = {};
styles.forEach((cur, idx) => {
for (const key of styleKeys) {
const value = cur[key] || "inherit";
if (idx === 0 && defaultColor) {
mergedStyles[key] = value;
} else {
const keyName = key === "color" ? "" : key === "background-color" ? "-bg" : `-${key}`;
const varKey = cssVariablePrefix + variantsOrder[idx] + (key === "color" ? "" : keyName);
mergedStyles[varKey] = value;
function mapThemeColors(themes, themeRegs, themeColorReplacements, cssVariablePrefix, defaultColor, property, colorsRendering) {
return themes.map((t, idx) => {
const value = applyColorReplacements(themeRegs[idx][property], themeColorReplacements[idx]) || "inherit";
const cssVar = `${cssVariablePrefix + t.color}${property === "bg" ? "-bg" : ""}:${value}`;
if (idx === 0 && defaultColor) {
if (defaultColor === DEFAULT_COLOR_LIGHT_DARK && themes.length > 1) {
const lightIndex = themes.findIndex((t2) => t2.color === "light");
const darkIndex = themes.findIndex((t2) => t2.color === "dark");
if (lightIndex === -1 || darkIndex === -1)
throw new ShikiError$1('When using `defaultColor: "light-dark()"`, you must provide both `light` and `dark` themes');
const lightValue = applyColorReplacements(themeRegs[lightIndex][property], themeColorReplacements[lightIndex]) || "inherit";
const darkValue = applyColorReplacements(themeRegs[darkIndex][property], themeColorReplacements[darkIndex]) || "inherit";
return `light-dark(${lightValue}, ${darkValue});${cssVar}`;
}
return value;
}
});
token.htmlStyle = mergedStyles;
return token;
if (colorsRendering === "css-vars") {
return cssVar;
}
return null;
}).filter((i) => !!i).join(";");
}
function codeToHast(internal, code, options, transformerContext = {
@@ -1159,12 +1212,16 @@ function codeToHast(internal, code, options, transformerContext = {
grammarState
} = codeToTokens(internal, input, options);
const {
mergeWhitespaces = true
mergeWhitespaces = true,
mergeSameStyleTokens = false
} = options;
if (mergeWhitespaces === true)
tokens = mergeWhitespaceTokens(tokens);
else if (mergeWhitespaces === "never")
tokens = splitWhitespaceTokens(tokens);
if (mergeSameStyleTokens) {
tokens = mergeAdjacentStyledTokens(tokens);
}
const contextSource = {
...transformerContext,
get source() {
@@ -1270,8 +1327,6 @@ function tokensToHast(tokens, options, transformerContext, grammarState = getLas
},
children: [{ type: "text", value: token.content }]
};
if (typeof token.htmlStyle === "string")
warnDeprecated("`htmlStyle` as a string is deprecated. Use an object instead.");
const style = stringifyTokenStyle(token.htmlStyle || getTokenStyleObject(token));
if (style)
tokenNode.properties.style = style;
@@ -1311,8 +1366,8 @@ function mergeWhitespaceTokens(tokens) {
let carryOnContent = "";
let firstOffset = 0;
line.forEach((token, idx) => {
const isUnderline = token.fontStyle && token.fontStyle & FontStyle.Underline;
const couldMerge = !isUnderline;
const isDecorated = token.fontStyle && (token.fontStyle & FontStyle.Underline || token.fontStyle & FontStyle.Strikethrough);
const couldMerge = !isDecorated;
if (couldMerge && token.content.match(/^\s+$/) && line[idx + 1]) {
if (!firstOffset)
firstOffset = token.offset;
@@ -1376,7 +1431,30 @@ function splitWhitespaceTokens(tokens) {
});
});
}
function mergeAdjacentStyledTokens(tokens) {
return tokens.map((line) => {
const newLine = [];
for (const token of line) {
if (newLine.length === 0) {
newLine.push({ ...token });
continue;
}
const prevToken = newLine[newLine.length - 1];
const prevStyle = stringifyTokenStyle(prevToken.htmlStyle || getTokenStyleObject(prevToken));
const currentStyle = stringifyTokenStyle(token.htmlStyle || getTokenStyleObject(token));
const isPrevDecorated = prevToken.fontStyle && (prevToken.fontStyle & FontStyle.Underline || prevToken.fontStyle & FontStyle.Strikethrough);
const isDecorated = token.fontStyle && (token.fontStyle & FontStyle.Underline || token.fontStyle & FontStyle.Strikethrough);
if (!isPrevDecorated && !isDecorated && prevStyle === currentStyle) {
prevToken.content += token.content;
} else {
newLine.push({ ...token });
}
}
return newLine;
});
}
const hastToHtml = toHtml;
function codeToHtml(internal, code, options) {
const context = {
meta: {},
@@ -1384,7 +1462,7 @@ function codeToHtml(internal, code, options) {
codeToHast: (_code, _options) => codeToHast(internal, _code, _options),
codeToTokens: (_code, _options) => codeToTokens(internal, _code, _options)
};
let result = toHtml(codeToHast(internal, code, options, context));
let result = hastToHtml(codeToHast(internal, code, options, context));
for (const transformer of getTransformers(options))
result = transformer.postprocess?.call(context, result, options) || result;
return result;
@@ -1408,7 +1486,7 @@ function normalizeTheme(rawTheme) {
theme.settings ||= [];
let { bg, fg } = theme;
if (!bg || !fg) {
const globalSetting = theme.settings ? theme.settings.find((s) => !s.name && !s.scope) : undefined;
const globalSetting = theme.settings ? theme.settings.find((s) => !s.name && !s.scope) : void 0;
if (globalSetting?.settings?.foreground)
fg = globalSetting.settings.foreground;
if (globalSetting?.settings?.background)
@@ -1498,6 +1576,31 @@ async function resolveThemes(themes) {
return resolved.filter((i) => !!i);
}
let _emitDeprecation = 3;
let _emitError = false;
function enableDeprecationWarnings(emitDeprecation = true, emitError = false) {
_emitDeprecation = emitDeprecation;
_emitError = emitError;
}
function warnDeprecated(message, version = 3) {
if (!_emitDeprecation)
return;
if (typeof _emitDeprecation === "number" && version > _emitDeprecation)
return;
if (_emitError) {
throw new Error(`[SHIKI DEPRECATE]: ${message}`);
} else {
console.trace(`[SHIKI DEPRECATE]: ${message}`);
}
}
class ShikiError extends Error {
constructor(message) {
super(message);
this.name = "ShikiError";
}
}
class Registry extends Registry$1 {
constructor(_resolver, _themes, _langs, _alias = {}) {
super(_resolver);
@@ -1771,9 +1874,9 @@ function createShikiInternalSync(options) {
};
}
async function createShikiInternal(options = {}) {
if (options.loadWasm) {
warnDeprecated("`loadWasm` option is deprecated. Use `engine: createOnigurumaEngine(loadWasm)` instead.");
async function createShikiInternal(options) {
if (!options.engine) {
warnDeprecated("`engine` option is required. Use `createOnigurumaEngine` or `createJavaScriptRegexEngine` to create an engine.");
}
const [
themes,
@@ -1782,22 +1885,17 @@ async function createShikiInternal(options = {}) {
] = await Promise.all([
resolveThemes(options.themes || []),
resolveLangs(options.langs || []),
options.engine || createOnigurumaEngine$1(options.loadWasm || getDefaultWasmLoader())
options.engine
]);
return createShikiInternalSync({
...options,
loadWasm: undefined,
themes,
langs,
engine
});
}
function getShikiInternal(options = {}) {
warnDeprecated("`getShikiInternal` is deprecated. Use `createShikiInternal` instead.");
return createShikiInternal(options);
}
async function createHighlighterCore(options = {}) {
async function createHighlighterCore(options) {
const internal = await createShikiInternal(options);
return {
getLastGrammarState: (...args) => getLastGrammarState(internal, ...args),
@@ -1806,11 +1904,13 @@ async function createHighlighterCore(options = {}) {
codeToTokens: (code, options2) => codeToTokens(internal, code, options2),
codeToHast: (code, options2) => codeToHast(internal, code, options2),
codeToHtml: (code, options2) => codeToHtml(internal, code, options2),
getBundledLanguages: () => ({}),
getBundledThemes: () => ({}),
...internal,
getInternalContext: () => internal
};
}
function createHighlighterCoreSync(options = {}) {
function createHighlighterCoreSync(options) {
const internal = createShikiInternalSync(options);
return {
getLastGrammarState: (...args) => getLastGrammarState(internal, ...args),
@@ -1819,13 +1919,15 @@ function createHighlighterCoreSync(options = {}) {
codeToTokens: (code, options2) => codeToTokens(internal, code, options2),
codeToHast: (code, options2) => codeToHast(internal, code, options2),
codeToHtml: (code, options2) => codeToHtml(internal, code, options2),
getBundledLanguages: () => ({}),
getBundledThemes: () => ({}),
...internal,
getInternalContext: () => internal
};
}
function makeSingletonHighlighterCore(createHighlighter) {
let _shiki;
async function getSingletonHighlighterCore2(options = {}) {
async function getSingletonHighlighterCore2(options) {
if (!_shiki) {
_shiki = createHighlighter({
...options,
@@ -1845,31 +1947,17 @@ function makeSingletonHighlighterCore(createHighlighter) {
return getSingletonHighlighterCore2;
}
const getSingletonHighlighterCore = /* @__PURE__ */ makeSingletonHighlighterCore(createHighlighterCore);
function getHighlighterCore(options = {}) {
warnDeprecated("`getHighlighterCore` is deprecated. Use `createHighlighterCore` or `getSingletonHighlighterCore` instead.");
return createHighlighterCore(options);
}
function createdBundledHighlighter(arg1, arg2, arg3) {
let bundledLanguages;
let bundledThemes;
let engine;
if (arg2) {
warnDeprecated("`createdBundledHighlighter` signature with `bundledLanguages` and `bundledThemes` is deprecated. Use the options object signature instead.");
bundledLanguages = arg1;
bundledThemes = arg2;
engine = () => createOnigurumaEngine(arg3);
} else {
const options = arg1;
bundledLanguages = options.langs;
bundledThemes = options.themes;
engine = options.engine;
}
async function createHighlighter(options) {
function createdBundledHighlighter(options) {
const bundledLanguages = options.langs;
const bundledThemes = options.themes;
const engine = options.engine;
async function createHighlighter(options2) {
function resolveLang(lang) {
if (typeof lang === "string") {
if (isSpecialLang(lang))
return [];
lang = options2.langAlias?.[lang] || lang;
const bundle = bundledLanguages[lang];
if (!bundle)
throw new ShikiError$1(`Language \`${lang}\` is not included in this bundle. You may want to load it from external source.`);
@@ -1888,11 +1976,11 @@ function createdBundledHighlighter(arg1, arg2, arg3) {
}
return theme;
}
const _themes = (options.themes ?? []).map((i) => resolveTheme(i));
const langs = (options.langs ?? []).map((i) => resolveLang(i));
const _themes = (options2.themes ?? []).map((i) => resolveTheme(i));
const langs = (options2.langs ?? []).map((i) => resolveLang(i));
const core = await createHighlighterCore({
engine: options.engine ?? engine(),
...options,
engine: options2.engine ?? engine(),
...options2,
themes: _themes,
langs
});
@@ -1903,6 +1991,12 @@ function createdBundledHighlighter(arg1, arg2, arg3) {
},
loadTheme(...themes) {
return core.loadTheme(...themes.map(resolveTheme));
},
getBundledLanguages() {
return bundledLanguages;
},
getBundledThemes() {
return bundledThemes;
}
};
}
@@ -1929,45 +2023,41 @@ function makeSingletonHighlighter(createHighlighter) {
}
return getSingletonHighlighter;
}
function createSingletonShorthands(createHighlighter) {
function createSingletonShorthands(createHighlighter, config) {
const getSingletonHighlighter = makeSingletonHighlighter(createHighlighter);
async function get(code, options) {
const shiki = await getSingletonHighlighter({
langs: [options.lang],
themes: "theme" in options ? [options.theme] : Object.values(options.themes)
});
const langs = await config?.guessEmbeddedLanguages?.(code, options.lang, shiki);
if (langs) {
await shiki.loadLanguage(...langs);
}
return shiki;
}
return {
getSingletonHighlighter(options) {
return getSingletonHighlighter(options);
},
async codeToHtml(code, options) {
const shiki = await getSingletonHighlighter({
langs: [options.lang],
themes: "theme" in options ? [options.theme] : Object.values(options.themes)
});
const shiki = await get(code, options);
return shiki.codeToHtml(code, options);
},
async codeToHast(code, options) {
const shiki = await getSingletonHighlighter({
langs: [options.lang],
themes: "theme" in options ? [options.theme] : Object.values(options.themes)
});
const shiki = await get(code, options);
return shiki.codeToHast(code, options);
},
async codeToTokens(code, options) {
const shiki = await getSingletonHighlighter({
langs: [options.lang],
themes: "theme" in options ? [options.theme] : Object.values(options.themes)
});
const shiki = await get(code, options);
return shiki.codeToTokens(code, options);
},
async codeToTokensBase(code, options) {
const shiki = await getSingletonHighlighter({
langs: [options.lang],
themes: [options.theme]
});
const shiki = await get(code, options);
return shiki.codeToTokensBase(code, options);
},
async codeToTokensWithThemes(code, options) {
const shiki = await getSingletonHighlighter({
langs: [options.lang],
themes: Object.values(options.themes).filter(Boolean)
});
const shiki = await get(code, options);
return shiki.codeToTokensWithThemes(code, options);
},
async getLastGrammarState(code, options) {
@@ -1980,15 +2070,6 @@ function createSingletonShorthands(createHighlighter) {
};
}
function createJavaScriptRegexEngine(options) {
warnDeprecated("import `createJavaScriptRegexEngine` from `@shikijs/engine-javascript` or `shiki/engine/javascript` instead");
return createJavaScriptRegexEngine$1(options);
}
function defaultJavaScriptRegexConstructor(pattern) {
warnDeprecated("import `defaultJavaScriptRegexConstructor` from `@shikijs/engine-javascript` or `shiki/engine/javascript` instead");
return defaultJavaScriptRegexConstructor$1(pattern);
}
function createCssVariablesTheme(options = {}) {
const {
name = "css-variables",
@@ -2224,4 +2305,4 @@ function createCssVariablesTheme(options = {}) {
return theme;
}
export { addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createCssVariablesTheme, createHighlighterCore, createHighlighterCoreSync, createJavaScriptRegexEngine, createOnigurumaEngine, createPositionConverter, createShikiInternal, createShikiInternalSync, createSingletonShorthands, createWasmOnigEngine, createdBundledHighlighter, defaultJavaScriptRegexConstructor, getHighlighterCore, getShikiInternal, getSingletonHighlighterCore, getTokenStyleObject, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, loadWasm, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeGetter, normalizeTheme, resolveColorReplacements, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations, warnDeprecated };
export { addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createCssVariablesTheme, createHighlighterCore, createHighlighterCoreSync, createPositionConverter, createShikiInternal, createShikiInternalSync, createSingletonShorthands, createdBundledHighlighter, enableDeprecationWarnings, flatTokenVariants, getSingletonHighlighterCore, getTokenStyleObject, guessEmbeddedLanguages, hastToHtml, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeGetter, normalizeTheme, resolveColorReplacements, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations, warnDeprecated };