@shikijs/core 1.7.0 → 1.8.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 CHANGED
@@ -5199,9 +5199,9 @@ class Registry extends Registry$1 {
5199
5199
  _themes;
5200
5200
  _langs;
5201
5201
  _alias;
5202
- _resolvedThemes = {};
5203
- _resolvedGrammars = {};
5204
- _langMap = {};
5202
+ _resolvedThemes = new Map();
5203
+ _resolvedGrammars = new Map();
5204
+ _langMap = new Map();
5205
5205
  _langGraph = new Map();
5206
5206
  _textmateThemeCache = new WeakMap();
5207
5207
  _loadedThemesCache = null;
@@ -5217,14 +5217,14 @@ class Registry extends Registry$1 {
5217
5217
  }
5218
5218
  getTheme(theme) {
5219
5219
  if (typeof theme === 'string')
5220
- return this._resolvedThemes[theme];
5220
+ return this._resolvedThemes.get(theme);
5221
5221
  else
5222
5222
  return this.loadTheme(theme);
5223
5223
  }
5224
5224
  loadTheme(theme) {
5225
5225
  const _theme = normalizeTheme(theme);
5226
5226
  if (_theme.name) {
5227
- this._resolvedThemes[_theme.name] = _theme;
5227
+ this._resolvedThemes.set(_theme.name, _theme);
5228
5228
  // Reset cache
5229
5229
  this._loadedThemesCache = null;
5230
5230
  }
@@ -5232,7 +5232,7 @@ class Registry extends Registry$1 {
5232
5232
  }
5233
5233
  getLoadedThemes() {
5234
5234
  if (!this._loadedThemesCache)
5235
- this._loadedThemesCache = Object.keys(this._resolvedThemes);
5235
+ this._loadedThemesCache = [...this._resolvedThemes.keys()];
5236
5236
  return this._loadedThemesCache;
5237
5237
  }
5238
5238
  // Override and re-implement this method to cache the textmate themes as `TextMateTheme.createFromRawTheme`
@@ -5259,12 +5259,13 @@ class Registry extends Registry$1 {
5259
5259
  resolved.add(name);
5260
5260
  }
5261
5261
  }
5262
- return this._resolvedGrammars[name];
5262
+ return this._resolvedGrammars.get(name);
5263
5263
  }
5264
5264
  async loadLanguage(lang) {
5265
5265
  if (this.getGrammar(lang.name))
5266
5266
  return;
5267
- const embeddedLazilyBy = new Set(Object.values(this._langMap).filter(i => i.embeddedLangsLazy?.includes(lang.name)));
5267
+ const embeddedLazilyBy = new Set([...this._langMap.values()]
5268
+ .filter(i => i.embeddedLangsLazy?.includes(lang.name)));
5268
5269
  this._resolver.addLanguage(lang);
5269
5270
  const grammarConfig = {
5270
5271
  balancedBracketSelectors: lang.balancedBracketSelectors || ['*'],
@@ -5273,7 +5274,7 @@ class Registry extends Registry$1 {
5273
5274
  // @ts-expect-error Private members, set this to override the previous grammar (that can be a stub)
5274
5275
  this._syncRegistry._rawGrammars.set(lang.scopeName, lang);
5275
5276
  const g = await this.loadGrammarWithConfiguration(lang.scopeName, 1, grammarConfig);
5276
- this._resolvedGrammars[lang.name] = g;
5277
+ this._resolvedGrammars.set(lang.name, g);
5277
5278
  if (lang.aliases) {
5278
5279
  lang.aliases.forEach((alias) => {
5279
5280
  this._alias[alias] = lang.name;
@@ -5284,14 +5285,14 @@ class Registry extends Registry$1 {
5284
5285
  // If there is a language that embeds this language lazily, we need to reload it
5285
5286
  if (embeddedLazilyBy.size) {
5286
5287
  for (const e of embeddedLazilyBy) {
5287
- delete this._resolvedGrammars[e.name];
5288
+ this._resolvedGrammars.delete(e.name);
5288
5289
  // Reset cache
5289
5290
  this._loadedLanguagesCache = null;
5290
5291
  // @ts-expect-error clear cache
5291
5292
  this._syncRegistry?._injectionGrammars?.delete(e.scopeName);
5292
5293
  // @ts-expect-error clear cache
5293
5294
  this._syncRegistry?._grammars?.delete(e.scopeName);
5294
- await this.loadLanguage(this._langMap[e.name]);
5295
+ await this.loadLanguage(this._langMap.get(e.name));
5295
5296
  }
5296
5297
  }
5297
5298
  }
@@ -5299,6 +5300,14 @@ class Registry extends Registry$1 {
5299
5300
  this._themes.map(t => this.loadTheme(t));
5300
5301
  await this.loadLanguages(this._langs);
5301
5302
  }
5303
+ dispose() {
5304
+ super.dispose();
5305
+ this._resolvedThemes.clear();
5306
+ this._resolvedGrammars.clear();
5307
+ this._langMap.clear();
5308
+ this._langGraph.clear();
5309
+ this._loadedThemesCache = null;
5310
+ }
5302
5311
  async loadLanguages(langs) {
5303
5312
  for (const lang of langs)
5304
5313
  this.resolveEmbeddedLanguages(lang);
@@ -5316,16 +5325,19 @@ class Registry extends Registry$1 {
5316
5325
  await this.loadLanguage(lang);
5317
5326
  }
5318
5327
  getLoadedLanguages() {
5319
- if (!this._loadedLanguagesCache)
5320
- this._loadedLanguagesCache = Object.keys({ ...this._resolvedGrammars, ...this._alias });
5328
+ if (!this._loadedLanguagesCache) {
5329
+ this._loadedLanguagesCache = [
5330
+ ...new Set([...this._resolvedGrammars.keys(), ...Object.keys(this._alias)]),
5331
+ ];
5332
+ }
5321
5333
  return this._loadedLanguagesCache;
5322
5334
  }
5323
5335
  resolveEmbeddedLanguages(lang) {
5324
- this._langMap[lang.name] = lang;
5336
+ this._langMap.set(lang.name, lang);
5325
5337
  this._langGraph.set(lang.name, lang);
5326
5338
  if (lang.embeddedLangs) {
5327
5339
  for (const embeddedLang of lang.embeddedLangs)
5328
- this._langGraph.set(embeddedLang, this._langMap[embeddedLang]);
5340
+ this._langGraph.set(embeddedLang, this._langMap.get(embeddedLang));
5329
5341
  }
5330
5342
  }
5331
5343
  }
@@ -5390,7 +5402,8 @@ let instancesCount = 0;
5390
5402
  async function getShikiInternal(options = {}) {
5391
5403
  instancesCount += 1;
5392
5404
  if (options.warnings !== false && instancesCount >= 10 && instancesCount % 10 === 0)
5393
- console.warn(`[Shiki] ${instancesCount} instances have been created. Shiki is supposed to be used as a singleton, consider refactoring your code to cache your highlighter instance.`);
5405
+ console.warn(`[Shiki] ${instancesCount} instances have been created. Shiki is supposed to be used as a singleton, consider refactoring your code to cache your highlighter instance; Or call \`highlighter.dispose()\` to release unused instances.`);
5406
+ let isDisposed = false;
5394
5407
  async function normalizeGetter(p) {
5395
5408
  return Promise.resolve(typeof p === 'function' ? p() : p).then(r => r.default || r);
5396
5409
  }
@@ -5417,6 +5430,7 @@ async function getShikiInternal(options = {}) {
5417
5430
  await _registry.init();
5418
5431
  let _lastTheme;
5419
5432
  function getLanguage(name) {
5433
+ ensureNotDisposed();
5420
5434
  const _lang = _registry.getGrammar(typeof name === 'string' ? name : name.name);
5421
5435
  if (!_lang)
5422
5436
  throw new ShikiError(`Language \`${name}\` not found, you may need to load it first`);
@@ -5425,12 +5439,14 @@ async function getShikiInternal(options = {}) {
5425
5439
  function getTheme(name) {
5426
5440
  if (name === 'none')
5427
5441
  return { bg: '', fg: '', name: 'none', settings: [], type: 'dark' };
5442
+ ensureNotDisposed();
5428
5443
  const _theme = _registry.getTheme(name);
5429
5444
  if (!_theme)
5430
5445
  throw new ShikiError(`Theme \`${name}\` not found, you may need to load it first`);
5431
5446
  return _theme;
5432
5447
  }
5433
5448
  function setTheme(name) {
5449
+ ensureNotDisposed();
5434
5450
  const theme = getTheme(name);
5435
5451
  if (_lastTheme !== name) {
5436
5452
  _registry.setTheme(theme);
@@ -5443,19 +5459,34 @@ async function getShikiInternal(options = {}) {
5443
5459
  };
5444
5460
  }
5445
5461
  function getLoadedThemes() {
5462
+ ensureNotDisposed();
5446
5463
  return _registry.getLoadedThemes();
5447
5464
  }
5448
5465
  function getLoadedLanguages() {
5466
+ ensureNotDisposed();
5449
5467
  return _registry.getLoadedLanguages();
5450
5468
  }
5451
5469
  async function loadLanguage(...langs) {
5470
+ ensureNotDisposed();
5452
5471
  await _registry.loadLanguages(await resolveLangs(langs));
5453
5472
  }
5454
5473
  async function loadTheme(...themes) {
5474
+ ensureNotDisposed();
5455
5475
  await Promise.all(themes.map(async (theme) => isSpecialTheme(theme)
5456
5476
  ? null
5457
5477
  : _registry.loadTheme(await normalizeGetter(theme))));
5458
5478
  }
5479
+ function ensureNotDisposed() {
5480
+ if (isDisposed)
5481
+ throw new ShikiError('Shiki instance has been disposed');
5482
+ }
5483
+ function dispose() {
5484
+ if (isDisposed)
5485
+ return;
5486
+ isDisposed = true;
5487
+ _registry.dispose();
5488
+ instancesCount -= 1;
5489
+ }
5459
5490
  return {
5460
5491
  setTheme,
5461
5492
  getTheme,
@@ -5464,6 +5495,8 @@ async function getShikiInternal(options = {}) {
5464
5495
  getLoadedLanguages,
5465
5496
  loadLanguage,
5466
5497
  loadTheme,
5498
+ dispose,
5499
+ [Symbol.dispose]: dispose,
5467
5500
  };
5468
5501
  }
5469
5502
 
package/dist/types.d.mts CHANGED
@@ -42,6 +42,14 @@ interface ShikiInternal<BundledLangKeys extends string = never, BundledThemeKeys
42
42
  * Special-handled themes like `none` are not included.
43
43
  */
44
44
  getLoadedThemes: () => string[];
45
+ /**
46
+ * Dispose the internal registry and release resources
47
+ */
48
+ dispose: () => void;
49
+ /**
50
+ * Dispose the internal registry and release resources
51
+ */
52
+ [Symbol.dispose]: () => void;
45
53
  }
46
54
  /**
47
55
  * Generic instance interface of Shiki
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shikijs/core",
3
3
  "type": "module",
4
- "version": "1.7.0",
4
+ "version": "1.8.0",
5
5
  "description": "Core of Shiki",
6
6
  "author": "Pine Wu <octref@gmail.com>; Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",