lody 0.63.2 → 0.64.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.
@@ -1,14 +1,14 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readFile, mkdir, writeFile, rename } from "node:fs/promises";
3
- import os__default from "node:os";
3
+ import os from "node:os";
4
4
  import path__default from "node:path";
5
5
  import process from "node:process";
6
- const reviewViewerVersion = "0.63.2";
6
+ const reviewViewerVersion = "0.64.0";
7
7
  const reviewViewerSha256 = "50ab599b652bdf4b959b539ea948454dd588703039bd4c5c037c7877ce10696f";
8
8
  const reviewViewerFileName = "standalone.html";
9
9
  const DEFAULT_CDN_BASES = ["https://cdn.jsdelivr.net/npm", "https://unpkg.com"];
10
10
  function cacheDir() {
11
- return path__default.join(os__default.homedir(), ".lody", "code-review-viewer");
11
+ return path__default.join(os.homedir(), ".lody", "code-review-viewer");
12
12
  }
13
13
  function cachePath() {
14
14
  return path__default.join(cacheDir(), `${reviewViewerVersion}.html`);
@@ -1,4 +1,4 @@
1
- import { c as computeLineCounts } from "./chunks/diff-line-counts-BLxwWP6r.js";
1
+ import { c as computeLineCounts } from "./chunks/diff-line-counts-ftjiViPL.js";
2
2
  import "node:child_process";
3
3
  import "node:fs";
4
4
  import "node:os";
@@ -0,0 +1,208 @@
1
+ import { opendir } from "node:fs/promises";
2
+ import path__default from "node:path";
3
+ import { K as buildCodeCollabFileIndexState, M as scanGitDirectoryEntries, a6 as joinWorkspacePath, a7 as isInsideGitWorktree, J as computeAllChanges, a8 as pathSegmentComparisonKey, O as closeDirectoryQuietly } from "./chunks/directory-handle-GsTHlZO7.js";
4
+ import "node:child_process";
5
+ import "node:util";
6
+ import "./chunks/diff-line-counts-ftjiViPL.js";
7
+ import "node:fs";
8
+ import "node:os";
9
+ const DEFAULT_IGNORED_DIRECTORY_NAMES = /* @__PURE__ */ new Set([
10
+ ".git",
11
+ "node_modules",
12
+ ".next",
13
+ "dist",
14
+ "build",
15
+ "target"
16
+ ]);
17
+ async function fileIndexScanWorker(input) {
18
+ if (input.kind === "full-state") {
19
+ return await computeFullFileIndexState(input);
20
+ }
21
+ const entries = await scanDirectoryEntries(input);
22
+ return { kind: "scan", entries: [...entries] };
23
+ }
24
+ async function computeFullFileIndexState(input) {
25
+ const startedAtMs = Date.now();
26
+ const allChangesResult = await resolveFullStateAllChanges(input);
27
+ if (allChangesResult.status !== "ok") {
28
+ return {
29
+ kind: "full-state",
30
+ status: "needs-provided-all-changes",
31
+ reason: allChangesResult.reason
32
+ };
33
+ }
34
+ const scanStartedAtMs = Date.now();
35
+ const fileTreeEntries = await scanDirectoryEntries({
36
+ directoryAbsolutePath: input.workspaceRoot,
37
+ directoryWorkspacePath: "",
38
+ maxRawTextBytes: input.maxRawTextBytes,
39
+ entryBudget: input.entryBudget,
40
+ recursive: true
41
+ });
42
+ const scanMs = Date.now() - scanStartedAtMs;
43
+ const fileTree = Object.fromEntries(fileTreeEntries);
44
+ const buildStartedAtMs = Date.now();
45
+ const fileIndex = buildCodeCollabFileIndexState(fileTree, allChangesResult.allChanges);
46
+ const buildMs = Date.now() - buildStartedAtMs;
47
+ return {
48
+ kind: "full-state",
49
+ status: "ok",
50
+ fileTreeEntries: [...fileTreeEntries],
51
+ allChanges: allChangesResult.allChanges,
52
+ fileIndex,
53
+ allChangesSource: allChangesResult.source,
54
+ changedPaths: Object.keys(allChangesResult.allChanges).length,
55
+ pathCount: Object.keys(fileIndex).length,
56
+ durationMs: Date.now() - startedAtMs,
57
+ scanMs,
58
+ allChangesMs: allChangesResult.allChangesMs,
59
+ buildMs
60
+ };
61
+ }
62
+ async function resolveFullStateAllChanges(input) {
63
+ if (input.providedAllChanges) {
64
+ return {
65
+ status: "ok",
66
+ source: input.providedAllChanges.source,
67
+ allChanges: input.providedAllChanges.state,
68
+ allChangesMs: input.providedAllChanges.computeMs
69
+ };
70
+ }
71
+ if (!await isInsideGitWorktree(input.workspaceRoot)) {
72
+ return { status: "needs-provided-all-changes", reason: "not-git" };
73
+ }
74
+ const allChangesStartedAtMs = Date.now();
75
+ const allChanges = await computeAllChanges(input.workspaceRoot, {
76
+ preferredBaseBranch: input.preferredBaseBranch
77
+ });
78
+ return {
79
+ status: "ok",
80
+ source: "git",
81
+ allChanges,
82
+ allChangesMs: Date.now() - allChangesStartedAtMs
83
+ };
84
+ }
85
+ async function scanDirectoryEntries(options) {
86
+ const gitEntries = await scanGitDirectoryEntries(options);
87
+ if (gitEntries) {
88
+ return gitEntries;
89
+ }
90
+ const entries = /* @__PURE__ */ new Map();
91
+ const queue = [
92
+ {
93
+ absolutePath: options.directoryAbsolutePath,
94
+ workspacePath: options.directoryWorkspacePath
95
+ }
96
+ ];
97
+ let remainingEntries = Math.max(0, options.entryBudget);
98
+ while (queue.length > 0 && remainingEntries > 0) {
99
+ const currentDirectory = queue.shift();
100
+ if (!currentDirectory) {
101
+ break;
102
+ }
103
+ const directoryEntries = await readDirectoryEntriesForScan(currentDirectory).catch(
104
+ (error) => {
105
+ if (currentDirectory.workspacePath === options.directoryWorkspacePath) {
106
+ throw error;
107
+ }
108
+ entries.set(currentDirectory.workspacePath, scanDirectoryReadErrorValue(error));
109
+ return null;
110
+ }
111
+ );
112
+ if (!directoryEntries) {
113
+ continue;
114
+ }
115
+ const collisionKeys = findDirectoryEntryCollisionKeys(directoryEntries);
116
+ for (const { entry, comparisonKey } of directoryEntries) {
117
+ if (remainingEntries <= 0) {
118
+ break;
119
+ }
120
+ const workspacePath = joinWorkspacePath(currentDirectory.workspacePath, entry.name);
121
+ const absolutePath = path__default.join(currentDirectory.absolutePath, entry.name);
122
+ const value = collisionKeys.has(comparisonKey) ? { kind: "skipped", reason: "path_conflict" } : classifyDirectoryEntry(entry);
123
+ if (value === void 0) {
124
+ continue;
125
+ }
126
+ entries.set(workspacePath, value);
127
+ remainingEntries -= 1;
128
+ if (options.recursive && isLazyDirectoryValue(value) && remainingEntries > 0) {
129
+ queue.push({ absolutePath, workspacePath });
130
+ }
131
+ }
132
+ }
133
+ return entries;
134
+ }
135
+ function scanDirectoryReadErrorValue(error) {
136
+ const code = errorCode(error);
137
+ if (code === "EACCES" || code === "EPERM") {
138
+ return { kind: "skipped", reason: "permission_denied" };
139
+ }
140
+ if (code === "ENOENT" || code === "ENOTDIR") {
141
+ return { kind: "skipped", reason: "not_found" };
142
+ }
143
+ return { kind: "skipped", reason: "transient_io" };
144
+ }
145
+ function errorCode(error) {
146
+ if (!error || typeof error !== "object" || !("code" in error)) {
147
+ return void 0;
148
+ }
149
+ const code = error.code;
150
+ return typeof code === "string" ? code : void 0;
151
+ }
152
+ async function readDirectoryEntriesForScan(directoryPath) {
153
+ const directory = await opendir(directoryPath.absolutePath);
154
+ try {
155
+ const directoryEntries = [];
156
+ for await (const entry of directory) {
157
+ if (entry.name === "." || entry.name === "..") {
158
+ continue;
159
+ }
160
+ directoryEntries.push({
161
+ entry,
162
+ comparisonKey: pathSegmentComparisonKey(entry.name)
163
+ });
164
+ }
165
+ return directoryEntries.sort((left, right) => {
166
+ const keyOrder = left.comparisonKey.localeCompare(right.comparisonKey);
167
+ return keyOrder === 0 ? left.entry.name.localeCompare(right.entry.name) : keyOrder;
168
+ });
169
+ } finally {
170
+ await closeDirectoryQuietly(directory);
171
+ }
172
+ }
173
+ function classifyDirectoryEntry(entry) {
174
+ if (entry.isDirectory()) {
175
+ return DEFAULT_IGNORED_DIRECTORY_NAMES.has(entry.name) ? void 0 : { kind: "lazy" };
176
+ }
177
+ if (entry.isSymbolicLink()) {
178
+ return { kind: "skipped", reason: "symlink" };
179
+ }
180
+ if (!entry.isFile()) {
181
+ return { kind: "skipped", reason: "special" };
182
+ }
183
+ return true;
184
+ }
185
+ function findDirectoryEntryCollisionKeys(entries) {
186
+ const namesByKey = /* @__PURE__ */ new Map();
187
+ for (const { entry, comparisonKey } of entries) {
188
+ const names = namesByKey.get(comparisonKey);
189
+ if (names) {
190
+ names.add(entry.name);
191
+ } else {
192
+ namesByKey.set(comparisonKey, /* @__PURE__ */ new Set([entry.name]));
193
+ }
194
+ }
195
+ const collisionKeys = /* @__PURE__ */ new Set();
196
+ for (const [comparisonKey, names] of namesByKey) {
197
+ if (names.size > 1) {
198
+ collisionKeys.add(comparisonKey);
199
+ }
200
+ }
201
+ return collisionKeys;
202
+ }
203
+ function isLazyDirectoryValue(value) {
204
+ return value !== void 0 && value !== true && value.kind === "lazy";
205
+ }
206
+ export {
207
+ fileIndexScanWorker as default
208
+ };