omp-plugin-duplicate-detector 0.1.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/README.md +117 -0
- package/dist/detector-worker.js +13897 -0
- package/package.json +105 -0
- package/src/config-loader.ts +336 -0
- package/src/coordinator.ts +536 -0
- package/src/detector-worker.ts +828 -0
- package/src/disk-cache.ts +703 -0
- package/src/duplicate-ledger.ts +144 -0
- package/src/index.ts +807 -0
- package/src/jscpd-engine.ts +797 -0
- package/src/project-state.ts +129 -0
- package/src/source-aware-index.ts +919 -0
- package/src/test-detector.ts +337 -0
- package/src/tui-notification.ts +464 -0
- package/src/worker-protocol.ts +330 -0
- package/types/global.d.ts +19 -0
- package/types/jscpd.d.ts +139 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import * as fsSync from "node:fs";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { getDefaultCacheDir } from "./disk-cache";
|
|
5
|
+
|
|
6
|
+
interface ProjectStateEntry {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
updatedAt?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ProjectsStateFile {
|
|
12
|
+
version: number;
|
|
13
|
+
projects: Record<string, ProjectStateEntry>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes a workspace project directory path to a canonical absolute path.
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeProjectPath(projectDir: string): string {
|
|
19
|
+
const resolved = path.resolve(projectDir);
|
|
20
|
+
try {
|
|
21
|
+
if (fsSync.existsSync(resolved)) {
|
|
22
|
+
return fsSync.realpathSync(resolved);
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
// Fall back to resolved path
|
|
26
|
+
}
|
|
27
|
+
return resolved;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the path to the persistent projects state JSON file.
|
|
32
|
+
*/
|
|
33
|
+
export function getProjectsStateFilePath(customCacheDir?: string): string {
|
|
34
|
+
const baseDir = customCacheDir ?? getDefaultCacheDir();
|
|
35
|
+
return path.join(baseDir, "projects.json");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Loads the persistent projects state file from disk.
|
|
40
|
+
* Returns default empty state if file does not exist or is corrupted.
|
|
41
|
+
*/
|
|
42
|
+
export async function loadProjectsState(
|
|
43
|
+
customCacheDir?: string,
|
|
44
|
+
): Promise<ProjectsStateFile> {
|
|
45
|
+
const filePath = getProjectsStateFilePath(customCacheDir);
|
|
46
|
+
try {
|
|
47
|
+
const file = Bun.file(filePath);
|
|
48
|
+
if (!(await file.exists())) {
|
|
49
|
+
return { version: 1, projects: {} };
|
|
50
|
+
}
|
|
51
|
+
const content = await file.text();
|
|
52
|
+
const parsed = JSON.parse(content);
|
|
53
|
+
if (
|
|
54
|
+
parsed &&
|
|
55
|
+
typeof parsed === "object" &&
|
|
56
|
+
parsed.projects !== null &&
|
|
57
|
+
typeof parsed.projects === "object" &&
|
|
58
|
+
!Array.isArray(parsed.projects)
|
|
59
|
+
) {
|
|
60
|
+
return {
|
|
61
|
+
version: typeof parsed.version === "number" ? parsed.version : 1,
|
|
62
|
+
projects: parsed.projects,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return { version: 1, projects: {} };
|
|
66
|
+
} catch {
|
|
67
|
+
return { version: 1, projects: {} };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Persists the projects state to disk atomically.
|
|
73
|
+
*/
|
|
74
|
+
export async function saveProjectsState(
|
|
75
|
+
state: ProjectsStateFile,
|
|
76
|
+
customCacheDir?: string,
|
|
77
|
+
): Promise<void> {
|
|
78
|
+
const filePath = getProjectsStateFilePath(customCacheDir);
|
|
79
|
+
const cacheDir = path.dirname(filePath);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
await fs.mkdir(cacheDir, { recursive: true });
|
|
83
|
+
const tempPath = `${filePath}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
84
|
+
const payload = JSON.stringify(state, null, 2);
|
|
85
|
+
await Bun.write(tempPath, payload);
|
|
86
|
+
await fs.rename(tempPath, filePath);
|
|
87
|
+
} catch {
|
|
88
|
+
// Fallback direct write if atomic rename fails
|
|
89
|
+
try {
|
|
90
|
+
await Bun.write(filePath, JSON.stringify(state, null, 2));
|
|
91
|
+
} catch {
|
|
92
|
+
// Fail open
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Checks whether duplicate detection is enabled for a given project directory.
|
|
99
|
+
* Defaults to true if no explicit setting has been configured for the project.
|
|
100
|
+
*/
|
|
101
|
+
export async function isProjectEnabled(
|
|
102
|
+
projectDir: string,
|
|
103
|
+
customCacheDir?: string,
|
|
104
|
+
): Promise<boolean> {
|
|
105
|
+
const normalized = normalizeProjectPath(projectDir);
|
|
106
|
+
const state = await loadProjectsState(customCacheDir);
|
|
107
|
+
const entry = state.projects[normalized];
|
|
108
|
+
if (entry && typeof entry.enabled === "boolean") {
|
|
109
|
+
return entry.enabled;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Sets whether duplicate detection is enabled or disabled for a given project directory.
|
|
116
|
+
*/
|
|
117
|
+
export async function setProjectEnabled(
|
|
118
|
+
projectDir: string,
|
|
119
|
+
enabled: boolean,
|
|
120
|
+
customCacheDir?: string,
|
|
121
|
+
): Promise<void> {
|
|
122
|
+
const normalized = normalizeProjectPath(projectDir);
|
|
123
|
+
const state = await loadProjectsState(customCacheDir);
|
|
124
|
+
state.projects[normalized] = {
|
|
125
|
+
enabled,
|
|
126
|
+
updatedAt: new Date().toISOString(),
|
|
127
|
+
};
|
|
128
|
+
await saveProjectsState(state, customCacheDir);
|
|
129
|
+
}
|