@shikijs/core 3.17.0 → 3.18.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.d.mts CHANGED
@@ -229,6 +229,19 @@ declare function addClassToHast(node: Element, className: string | string[]): El
229
229
 
230
230
  /**
231
231
  * Split a string into lines, each line preserves the line ending.
232
+ *
233
+ * @param code - The code string to split into lines
234
+ * @param preserveEnding - Whether to preserve line endings in the result
235
+ * @returns Array of tuples containing [line content, offset index]
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * splitLines('hello\nworld', false)
240
+ * // => [['hello', 0], ['world', 6]]
241
+ *
242
+ * splitLines('hello\nworld', true)
243
+ * // => [['hello\n', 0], ['world', 6]]
244
+ * ```
232
245
  */
233
246
  declare function splitLines(code: string, preserveEnding?: boolean): [string, number][];
234
247
  /**
@@ -245,6 +258,20 @@ declare function createPositionConverter(code: string): {
245
258
  * Guess embedded languages from given code and highlighter.
246
259
  *
247
260
  * When highlighter is provided, only bundled languages will be included.
261
+ *
262
+ * @param code - The code string to analyze
263
+ * @param _lang - The primary language of the code (currently unused)
264
+ * @param highlighter - Optional highlighter instance to validate languages
265
+ * @returns Array of detected language identifiers
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * // Detects 'javascript' from Vue SFC
270
+ * guessEmbeddedLanguages('<script lang="javascript">')
271
+ *
272
+ * // Detects 'python' from markdown code block
273
+ * guessEmbeddedLanguages('```python\nprint("hi")\n```')
274
+ * ```
248
275
  */
249
276
  declare function guessEmbeddedLanguages(code: string, _lang: string | undefined, highlighter?: HighlighterGeneric<any, any>): string[];
250
277
 
package/dist/index.mjs CHANGED
@@ -57,6 +57,9 @@ function addClassToHast(node, className) {
57
57
  }
58
58
 
59
59
  function splitLines(code, preserveEnding = false) {
60
+ if (code.length === 0) {
61
+ return [["", 0]];
62
+ }
60
63
  const parts = code.split(/(\r?\n)/g);
61
64
  let index = 0;
62
65
  const lines = [];
@@ -102,14 +105,26 @@ function createPositionConverter(code) {
102
105
  }
103
106
  function guessEmbeddedLanguages(code, _lang, highlighter) {
104
107
  const langs = /* @__PURE__ */ new Set();
105
- for (const match of code.matchAll(/lang=["']([\w-]+)["']/g)) {
106
- langs.add(match[1]);
108
+ for (const match of code.matchAll(/:?lang=["']([^"']+)["']/g)) {
109
+ const lang = match[1].toLowerCase().trim();
110
+ if (lang)
111
+ langs.add(lang);
107
112
  }
108
113
  for (const match of code.matchAll(/(?:```|~~~)([\w-]+)/g)) {
109
- langs.add(match[1]);
114
+ const lang = match[1].toLowerCase().trim();
115
+ if (lang)
116
+ langs.add(lang);
110
117
  }
111
118
  for (const match of code.matchAll(/\\begin\{([\w-]+)\}/g)) {
112
- langs.add(match[1]);
119
+ const lang = match[1].toLowerCase().trim();
120
+ if (lang)
121
+ langs.add(lang);
122
+ }
123
+ for (const match of code.matchAll(/<script\s+(?:type|lang)=["']([^"']+)["']/gi)) {
124
+ const fullType = match[1].toLowerCase().trim();
125
+ const lang = fullType.includes("/") ? fullType.split("/").pop() : fullType;
126
+ if (lang)
127
+ langs.add(lang);
113
128
  }
114
129
  if (!highlighter)
115
130
  return Array.from(langs);
@@ -844,15 +859,26 @@ function tokenizeAnsiWithTheme(theme, fileContents, options) {
844
859
  );
845
860
  }
846
861
  function dimColor(color) {
847
- const hexMatch = color.match(/#([0-9a-f]{3})([0-9a-f]{3})?([0-9a-f]{2})?/i);
862
+ const hexMatch = color.match(/#([0-9a-f]{3,8})/i);
848
863
  if (hexMatch) {
849
- if (hexMatch[3]) {
850
- const alpha = Math.round(Number.parseInt(hexMatch[3], 16) / 2).toString(16).padStart(2, "0");
851
- return `#${hexMatch[1]}${hexMatch[2]}${alpha}`;
852
- } else if (hexMatch[2]) {
853
- return `#${hexMatch[1]}${hexMatch[2]}80`;
854
- } else {
855
- return `#${Array.from(hexMatch[1]).map((x) => `${x}${x}`).join("")}80`;
864
+ const hex = hexMatch[1];
865
+ if (hex.length === 8) {
866
+ const alpha = Math.round(Number.parseInt(hex.slice(6, 8), 16) / 2).toString(16).padStart(2, "0");
867
+ return `#${hex.slice(0, 6)}${alpha}`;
868
+ } else if (hex.length === 6) {
869
+ return `#${hex}80`;
870
+ } else if (hex.length === 4) {
871
+ const r = hex[0];
872
+ const g = hex[1];
873
+ const b = hex[2];
874
+ const a = hex[3];
875
+ const alpha = Math.round(Number.parseInt(`${a}${a}`, 16) / 2).toString(16).padStart(2, "0");
876
+ return `#${r}${r}${g}${g}${b}${b}${alpha}`;
877
+ } else if (hex.length === 3) {
878
+ const r = hex[0];
879
+ const g = hex[1];
880
+ const b = hex[2];
881
+ return `#${r}${r}${g}${g}${b}${b}80`;
856
882
  }
857
883
  }
858
884
  const cssVarMatch = color.match(/var\((--[\w-]+-ansi-[\w-]+)\)/);
@@ -863,15 +889,15 @@ function dimColor(color) {
863
889
 
864
890
  function codeToTokensBase(internal, code, options = {}) {
865
891
  const {
866
- lang = "text",
867
892
  theme: themeName = internal.getLoadedThemes()[0]
868
893
  } = options;
894
+ const lang = internal.resolveLangAlias(options.lang || "text");
869
895
  if (isPlainLang(lang) || isNoneTheme(themeName))
870
896
  return splitLines(code).map((line) => [{ content: line[0], offset: line[1] }]);
871
897
  const { theme, colorMap } = internal.setTheme(themeName);
872
898
  if (lang === "ansi")
873
899
  return tokenizeAnsiWithTheme(theme, code, options);
874
- const _grammar = internal.getLanguage(lang);
900
+ const _grammar = internal.getLanguage(options.lang || "text");
875
901
  if (options.grammarState) {
876
902
  if (options.grammarState.lang !== _grammar.name) {
877
903
  throw new ShikiError$1(`Grammar state language "${options.grammarState.lang}" does not match highlight language "${_grammar.name}"`);
@@ -1448,12 +1474,12 @@ function mergeWhitespaceTokens(tokens) {
1448
1474
  return tokens.map((line) => {
1449
1475
  const newLine = [];
1450
1476
  let carryOnContent = "";
1451
- let firstOffset = 0;
1477
+ let firstOffset;
1452
1478
  line.forEach((token, idx) => {
1453
1479
  const isDecorated = token.fontStyle && (token.fontStyle & FontStyle.Underline || token.fontStyle & FontStyle.Strikethrough);
1454
1480
  const couldMerge = !isDecorated;
1455
1481
  if (couldMerge && token.content.match(/^\s+$/) && line[idx + 1]) {
1456
- if (!firstOffset)
1482
+ if (firstOffset === void 0)
1457
1483
  firstOffset = token.offset;
1458
1484
  carryOnContent += token.content;
1459
1485
  } else {
@@ -1473,7 +1499,7 @@ function mergeWhitespaceTokens(tokens) {
1473
1499
  token
1474
1500
  );
1475
1501
  }
1476
- firstOffset = 0;
1502
+ firstOffset = void 0;
1477
1503
  carryOnContent = "";
1478
1504
  } else {
1479
1505
  newLine.push(token);
@@ -1685,6 +1711,21 @@ class ShikiError extends Error {
1685
1711
  }
1686
1712
  }
1687
1713
 
1714
+ function resolveLangAlias(name, alias) {
1715
+ if (!alias)
1716
+ return name;
1717
+ if (alias[name]) {
1718
+ const resolved = /* @__PURE__ */ new Set([name]);
1719
+ while (alias[name]) {
1720
+ name = alias[name];
1721
+ if (resolved.has(name))
1722
+ throw new ShikiError(`Circular alias \`${Array.from(resolved).join(" -> ")} -> ${name}\``);
1723
+ resolved.add(name);
1724
+ }
1725
+ }
1726
+ return name;
1727
+ }
1728
+
1688
1729
  class Registry extends Registry$1 {
1689
1730
  constructor(_resolver, _themes, _langs, _alias = {}) {
1690
1731
  super(_resolver);
@@ -1735,15 +1776,7 @@ class Registry extends Registry$1 {
1735
1776
  this._syncRegistry.setTheme(textmateTheme);
1736
1777
  }
1737
1778
  getGrammar(name) {
1738
- if (this._alias[name]) {
1739
- const resolved = /* @__PURE__ */ new Set([name]);
1740
- while (this._alias[name]) {
1741
- name = this._alias[name];
1742
- if (resolved.has(name))
1743
- throw new ShikiError(`Circular alias \`${Array.from(resolved).join(" -> ")} -> ${name}\``);
1744
- resolved.add(name);
1745
- }
1746
- }
1779
+ name = resolveLangAlias(name, this._alias);
1747
1780
  return this._resolvedGrammars.get(name);
1748
1781
  }
1749
1782
  loadLanguage(lang) {
@@ -1879,6 +1912,9 @@ function createShikiInternalSync(options) {
1879
1912
  const resolver = new Resolver(options.engine, langs);
1880
1913
  const _registry = new Registry(resolver, themes, langs, options.langAlias);
1881
1914
  let _lastTheme;
1915
+ function resolveLangAlias$1(name) {
1916
+ return resolveLangAlias(name, options.langAlias);
1917
+ }
1882
1918
  function getLanguage(name) {
1883
1919
  ensureNotDisposed();
1884
1920
  const _lang = _registry.getGrammar(typeof name === "string" ? name : name.name);
@@ -1950,6 +1986,7 @@ function createShikiInternalSync(options) {
1950
1986
  getLanguage,
1951
1987
  getLoadedThemes,
1952
1988
  getLoadedLanguages,
1989
+ resolveLangAlias: resolveLangAlias$1,
1953
1990
  loadLanguage,
1954
1991
  loadLanguageSync,
1955
1992
  loadTheme,
@@ -2040,9 +2077,9 @@ function createBundledHighlighter(options) {
2040
2077
  async function createHighlighter(options2) {
2041
2078
  function resolveLang(lang) {
2042
2079
  if (typeof lang === "string") {
2080
+ lang = options2.langAlias?.[lang] || lang;
2043
2081
  if (isSpecialLang(lang))
2044
2082
  return [];
2045
- lang = options2.langAlias?.[lang] || lang;
2046
2083
  const bundle = bundledLanguages[lang];
2047
2084
  if (!bundle)
2048
2085
  throw new ShikiError$1(`Language \`${lang}\` is not included in this bundle. You may want to load it from external source.`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shikijs/core",
3
3
  "type": "module",
4
- "version": "3.17.0",
4
+ "version": "3.18.0",
5
5
  "description": "Core of Shiki",
6
6
  "author": "Pine Wu <octref@gmail.com>; Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "@shikijs/vscode-textmate": "^10.0.2",
40
40
  "@types/hast": "^3.0.4",
41
41
  "hast-util-to-html": "^9.0.5",
42
- "@shikijs/types": "3.17.0"
42
+ "@shikijs/types": "3.18.0"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "unbuild",