History

shiki loading changes

Julius Marminge committed 7 months ago

Commit 12fc9b71 parent a22cb053 files · +227 −80Browse files

Unified · Split

3 files
  1. apps/mobile/package.json +4 −1
  2. apps/mobile/src/features/threads/review/shikiReviewHighlighter.ts +201 −48
  3. bun.lock +22 −31
apps/mobile/package.json+4−1
@@ -39,6 +39,10 @@ · 38 unmodified lines
3939 "@legendapp/list": "3.0.0-beta.44",
4040 "@pierre/diffs": "^1.1.0-beta.16",
4141 "@react-native-menu/menu": "^2.0.0",
42+ "@shikijs/core": "3.23.0",
43+ "@shikijs/engine-javascript": "3.23.0",
44+ "@shikijs/langs": "3.23.0",
45+ "@shikijs/themes": "3.23.0",
4246 "@t3tools/client-runtime": "workspace:*",
4347 "@t3tools/contracts": "workspace:*",
4448 "@t3tools/shared": "workspace:*",
@@ -76,7 +80,6 @@ · 31 unmodified lines
7680 "react-native-shiki-engine": "^0.3.9",
7781 "react-native-svg": "15.15.3",
7882 "react-native-worklets": "0.7.2",
79− "shiki": "3.23.0",
8083 "tailwind-merge": "^3.5.0",
8184 "uniwind": "^1.6.2"
8285 },
apps/mobile/src/features/threads/review/shikiReviewHighlighter.ts+201−48
@@ -1,3 +1,5 @@
1+import { createHighlighterCore, type HighlighterCore } from "@shikijs/core";
2+import { createJavaScriptRegexEngine } from "@shikijs/engine-javascript";
13 import { getFiletypeFromFileName } from "@pierre/diffs/utils";
24
35 import {
@@ -20,7 +22,7 @@ export interface ReviewHighlightedFile { · 16 unmodified lines
2022 readonly deletionLines: ReadonlyArray<ReadonlyArray<ReviewHighlightedToken>>;
2123 }
2224
23−const SHIKI_THEME_BY_SCHEME = {
25+const SHIKI_THEME_NAME_BY_SCHEME = {
2426 light: "github-light-default",
2527 dark: "github-dark-default",
2628 } as const;
@@ -31,20 +33,120 @@ const REVIEW_HIGHLIGHTER_DISABLE_RESULT_CACHE = resolveReviewHighlighterBooleanF · 4 unmodified lines
3133 process.env.EXPO_PUBLIC_REVIEW_HIGHLIGHTER_DISABLE_CACHE,
3234 false,
3335 );
34−
3536 const highlightCache = new Map<string, Promise<ReviewHighlightedFile>>();
3637 const resolvedHighlightCache = new Map<string, ReviewHighlightedFile>();
3738 const loadedLanguages = new Set<string>(["text"]);
38−type ShikiHighlighter = {
39− loadLanguage: (...langs: string[]) => Promise<void>;
40− codeToTokensBase: (
41− code: string,
42− options: { readonly lang: string; readonly theme: string },
43− ) => Promise<Array<Array<{ content: string; color?: string; fontStyle?: number }>>>;
39+const languageLoadingPromises = new Map<string, Promise<boolean>>();
40+const languageImports: Partial<Record<string, () => Promise<unknown>>> = {
41+ javascript: () => import("@shikijs/langs/javascript"),
42+ typescript: () => import("@shikijs/langs/typescript"),
43+ jsx: () => import("@shikijs/langs/jsx"),
44+ tsx: () => import("@shikijs/langs/tsx"),
45+ python: () => import("@shikijs/langs/python"),
46+ rust: () => import("@shikijs/langs/rust"),
47+ go: () => import("@shikijs/langs/go"),
48+ java: () => import("@shikijs/langs/java"),
49+ kotlin: () => import("@shikijs/langs/kotlin"),
50+ swift: () => import("@shikijs/langs/swift"),
51+ "objective-c": () => import("@shikijs/langs/objective-c"),
52+ c: () => import("@shikijs/langs/c"),
53+ cpp: () => import("@shikijs/langs/cpp"),
54+ csharp: () => import("@shikijs/langs/csharp"),
55+ php: () => import("@shikijs/langs/php"),
56+ ruby: () => import("@shikijs/langs/ruby"),
57+ lua: () => import("@shikijs/langs/lua"),
58+ perl: () => import("@shikijs/langs/perl"),
59+ r: () => import("@shikijs/langs/r"),
60+ dart: () => import("@shikijs/langs/dart"),
61+ scala: () => import("@shikijs/langs/scala"),
62+ elixir: () => import("@shikijs/langs/elixir"),
63+ haskell: () => import("@shikijs/langs/haskell"),
64+ clojure: () => import("@shikijs/langs/clojure"),
65+ ocaml: () => import("@shikijs/langs/ocaml"),
66+ fsharp: () => import("@shikijs/langs/fsharp"),
67+ erlang: () => import("@shikijs/langs/erlang"),
68+ zig: () => import("@shikijs/langs/zig"),
69+ nim: () => import("@shikijs/langs/nim"),
70+ html: () => import("@shikijs/langs/html"),
71+ css: () => import("@shikijs/langs/css"),
72+ scss: () => import("@shikijs/langs/scss"),
73+ less: () => import("@shikijs/langs/less"),
74+ xml: () => import("@shikijs/langs/xml"),
75+ svg: () => import("@shikijs/langs/xml"),
76+ vue: () => import("@shikijs/langs/vue"),
77+ svelte: () => import("@shikijs/langs/svelte"),
78+ astro: () => import("@shikijs/langs/astro"),
79+ json: () => import("@shikijs/langs/json"),
80+ jsonc: () => import("@shikijs/langs/jsonc"),
81+ yaml: () => import("@shikijs/langs/yaml"),
82+ toml: () => import("@shikijs/langs/toml"),
83+ ini: () => import("@shikijs/langs/ini"),
84+ bash: () => import("@shikijs/langs/bash"),
85+ shellscript: () => import("@shikijs/langs/shellscript"),
86+ powershell: () => import("@shikijs/langs/powershell"),
87+ fish: () => import("@shikijs/langs/fish"),
88+ sql: () => import("@shikijs/langs/sql"),
89+ graphql: () => import("@shikijs/langs/graphql"),
90+ prisma: () => import("@shikijs/langs/prisma"),
91+ docker: () => import("@shikijs/langs/docker"),
92+ hcl: () => import("@shikijs/langs/hcl"),
93+ nix: () => import("@shikijs/langs/nix"),
94+ markdown: () => import("@shikijs/langs/markdown"),
95+ mdx: () => import("@shikijs/langs/mdx"),
96+ tex: () => import("@shikijs/langs/tex"),
97+ diff: () => import("@shikijs/langs/diff"),
98+ regex: () => import("@shikijs/langs/regex"),
99+ viml: () => import("@shikijs/langs/viml"),
100+ makefile: () => import("@shikijs/langs/makefile"),
101+ cmake: () => import("@shikijs/langs/cmake"),
102+ groovy: () => import("@shikijs/langs/groovy"),
103+};
104+
105+const languageAliases: Record<string, string> = {
106+ js: "javascript",
107+ mjs: "javascript",
108+ cjs: "javascript",
109+ ts: "typescript",
110+ mts: "typescript",
111+ cts: "typescript",
112+ py: "python",
113+ rb: "ruby",
114+ rs: "rust",
115+ sh: "bash",
116+ zsh: "bash",
117+ shell: "shellscript",
118+ yml: "yaml",
119+ md: "markdown",
120+ "c++": "cpp",
121+ "c#": "csharp",
122+ cs: "csharp",
123+ dockerfile: "docker",
124+ vim: "viml",
125+ objc: "objective-c",
126+ objectivec: "objective-c",
127+ "obj-c": "objective-c",
128+ ps1: "powershell",
129+ pwsh: "powershell",
130+ hs: "haskell",
131+ ex: "elixir",
132+ exs: "elixir",
133+ erl: "erlang",
134+ clj: "clojure",
135+ ml: "ocaml",
136+ fs: "fsharp",
137+ tf: "hcl",
138+ make: "makefile",
139+ plain: "text",
140+ plaintext: "text",
141+ txt: "text",
44142 };
45−let highlighterPromise: Promise<ShikiHighlighter> | null = null;
143+let highlighterPromise: Promise<HighlighterCore> | null = null;
46144 let activeHighlighterEnginePromise: Promise<ReviewHighlighterEngine> | null = null;
47145
146+type LoadedLanguageModule = {
147+ default: Parameters<HighlighterCore["loadLanguage"]>[0];
148+};
149+
48150 function resolveReviewHighlighterBooleanFlag(
49151 value: string | undefined,
50152 defaultValue: boolean,
@@ -103,9 +205,12 @@ function joinPatchLines(lines: ReadonlyArray<string>): string { · 52 unmodified lines
103205 return lines.map(stripTrailingNewline).join("\n");
104206 }
105207
106−async function getHighlighter() {
208+async function getHighlighter(): Promise<HighlighterCore> {
107209 if (!highlighterPromise) {
108− const configuredHighlighterPromise = import("shiki").then(async (shikiModule) => {
210+ const configuredHighlighterPromise = Promise.all([
211+ import("@shikijs/themes/github-light-default"),
212+ import("@shikijs/themes/github-dark-default"),
213+ ]).then(async ([lightThemeModule, darkThemeModule]) => {
109214 let nativeEngineAvailable = false;
110215
111216 logReviewHighlighterDiagnostic("initializing", {
@@ -113,6 +218,8 @@ async function getHighlighter() { · 1 unmodified line
113218 resultCacheDisabled: REVIEW_HIGHLIGHTER_DISABLE_RESULT_CACHE,
114219 });
115220
221+ const themes = [lightThemeModule.default, darkThemeModule.default];
222+
116223 if (REVIEW_HIGHLIGHTER_ENGINE_PREFERENCE !== "javascript") {
117224 try {
118225 const nativeEngineModule = await import("react-native-shiki-engine");
@@ -121,22 +228,17 @@ async function getHighlighter() { · 2 unmodified lines
121228 logReviewHighlighterDiagnostic("checked native engine availability", {
122229 nativeEngineAvailable,
123230 });
231+
124232 if (nativeEngineAvailable) {
125− const createHighlighter = shikiModule.createBundledHighlighter({
126− langs: shikiModule.bundledLanguages,
127− themes: shikiModule.bundledThemes,
128− engine: () => {
129− logReviewHighlighterDiagnostic("creating native regex engine");
130− return nativeEngineModule.createNativeEngine();
131− },
132− });
133− const highlighter = await createHighlighter({
134− themes: [SHIKI_THEME_BY_SCHEME.light, SHIKI_THEME_BY_SCHEME.dark],
233+ logReviewHighlighterDiagnostic("creating native regex engine");
234+ const highlighter = await createHighlighterCore({
235+ themes,
135236 langs: [],
237+ engine: nativeEngineModule.createNativeEngine(),
136238 });
137239 logReviewHighlighterDiagnostic("using native engine");
138240 return {
139− highlighter: highlighter as unknown as ShikiHighlighter,
241+ highlighter,
140242 engine: "native" as const,
141243 };
142244 }
@@ -157,54 +259,105 @@ async function getHighlighter() { · 14 unmodified lines
157259 REVIEW_HIGHLIGHTER_ENGINE_PREFERENCE,
158260 nativeEngineAvailable,
159261 );
160− const createHighlighter = shikiModule.createBundledHighlighter({
161− langs: shikiModule.bundledLanguages,
162− themes: shikiModule.bundledThemes,
163− engine: () => shikiModule.createJavaScriptRegexEngine(),
164− });
165− const highlighter = await createHighlighter({
166− themes: [SHIKI_THEME_BY_SCHEME.light, SHIKI_THEME_BY_SCHEME.dark],
262+ const highlighter = await createHighlighterCore({
263+ themes,
167264 langs: [],
265+ engine: createJavaScriptRegexEngine(),
168266 });
169267 logReviewHighlighterDiagnostic("using javascript engine", {
170268 resolvedEngine: engine,
171269 });
172270 return {
173− highlighter: highlighter as unknown as ShikiHighlighter,
271+ highlighter,
174272 engine,
175273 };
176274 });
177275
178− highlighterPromise = configuredHighlighterPromise.then((result) => result.highlighter);
179− activeHighlighterEnginePromise = configuredHighlighterPromise.then((result) => result.engine);
276+ highlighterPromise = configuredHighlighterPromise
277+ .then((result) => result.highlighter)
278+ .catch((error) => {
279+ highlighterPromise = null;
280+ activeHighlighterEnginePromise = null;
281+ throw error;
282+ });
283+ activeHighlighterEnginePromise = configuredHighlighterPromise
284+ .then((result) => result.engine)
285+ .catch((error) => {
286+ activeHighlighterEnginePromise = null;
287+ throw error;
288+ });
180289 }
181290
182− return highlighterPromise as Promise<ShikiHighlighter>;
291+ return highlighterPromise;
183292 }
184293
185294 export async function getActiveReviewHighlighterEngine(): Promise<ReviewHighlighterEngine> {
186295 await getHighlighter();
187− return (activeHighlighterEnginePromise ??
188− Promise.resolve("javascript")) as Promise<ReviewHighlighterEngine>;
296+ return activeHighlighterEnginePromise ?? Promise.resolve("javascript");
297+}
298+
299+function resolveLanguageAlias(language: string): string {
300+ const normalized = language.toLowerCase();
301+ return languageAliases[normalized] ?? normalized;
302+}
303+
304+async function loadSingleLanguage(
305+ highlighter: HighlighterCore,
306+ language: string,
307+): Promise<boolean> {
308+ if (loadedLanguages.has(language)) {
309+ return true;
310+ }
311+
312+ const existingPromise = languageLoadingPromises.get(language);
313+ if (existingPromise) {
314+ return existingPromise;
315+ }
316+
317+ const importer = languageImports[language];
318+ if (!importer) {
319+ return false;
320+ }
321+
322+ const loadingPromise = (async () => {
323+ try {
324+ const languageModule = (await importer()) as LoadedLanguageModule;
325+ await highlighter.loadLanguage(languageModule.default);
326+ loadedLanguages.add(language);
327+ return true;
328+ } catch {
329+ return false;
330+ } finally {
331+ languageLoadingPromises.delete(language);
332+ }
333+ })();
334+
335+ languageLoadingPromises.set(language, loadingPromise);
336+ return loadingPromise;
189337 }
190338
191339 async function resolveLanguageFromPath(
192340 path: string,
193341 languageHint: string | null = null,
194342 ): Promise<string> {
195− const candidate = languageHint ?? getFiletypeFromFileName(path);
196− if (!candidate || candidate === "text" || candidate === "ansi") {
343+ const detectedLanguage = languageHint ?? getFiletypeFromFileName(path);
344+ if (!detectedLanguage) {
345+ return "text";
346+ }
347+
348+ const candidate = resolveLanguageAlias(detectedLanguage);
349+ if (candidate === "text" || candidate === "ansi") {
350+ return "text";
351+ }
352+
353+ if (!(candidate in languageImports)) {
197354 return "text";
198355 }
199356
200357 const highlighter = await getHighlighter();
201− if (!loadedLanguages.has(candidate)) {
202− try {
203− await highlighter.loadLanguage(candidate);
204− loadedLanguages.add(candidate);
205− } catch {
206− return "text";
207− }
358+ const loaded = await loadSingleLanguage(highlighter, resolveLanguageAlias(candidate));
359+ if (!loaded) {
360+ return "text";
208361 }
209362
210363 return candidate;
@@ -236,12 +389,12 @@ async function highlightLines( · 25 unmodified lines
236389 }
237390
238391 const highlighter = await getHighlighter();
239− const tokenLines = await highlighter.codeToTokensBase(code, { lang: language, theme });
392+ const tokenLines = highlighter.codeToTokensBase(code, { lang: language, theme });
240393 return normalizeHighlightedLines(tokenLines);
241394 }
242395
243396 function getHighlightCacheKey(file: ReviewRenderableFile, theme: ReviewDiffTheme): string {
244− return `${SHIKI_THEME_BY_SCHEME[theme]}:${file.cacheKey}`;
397+ return `${SHIKI_THEME_NAME_BY_SCHEME[theme]}:${file.cacheKey}`;
245398 }
246399
247400 export function getCachedHighlightedReviewFile(
@@ -259,7 +412,7 @@ export async function highlightReviewFile( · 11 unmodified lines
259412 file: ReviewRenderableFile,
260413 theme: ReviewDiffTheme,
261414 ): Promise<ReviewHighlightedFile> {
262− const shikiTheme = SHIKI_THEME_BY_SCHEME[theme];
415+ const shikiTheme = SHIKI_THEME_NAME_BY_SCHEME[theme];
263416 const cacheKey = getHighlightCacheKey(file, theme);
264417 if (!REVIEW_HIGHLIGHTER_DISABLE_RESULT_CACHE) {
265418 const resolved = resolvedHighlightCache.get(cacheKey);
@@ -303,7 +456,7 @@ export async function highlightReviewSelectedLines(input: { · 37 unmodified lines
303456 }
304457
305458 const language = await resolveLanguageFromPath(input.filePath, input.languageHint ?? null);
306− const shikiTheme = SHIKI_THEME_BY_SCHEME[input.theme];
459+ const shikiTheme = SHIKI_THEME_NAME_BY_SCHEME[input.theme];
307460 const additionLikeLines = input.lines
308461 .filter((line) => line.change !== "delete")
309462 .map((line) => `${line.content}\n`);
bun.lock+22−31
@@ -51,6 +51,10 @@ · 50 unmodified lines
5151 "@legendapp/list": "3.0.0-beta.44",
5252 "@pierre/diffs": "^1.1.0-beta.16",
5353 "@react-native-menu/menu": "^2.0.0",
54+ "@shikijs/core": "3.23.0",
55+ "@shikijs/engine-javascript": "3.23.0",
56+ "@shikijs/langs": "3.23.0",
57+ "@shikijs/themes": "3.23.0",
5458 "@t3tools/client-runtime": "workspace:*",
5559 "@t3tools/contracts": "workspace:*",
5660 "@t3tools/shared": "workspace:*",
@@ -88,7 +92,6 @@ · 31 unmodified lines
8892 "react-native-shiki-engine": "^0.3.9",
8993 "react-native-svg": "15.15.3",
9094 "react-native-worklets": "0.7.2",
91− "shiki": "3.23.0",
9295 "tailwind-merge": "^3.5.0",
9396 "uniwind": "^1.6.2",
9497 },
@@ -1062,7 +1065,7 @@ · 967 unmodified lines
10621065
10631066 "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA=="],
10641067
1065− "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
1068+ "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="],
10661069
10671070 "@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="],
10681071
@@ -2592,7 +2595,7 @@ · 1523 unmodified lines
25922595
25932596 "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
25942597
2595− "shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
2598+ "shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="],
25962599
25972600 "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
25982601
@@ -2954,8 +2957,6 @@ · 355 unmodified lines
29542957
29552958 "@astrojs/language-server/@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="],
29562959
2957− "@astrojs/markdown-remark/shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="],
2958−
29592960 "@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
29602961
29612962 "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
@@ -3006,6 +3007,8 @@ · 44 unmodified lines
30063007
30073008 "@pierre/diffs/diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="],
30083009
3010+ "@pierre/diffs/shiki": ["shiki@3.23.0", "", { "dependencies": { "@shikijs/core": "3.23.0", "@shikijs/engine-javascript": "3.23.0", "@shikijs/engine-oniguruma": "3.23.0", "@shikijs/langs": "3.23.0", "@shikijs/themes": "3.23.0", "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA=="],
3011+
30093012 "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
30103013
30113014 "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
@@ -3026,6 +3029,8 @@ · 14 unmodified lines
30263029
30273030 "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
30283031
3032+ "@shikijs/engine-oniguruma/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
3033+
30293034 "@shikijs/primitive/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
30303035
30313036 "@tailwindcss/node/tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="],
@@ -3062,8 +3067,6 @@ · 30 unmodified lines
30623067
30633068 "ast-kit/@babel/parser": ["@babel/parser@8.0.0-rc.2", "", { "dependencies": { "@babel/types": "^8.0.0-rc.2" }, "bin": "./bin/babel-parser.js" }, "sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ=="],
30643069
3065− "astro/shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="],
3066−
30673070 "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
30683071
30693072 "babel-preset-expo/babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "^7.26.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="],
@@ -3208,6 +3211,16 @@ · 138 unmodified lines
32083211
32093212 "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
32103213
3214+ "shiki/@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="],
3215+
3216+ "shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="],
3217+
3218+ "shiki/@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="],
3219+
3220+ "shiki/@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="],
3221+
3222+ "shiki/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
3223+
32113224 "simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="],
32123225
32133226 "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
@@ -3258,18 +3271,6 @@ · 44 unmodified lines
32583271
32593272 "yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
32603273
3261− "@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="],
3262−
3263− "@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="],
3264−
3265− "@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="],
3266−
3267− "@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="],
3268−
3269− "@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="],
3270−
3271− "@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
3272−
32733274 "@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
32743275
32753276 "@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
@@ -3280,6 +3281,8 @@ · 4 unmodified lines
32803281
32813282 "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
32823283
3284+ "@pierre/diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="],
3285+
32833286 "@react-native/babel-preset/babel-plugin-syntax-hermes-parser/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="],
32843287
32853288 "@react-native/codegen/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
@@ -3352,18 +3355,6 @@ · 66 unmodified lines
33523355
33533356 "ast-kit/@babel/parser/@babel/types": ["@babel/types@8.0.0-rc.2", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.2", "@babel/helper-validator-identifier": "^8.0.0-rc.2" } }, "sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw=="],
33543357
3355− "astro/shiki/@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="],
3356−
3357− "astro/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="],
3358−
3359− "astro/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="],
3360−
3361− "astro/shiki/@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="],
3362−
3363− "astro/shiki/@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="],
3364−
3365− "astro/shiki/@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
3366−
33673358 "better-opn/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
33683359
33693360 "better-opn/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],