@youtyan/code-viewer 0.1.30 → 0.1.32

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.
@@ -11,7 +11,7 @@ import {
11
11
  readFileSync as readFileSync2,
12
12
  realpathSync,
13
13
  renameSync,
14
- statSync,
14
+ statSync as statSync2,
15
15
  unlinkSync,
16
16
  watch,
17
17
  writeFileSync
@@ -106,7 +106,8 @@ import {
106
106
  existsSync,
107
107
  lstatSync as lstatSync2,
108
108
  readdirSync,
109
- readFileSync
109
+ readFileSync,
110
+ statSync
110
111
  } from "node:fs";
111
112
  import { join as join2 } from "node:path";
112
113
 
@@ -188,9 +189,13 @@ function startServer(options) {
188
189
  const request = nodeRequestToWeb(req, options.hostname, server.address());
189
190
  const response = await options.fetch(request);
190
191
  await writeWebResponse(res, response);
191
- } catch {
192
- if (!res.headersSent)
193
- res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
192
+ } catch (error) {
193
+ console.error("[code-viewer] request error:", req.method, req.url, error);
194
+ if (res.headersSent || res.writableEnded) {
195
+ res.destroy(error instanceof Error ? error : undefined);
196
+ return;
197
+ }
198
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
194
199
  res.end("internal server error");
195
200
  }
196
201
  });
@@ -203,7 +208,18 @@ function startServer(options) {
203
208
  });
204
209
  const address = server.address();
205
210
  const port = typeof address === "object" && address ? address.port : options.port;
206
- resolve({ port });
211
+ resolve({
212
+ port,
213
+ close: () => new Promise((resolveClose, rejectClose) => {
214
+ server.close((error) => {
215
+ if (error)
216
+ rejectClose(error);
217
+ else
218
+ resolveClose();
219
+ });
220
+ server.closeAllConnections?.();
221
+ })
222
+ });
207
223
  });
208
224
  });
209
225
  }
@@ -752,26 +768,36 @@ function listTree(ref, path, cwd, options = {}) {
752
768
  };
753
769
  }
754
770
  function untrackedMeta(cwd) {
755
- return untracked(cwd).map((path) => {
771
+ return untracked(cwd).flatMap((path) => {
756
772
  const full = join2(cwd, path);
757
773
  let binary = false;
758
774
  let lines = 0;
759
- if (existsSync(full)) {
775
+ let fileExists = false;
776
+ try {
777
+ fileExists = existsSync(full) && statSync(full).isFile();
778
+ } catch {
779
+ fileExists = false;
780
+ }
781
+ if (fileExists) {
760
782
  const data = readFileSync(full);
761
783
  const probe = data.subarray(0, 8192);
762
784
  binary = probe.includes(0);
763
785
  if (!binary)
764
786
  lines = data.toString("utf8").split(`
765
787
  `).length - 1;
788
+ } else {
789
+ return [];
766
790
  }
767
- return {
768
- path,
769
- status: "A",
770
- additions: binary ? 0 : lines,
771
- deletions: 0,
772
- binary,
773
- untracked: true
774
- };
791
+ return [
792
+ {
793
+ path,
794
+ status: "A",
795
+ additions: binary ? 0 : lines,
796
+ deletions: 0,
797
+ binary,
798
+ untracked: true
799
+ }
800
+ ];
775
801
  });
776
802
  }
777
803
  function fileMeta(args, cwd, includeUntracked = false) {
@@ -1967,7 +1993,7 @@ function worktreeFileMetadata(path, knownSize) {
1967
1993
  if (!full)
1968
1994
  return {};
1969
1995
  try {
1970
- const stat = statSync(full);
1996
+ const stat = statSync2(full);
1971
1997
  return {
1972
1998
  size: knownSize ?? stat.size,
1973
1999
  created_at: isoDate(stat.birthtimeMs),
@@ -1992,7 +2018,7 @@ function directoryMetadata(target, path) {
1992
2018
  if (!full)
1993
2019
  return {};
1994
2020
  try {
1995
- const stat = statSync(full);
2021
+ const stat = statSync2(full);
1996
2022
  return {
1997
2023
  created_at: isoDate(stat.birthtimeMs),
1998
2024
  updated_at: isoDate(stat.mtimeMs)
@@ -2319,7 +2345,7 @@ function handleFileDiff(url) {
2319
2345
  }
2320
2346
  function worktreeLineIndexSignature(full) {
2321
2347
  try {
2322
- const stat = statSync(full);
2348
+ const stat = statSync2(full);
2323
2349
  return `size:${stat.size}|mtime:${stat.mtimeMs}|ctime:${stat.ctimeMs}|ino:${stat.ino || 0}`;
2324
2350
  } catch {
2325
2351
  return null;
@@ -2335,7 +2361,7 @@ async function getWorktreeLineIndex(full) {
2335
2361
  lineIndexCache.set(full, cached);
2336
2362
  return cached.index;
2337
2363
  }
2338
- const stat = statSync(full);
2364
+ const stat = statSync2(full);
2339
2365
  if (stat.size > LINE_INDEX_MAX_FILE_BYTES)
2340
2366
  return null;
2341
2367
  const index = await buildLineOffsetIndexFromStream(fileReadableStream(full), stat.size);
@@ -2580,7 +2606,7 @@ function rawFileSize(path, ref) {
2580
2606
  if (!full)
2581
2607
  return null;
2582
2608
  try {
2583
- return statSync(full).size;
2609
+ return statSync2(full).size;
2584
2610
  } catch {
2585
2611
  return null;
2586
2612
  }
@@ -2679,7 +2705,7 @@ async function handleUploadFiles(req) {
2679
2705
  const realDir = safeOpenWorktreePath(dir);
2680
2706
  if (!realDir)
2681
2707
  return text("not found", 404);
2682
- const stats = statSync(realDir);
2708
+ const stats = statSync2(realDir);
2683
2709
  if (!stats.isDirectory())
2684
2710
  return text("not a directory", 400);
2685
2711
  const files = form.getAll("files").filter((item) => item instanceof File);
@@ -2927,7 +2953,7 @@ async function handleOpenPath(req) {
2927
2953
  const target = safeOpenWorktreePath(targetPath);
2928
2954
  if (!target)
2929
2955
  return text("not found", 404);
2930
- const stats = statSync(target);
2956
+ const stats = statSync2(target);
2931
2957
  if (!stats.isDirectory())
2932
2958
  return text("not a directory", 400);
2933
2959
  openOsPath(target);
@@ -3012,7 +3038,7 @@ async function handleCreateDirectory(req) {
3012
3038
  const parent = safeOpenWorktreePath(dir);
3013
3039
  if (!parent)
3014
3040
  return text("not found", 404);
3015
- const stats = statSync(parent);
3041
+ const stats = statSync2(parent);
3016
3042
  if (!stats.isDirectory())
3017
3043
  return text("not a directory", 400);
3018
3044
  const targetPath = dir ? `${dir}/${name}` : name;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youtyan/code-viewer",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "Local browser-based code and git diff viewer",
5
5
  "type": "module",
6
6
  "bin": {
package/web/mermaid.js CHANGED
@@ -1930,8 +1930,7 @@ function createDOMPurify() {
1930
1930
  ;
1931
1931
  else if (value) {
1932
1932
  return false;
1933
- } else
1934
- ;
1933
+ }
1935
1934
  return true;
1936
1935
  };
1937
1936
  const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ["annotation-xml", "color-profile", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "missing-glyph"]);
@@ -78802,7 +78801,7 @@ var require_layout_base = __commonJS((exports, module) => {
78802
78801
  result[2] = p2x;
78803
78802
  result[3] = topLeftBy;
78804
78803
  return false;
78805
- } else {}
78804
+ }
78806
78805
  } else if (p1y === p2y) {
78807
78806
  if (p1x > p2x) {
78808
78807
  result[0] = topLeftAx;
@@ -78816,7 +78815,7 @@ var require_layout_base = __commonJS((exports, module) => {
78816
78815
  result[2] = topLeftBx;
78817
78816
  result[3] = p2y;
78818
78817
  return false;
78819
- } else {}
78818
+ }
78820
78819
  } else {
78821
78820
  var slopeA = rectA.height / rectA.width;
78822
78821
  var slopeB = rectB.height / rectB.width;
@@ -109930,7 +109929,7 @@ class DefaultDocumentBuilder {
109930
109929
  options: options2,
109931
109930
  result: state2?.result
109932
109931
  });
109933
- } else {}
109932
+ }
109934
109933
  }
109935
109934
  }
109936
109935
  async runCancelable(documents, targetState, cancelToken, callback) {
@@ -143202,7 +143201,7 @@ var require_layout_base2 = __commonJS((exports, module) => {
143202
143201
  result[2] = p2x;
143203
143202
  result[3] = topLeftBy;
143204
143203
  return false;
143205
- } else {}
143204
+ }
143206
143205
  } else if (p1y === p2y) {
143207
143206
  if (p1x > p2x) {
143208
143207
  result[0] = topLeftAx;
@@ -143216,7 +143215,7 @@ var require_layout_base2 = __commonJS((exports, module) => {
143216
143215
  result[2] = topLeftBx;
143217
143216
  result[3] = p2y;
143218
143217
  return false;
143219
- } else {}
143218
+ }
143220
143219
  } else {
143221
143220
  var slopeA = rectA.height / rectA.width;
143222
143221
  var slopeB = rectB.height / rectB.width;
package/web/shiki.js CHANGED
@@ -7836,7 +7836,7 @@ var RuleFactory = class _RuleFactory {
7836
7836
  let localIncludedRule = repository[reference.ruleName];
7837
7837
  if (localIncludedRule) {
7838
7838
  ruleId = _RuleFactory.getCompiledRuleId(localIncludedRule, helper, repository);
7839
- } else {}
7839
+ }
7840
7840
  break;
7841
7841
  case 3:
7842
7842
  case 4:
@@ -7848,11 +7848,11 @@ var RuleFactory = class _RuleFactory {
7848
7848
  let externalIncludedRule = externalGrammar.repository[externalGrammarInclude];
7849
7849
  if (externalIncludedRule) {
7850
7850
  ruleId = _RuleFactory.getCompiledRuleId(externalIncludedRule, helper, externalGrammar.repository);
7851
- } else {}
7851
+ }
7852
7852
  } else {
7853
7853
  ruleId = _RuleFactory.getCompiledRuleId(externalGrammar.repository.$self, helper, externalGrammar.repository);
7854
7854
  }
7855
- } else {}
7855
+ }
7856
7856
  break;
7857
7857
  }
7858
7858
  } else {