pushwork 2.0.0-a.sub.1 → 2.0.0-preview.2

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.
Files changed (234) hide show
  1. package/dist/branches.d.ts +20 -0
  2. package/dist/branches.d.ts.map +1 -0
  3. package/dist/branches.js +111 -0
  4. package/dist/branches.js.map +1 -0
  5. package/dist/cli.d.ts +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +245 -270
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config.d.ts +17 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +84 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/fs-tree.d.ts +6 -0
  14. package/dist/fs-tree.d.ts.map +1 -0
  15. package/dist/fs-tree.js +99 -0
  16. package/dist/fs-tree.js.map +1 -0
  17. package/dist/ignore.d.ts +6 -0
  18. package/dist/ignore.d.ts.map +1 -0
  19. package/dist/ignore.js +74 -0
  20. package/dist/ignore.js.map +1 -0
  21. package/dist/index.d.ts +8 -4
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +35 -4
  24. package/dist/index.js.map +1 -1
  25. package/dist/log.d.ts +3 -0
  26. package/dist/log.d.ts.map +1 -0
  27. package/dist/log.js +14 -0
  28. package/dist/log.js.map +1 -0
  29. package/dist/pushwork.d.ts +129 -0
  30. package/dist/pushwork.d.ts.map +1 -0
  31. package/dist/pushwork.js +1062 -0
  32. package/dist/pushwork.js.map +1 -0
  33. package/dist/repo.d.ts +14 -0
  34. package/dist/repo.d.ts.map +1 -0
  35. package/dist/repo.js +60 -0
  36. package/dist/repo.js.map +1 -0
  37. package/dist/shapes/custom.d.ts +3 -0
  38. package/dist/shapes/custom.d.ts.map +1 -0
  39. package/dist/shapes/custom.js +57 -0
  40. package/dist/shapes/custom.js.map +1 -0
  41. package/dist/shapes/file.d.ts +20 -0
  42. package/dist/shapes/file.d.ts.map +1 -0
  43. package/dist/shapes/file.js +140 -0
  44. package/dist/shapes/file.js.map +1 -0
  45. package/dist/shapes/index.d.ts +10 -0
  46. package/dist/shapes/index.d.ts.map +1 -0
  47. package/dist/shapes/index.js +35 -0
  48. package/dist/shapes/index.js.map +1 -0
  49. package/dist/shapes/patchwork-folder.d.ts +3 -0
  50. package/dist/shapes/patchwork-folder.d.ts.map +1 -0
  51. package/dist/shapes/patchwork-folder.js +160 -0
  52. package/dist/shapes/patchwork-folder.js.map +1 -0
  53. package/dist/shapes/types.d.ts +38 -0
  54. package/dist/shapes/types.d.ts.map +1 -0
  55. package/dist/shapes/types.js +52 -0
  56. package/dist/shapes/types.js.map +1 -0
  57. package/dist/shapes/vfs.d.ts +3 -0
  58. package/dist/shapes/vfs.d.ts.map +1 -0
  59. package/dist/shapes/vfs.js +92 -0
  60. package/dist/shapes/vfs.js.map +1 -0
  61. package/dist/stash.d.ts +23 -0
  62. package/dist/stash.d.ts.map +1 -0
  63. package/dist/stash.js +118 -0
  64. package/dist/stash.js.map +1 -0
  65. package/dist/version.d.ts +11 -0
  66. package/dist/version.d.ts.map +1 -0
  67. package/dist/version.js +93 -0
  68. package/dist/version.js.map +1 -0
  69. package/package.json +19 -48
  70. package/patches/@automerge__automerge-repo@2.6.0-subduction.15.patch +26 -0
  71. package/.prettierrc +0 -9
  72. package/ARCHITECTURE-ACCORDING-TO-CLAUDE.md +0 -248
  73. package/CLAUDE.md +0 -141
  74. package/README.md +0 -221
  75. package/babel.config.js +0 -5
  76. package/dist/cli/commands.d.ts +0 -71
  77. package/dist/cli/commands.d.ts.map +0 -1
  78. package/dist/cli/commands.js +0 -794
  79. package/dist/cli/commands.js.map +0 -1
  80. package/dist/cli/index.d.ts +0 -2
  81. package/dist/cli/index.d.ts.map +0 -1
  82. package/dist/cli/index.js +0 -19
  83. package/dist/cli/index.js.map +0 -1
  84. package/dist/commands.d.ts +0 -61
  85. package/dist/commands.d.ts.map +0 -1
  86. package/dist/commands.js +0 -861
  87. package/dist/commands.js.map +0 -1
  88. package/dist/config/index.d.ts +0 -71
  89. package/dist/config/index.d.ts.map +0 -1
  90. package/dist/config/index.js +0 -314
  91. package/dist/config/index.js.map +0 -1
  92. package/dist/core/change-detection.d.ts +0 -80
  93. package/dist/core/change-detection.d.ts.map +0 -1
  94. package/dist/core/change-detection.js +0 -523
  95. package/dist/core/change-detection.js.map +0 -1
  96. package/dist/core/config.d.ts +0 -81
  97. package/dist/core/config.d.ts.map +0 -1
  98. package/dist/core/config.js +0 -258
  99. package/dist/core/config.js.map +0 -1
  100. package/dist/core/index.d.ts +0 -6
  101. package/dist/core/index.d.ts.map +0 -1
  102. package/dist/core/index.js +0 -6
  103. package/dist/core/index.js.map +0 -1
  104. package/dist/core/move-detection.d.ts +0 -34
  105. package/dist/core/move-detection.d.ts.map +0 -1
  106. package/dist/core/move-detection.js +0 -121
  107. package/dist/core/move-detection.js.map +0 -1
  108. package/dist/core/snapshot.d.ts +0 -105
  109. package/dist/core/snapshot.d.ts.map +0 -1
  110. package/dist/core/snapshot.js +0 -217
  111. package/dist/core/snapshot.js.map +0 -1
  112. package/dist/core/sync-engine.d.ts +0 -157
  113. package/dist/core/sync-engine.d.ts.map +0 -1
  114. package/dist/core/sync-engine.js +0 -1379
  115. package/dist/core/sync-engine.js.map +0 -1
  116. package/dist/types/config.d.ts +0 -99
  117. package/dist/types/config.d.ts.map +0 -1
  118. package/dist/types/config.js +0 -5
  119. package/dist/types/config.js.map +0 -1
  120. package/dist/types/documents.d.ts +0 -88
  121. package/dist/types/documents.d.ts.map +0 -1
  122. package/dist/types/documents.js +0 -20
  123. package/dist/types/documents.js.map +0 -1
  124. package/dist/types/index.d.ts +0 -4
  125. package/dist/types/index.d.ts.map +0 -1
  126. package/dist/types/index.js +0 -4
  127. package/dist/types/index.js.map +0 -1
  128. package/dist/types/snapshot.d.ts +0 -64
  129. package/dist/types/snapshot.d.ts.map +0 -1
  130. package/dist/types/snapshot.js +0 -2
  131. package/dist/types/snapshot.js.map +0 -1
  132. package/dist/utils/content-similarity.d.ts +0 -53
  133. package/dist/utils/content-similarity.d.ts.map +0 -1
  134. package/dist/utils/content-similarity.js +0 -155
  135. package/dist/utils/content-similarity.js.map +0 -1
  136. package/dist/utils/content.d.ts +0 -10
  137. package/dist/utils/content.d.ts.map +0 -1
  138. package/dist/utils/content.js +0 -31
  139. package/dist/utils/content.js.map +0 -1
  140. package/dist/utils/directory.d.ts +0 -24
  141. package/dist/utils/directory.d.ts.map +0 -1
  142. package/dist/utils/directory.js +0 -52
  143. package/dist/utils/directory.js.map +0 -1
  144. package/dist/utils/fs.d.ts +0 -74
  145. package/dist/utils/fs.d.ts.map +0 -1
  146. package/dist/utils/fs.js +0 -248
  147. package/dist/utils/fs.js.map +0 -1
  148. package/dist/utils/index.d.ts +0 -5
  149. package/dist/utils/index.d.ts.map +0 -1
  150. package/dist/utils/index.js +0 -5
  151. package/dist/utils/index.js.map +0 -1
  152. package/dist/utils/mime-types.d.ts +0 -13
  153. package/dist/utils/mime-types.d.ts.map +0 -1
  154. package/dist/utils/mime-types.js +0 -209
  155. package/dist/utils/mime-types.js.map +0 -1
  156. package/dist/utils/network-sync.d.ts +0 -36
  157. package/dist/utils/network-sync.d.ts.map +0 -1
  158. package/dist/utils/network-sync.js +0 -250
  159. package/dist/utils/network-sync.js.map +0 -1
  160. package/dist/utils/node-polyfills.d.ts +0 -9
  161. package/dist/utils/node-polyfills.d.ts.map +0 -1
  162. package/dist/utils/node-polyfills.js +0 -9
  163. package/dist/utils/node-polyfills.js.map +0 -1
  164. package/dist/utils/output.d.ts +0 -129
  165. package/dist/utils/output.d.ts.map +0 -1
  166. package/dist/utils/output.js +0 -368
  167. package/dist/utils/output.js.map +0 -1
  168. package/dist/utils/repo-factory.d.ts +0 -13
  169. package/dist/utils/repo-factory.d.ts.map +0 -1
  170. package/dist/utils/repo-factory.js +0 -46
  171. package/dist/utils/repo-factory.js.map +0 -1
  172. package/dist/utils/string-similarity.d.ts +0 -14
  173. package/dist/utils/string-similarity.d.ts.map +0 -1
  174. package/dist/utils/string-similarity.js +0 -39
  175. package/dist/utils/string-similarity.js.map +0 -1
  176. package/dist/utils/text-diff.d.ts +0 -37
  177. package/dist/utils/text-diff.d.ts.map +0 -1
  178. package/dist/utils/text-diff.js +0 -93
  179. package/dist/utils/text-diff.js.map +0 -1
  180. package/dist/utils/trace.d.ts +0 -19
  181. package/dist/utils/trace.d.ts.map +0 -1
  182. package/dist/utils/trace.js +0 -63
  183. package/dist/utils/trace.js.map +0 -1
  184. package/src/cli.ts +0 -442
  185. package/src/commands.ts +0 -1134
  186. package/src/core/change-detection.ts +0 -712
  187. package/src/core/config.ts +0 -313
  188. package/src/core/index.ts +0 -5
  189. package/src/core/move-detection.ts +0 -169
  190. package/src/core/snapshot.ts +0 -275
  191. package/src/core/sync-engine.ts +0 -1795
  192. package/src/index.ts +0 -4
  193. package/src/types/config.ts +0 -111
  194. package/src/types/documents.ts +0 -91
  195. package/src/types/index.ts +0 -3
  196. package/src/types/snapshot.ts +0 -67
  197. package/src/utils/content.ts +0 -34
  198. package/src/utils/directory.ts +0 -73
  199. package/src/utils/fs.ts +0 -297
  200. package/src/utils/index.ts +0 -4
  201. package/src/utils/mime-types.ts +0 -244
  202. package/src/utils/network-sync.ts +0 -319
  203. package/src/utils/node-polyfills.ts +0 -8
  204. package/src/utils/output.ts +0 -450
  205. package/src/utils/repo-factory.ts +0 -73
  206. package/src/utils/string-similarity.ts +0 -54
  207. package/src/utils/text-diff.ts +0 -101
  208. package/src/utils/trace.ts +0 -70
  209. package/test/integration/README.md +0 -328
  210. package/test/integration/clone-test.sh +0 -310
  211. package/test/integration/conflict-resolution-test.sh +0 -309
  212. package/test/integration/debug-both-nested.sh +0 -74
  213. package/test/integration/debug-concurrent-nested.sh +0 -87
  214. package/test/integration/debug-nested.sh +0 -73
  215. package/test/integration/deletion-behavior-test.sh +0 -487
  216. package/test/integration/deletion-sync-test-simple.sh +0 -193
  217. package/test/integration/deletion-sync-test.sh +0 -297
  218. package/test/integration/exclude-patterns.test.ts +0 -144
  219. package/test/integration/full-integration-test.sh +0 -363
  220. package/test/integration/fuzzer.test.ts +0 -818
  221. package/test/integration/in-memory-sync.test.ts +0 -830
  222. package/test/integration/init-sync.test.ts +0 -89
  223. package/test/integration/manual-sync-test.sh +0 -84
  224. package/test/integration/sync-deletion.test.ts +0 -280
  225. package/test/integration/sync-flow.test.ts +0 -291
  226. package/test/jest.setup.ts +0 -34
  227. package/test/run-tests.sh +0 -225
  228. package/test/unit/deletion-behavior.test.ts +0 -249
  229. package/test/unit/enhanced-mime-detection.test.ts +0 -244
  230. package/test/unit/snapshot.test.ts +0 -404
  231. package/test/unit/sync-convergence.test.ts +0 -298
  232. package/test/unit/sync-timing.test.ts +0 -134
  233. package/test/unit/utils.test.ts +0 -366
  234. package/tsconfig.json +0 -23
@@ -1,134 +0,0 @@
1
- import * as fs from "fs/promises";
2
- import * as path from "path";
3
- import { tmpdir } from "os";
4
-
5
- describe("Sync Timing Analysis", () => {
6
- let testDir: string;
7
-
8
- beforeEach(async () => {
9
- testDir = await fs.mkdtemp(path.join(tmpdir(), "sync-timing-"));
10
- });
11
-
12
- afterEach(async () => {
13
- await fs.rm(testDir, { recursive: true, force: true });
14
- });
15
-
16
- describe("File Operation Timing", () => {
17
- it("should measure rapid file operations timing", async () => {
18
- const startTime = Date.now();
19
-
20
- // Simulate rapid file operations similar to sync
21
- const promises: Promise<void>[] = [];
22
- for (let i = 0; i < 10; i++) {
23
- promises.push(
24
- fs.writeFile(path.join(testDir, `file${i}.txt`), `content${i}`)
25
- );
26
- }
27
-
28
- await Promise.all(promises);
29
- const totalTime = Date.now() - startTime;
30
-
31
- // Verify all files exist
32
- const files = await fs.readdir(testDir);
33
- expect(files).toHaveLength(10);
34
-
35
- // This test shows us baseline file operation timing
36
- expect(totalTime).toBeLessThan(1000); // Should be fast for local operations
37
- });
38
-
39
- it("should test file operation atomicity", async () => {
40
- const filePath = path.join(testDir, "test.txt");
41
-
42
- // Write initial content
43
- await fs.writeFile(filePath, "initial content");
44
-
45
- // Rapid successive writes to same file
46
- const writes: Promise<void>[] = [];
47
- for (let i = 0; i < 5; i++) {
48
- writes.push(fs.writeFile(filePath, `updated content ${i}`));
49
- }
50
-
51
- await Promise.all(writes);
52
-
53
- // Check final content (should be one of the updates)
54
- const finalContent = await fs.readFile(filePath, "utf8");
55
- expect(finalContent).toMatch(/updated content \d/);
56
- });
57
- });
58
-
59
- describe("Sync Completion Scenarios", () => {
60
- it("should simulate the need for sync completion detection", async () => {
61
- // This test simulates what might happen with network sync
62
- // where we need to wait for operations to complete
63
-
64
- const results: { operation: string; time: number }[] = [];
65
-
66
- // Simulate "local" operations (fast)
67
- const localStart = Date.now();
68
- await fs.writeFile(path.join(testDir, "local.txt"), "local content");
69
- const localTime = Date.now() - localStart;
70
- results.push({ operation: "local write", time: localTime });
71
-
72
- // Simulate "network" operations (slower with artificial delay)
73
- const networkStart = Date.now();
74
- await new Promise((resolve) => setTimeout(resolve, 50)); // 50ms delay
75
- await fs.writeFile(path.join(testDir, "network.txt"), "network content");
76
- const networkTime = Date.now() - networkStart;
77
- results.push({ operation: "network write", time: networkTime });
78
-
79
- // This demonstrates why we might need to wait for slower operations
80
- expect(networkTime).toBeGreaterThan(localTime);
81
- expect(networkTime).toBeGreaterThan(40); // Should include our delay
82
- });
83
-
84
- it("should test what happens without proper completion waiting", async () => {
85
- // Simulate starting an operation but not waiting for it
86
- const promises: Promise<void>[] = [];
87
-
88
- // Start operations without awaiting
89
- for (let i = 0; i < 3; i++) {
90
- promises.push(
91
- (async () => {
92
- await new Promise((resolve) => setTimeout(resolve, 10 * i)); // Varying delays
93
- await fs.writeFile(
94
- path.join(testDir, `async${i}.txt`),
95
- `content${i}`
96
- );
97
- })()
98
- );
99
- }
100
-
101
- // Check immediately (before operations complete)
102
- const filesImmediate = await fs.readdir(testDir);
103
-
104
- // Now wait for operations to complete
105
- await Promise.all(promises);
106
-
107
- // Check after completion
108
- const filesAfter = await fs.readdir(testDir);
109
-
110
- // This shows the difference between checking immediately vs waiting
111
- expect(filesAfter.length).toBeGreaterThanOrEqual(filesImmediate.length);
112
- expect(filesAfter).toHaveLength(3);
113
- });
114
- });
115
-
116
- describe("Potential Race Conditions", () => {
117
- it("should test for potential race conditions in file operations", async () => {
118
- const sharedFile = path.join(testDir, "shared.txt");
119
-
120
- // Multiple operations on the same file
121
- const operations = [
122
- fs.writeFile(sharedFile, "operation1"),
123
- fs.writeFile(sharedFile, "operation2"),
124
- fs.writeFile(sharedFile, "operation3"),
125
- ];
126
-
127
- await Promise.all(operations);
128
-
129
- // Only one operation should "win"
130
- const content = await fs.readFile(sharedFile, "utf8");
131
- expect(["operation1", "operation2", "operation3"]).toContain(content);
132
- });
133
- });
134
- });
@@ -1,366 +0,0 @@
1
- import * as fs from "fs/promises";
2
- import * as path from "path";
3
- import * as tmp from "tmp";
4
- import {
5
- pathExists,
6
- getFileSystemEntry,
7
- isTextFile,
8
- readFileContent,
9
- writeFileContent,
10
- ensureDirectoryExists,
11
- removePath,
12
- listDirectory,
13
- calculateContentHash,
14
- getMimeType,
15
- getFileExtension,
16
- normalizePath,
17
- getRelativePath,
18
- } from "../../src/utils/fs";
19
- import { FileType } from "../../src/types";
20
-
21
- describe("File System Utilities", () => {
22
- let tmpDir: string;
23
- let cleanup: () => void;
24
-
25
- beforeEach(() => {
26
- const tmpObj = tmp.dirSync({ unsafeCleanup: true });
27
- tmpDir = tmpObj.name;
28
- cleanup = tmpObj.removeCallback;
29
- });
30
-
31
- afterEach(() => {
32
- cleanup();
33
- });
34
-
35
- describe("pathExists", () => {
36
- it("should return true for existing files", async () => {
37
- const filePath = path.join(tmpDir, "test.txt");
38
- await fs.writeFile(filePath, "test content");
39
-
40
- expect(await pathExists(filePath)).toBe(true);
41
- });
42
-
43
- it("should return false for non-existing files", async () => {
44
- const filePath = path.join(tmpDir, "nonexistent.txt");
45
-
46
- expect(await pathExists(filePath)).toBe(false);
47
- });
48
-
49
- it("should return true for existing directories", async () => {
50
- expect(await pathExists(tmpDir)).toBe(true);
51
- });
52
- });
53
-
54
- describe("getFileSystemEntry", () => {
55
- it("should return metadata for files", async () => {
56
- const filePath = path.join(tmpDir, "test.txt");
57
- await fs.writeFile(filePath, "test content");
58
-
59
- const entry = await getFileSystemEntry(filePath);
60
-
61
- expect(entry).not.toBeNull();
62
- expect(entry?.path).toBe(filePath);
63
- expect(entry?.type).toBe(FileType.TEXT);
64
- expect(entry?.size).toBe(12); // 'test content'.length
65
- expect(entry?.mtime).toBeDefined();
66
- expect(entry?.mtime.getTime()).toBeGreaterThan(0);
67
- expect(typeof entry?.mtime.getTime()).toBe("number");
68
- });
69
-
70
- it("should return metadata for directories", async () => {
71
- const dirPath = path.join(tmpDir, "subdir");
72
- await fs.mkdir(dirPath);
73
-
74
- const entry = await getFileSystemEntry(dirPath);
75
-
76
- expect(entry).not.toBeNull();
77
- expect(entry?.path).toBe(dirPath);
78
- expect(entry?.type).toBe(FileType.DIRECTORY);
79
- });
80
-
81
- it("should return null for non-existing paths", async () => {
82
- const entry = await getFileSystemEntry(path.join(tmpDir, "nonexistent"));
83
- expect(entry).toBeNull();
84
- });
85
- });
86
-
87
- describe("isTextFile", () => {
88
- it("should detect text files by extension", async () => {
89
- const filePath = path.join(tmpDir, "test.txt");
90
- await fs.writeFile(filePath, "text content");
91
-
92
- expect(await isTextFile(filePath)).toBe(true);
93
- });
94
-
95
- it("should detect JSON files as text", async () => {
96
- const filePath = path.join(tmpDir, "test.json");
97
- await fs.writeFile(filePath, '{"key": "value"}');
98
-
99
- expect(await isTextFile(filePath)).toBe(true);
100
- });
101
-
102
- it("should detect binary files by content", async () => {
103
- const filePath = path.join(tmpDir, "test.bin");
104
- const binaryContent = Buffer.from([0x00, 0x01, 0x02, 0x03]);
105
- await fs.writeFile(filePath, binaryContent);
106
-
107
- expect(await isTextFile(filePath)).toBe(false);
108
- });
109
- });
110
-
111
- describe("readFileContent", () => {
112
- it("should read text files as strings", async () => {
113
- const filePath = path.join(tmpDir, "test.txt");
114
- const content = "Hello, world!";
115
- await fs.writeFile(filePath, content);
116
-
117
- const result = await readFileContent(filePath);
118
-
119
- expect(typeof result).toBe("string");
120
- expect(result).toBe(content);
121
- });
122
-
123
- it("should read TypeScript files as strings", async () => {
124
- const filePath = path.join(tmpDir, "component.ts");
125
- const content = "interface User { name: string; age: number; }";
126
- await fs.writeFile(filePath, content);
127
-
128
- const result = await readFileContent(filePath);
129
-
130
- expect(typeof result).toBe("string");
131
- expect(result).toBe(content);
132
- });
133
-
134
- it("should read TSX files as strings", async () => {
135
- const filePath = path.join(tmpDir, "Component.tsx");
136
- const content = "export const App = () => <div>Hello World</div>;";
137
- await fs.writeFile(filePath, content);
138
-
139
- const result = await readFileContent(filePath);
140
-
141
- expect(typeof result).toBe("string");
142
- expect(result).toBe(content);
143
- });
144
-
145
- it("should read Vue files as strings", async () => {
146
- const filePath = path.join(tmpDir, "App.vue");
147
- const content = "<template><div>{{ message }}</div></template>";
148
- await fs.writeFile(filePath, content);
149
-
150
- const result = await readFileContent(filePath);
151
-
152
- expect(typeof result).toBe("string");
153
- expect(result).toBe(content);
154
- });
155
-
156
- it("should read SCSS files as strings", async () => {
157
- const filePath = path.join(tmpDir, "styles.scss");
158
- const content = "$primary: #007bff; .btn { color: $primary; }";
159
- await fs.writeFile(filePath, content);
160
-
161
- const result = await readFileContent(filePath);
162
-
163
- expect(typeof result).toBe("string");
164
- expect(result).toBe(content);
165
- });
166
-
167
- it("should read binary files as Uint8Array", async () => {
168
- const filePath = path.join(tmpDir, "test.bin");
169
- const binaryContent = Buffer.from([0x00, 0x01, 0x02, 0x03]);
170
- await fs.writeFile(filePath, binaryContent);
171
-
172
- const result = await readFileContent(filePath);
173
-
174
- expect(result).toBeInstanceOf(Uint8Array);
175
- expect(Array.from(result as Uint8Array)).toEqual([
176
- 0x00, 0x01, 0x02, 0x03,
177
- ]);
178
- });
179
- });
180
-
181
- describe("writeFileContent", () => {
182
- it("should write string content to files", async () => {
183
- const filePath = path.join(tmpDir, "output.txt");
184
- const content = "Test content";
185
-
186
- await writeFileContent(filePath, content);
187
-
188
- const written = await fs.readFile(filePath, "utf8");
189
- expect(written).toBe(content);
190
- });
191
-
192
- it("should write binary content to files", async () => {
193
- const filePath = path.join(tmpDir, "output.bin");
194
- const content = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
195
-
196
- await writeFileContent(filePath, content);
197
-
198
- const written = await fs.readFile(filePath);
199
- expect(Array.from(written)).toEqual([0x00, 0x01, 0x02, 0x03]);
200
- });
201
-
202
- it("should create directories if they don't exist", async () => {
203
- const filePath = path.join(tmpDir, "nested", "deep", "file.txt");
204
-
205
- await writeFileContent(filePath, "content");
206
-
207
- expect(await pathExists(filePath)).toBe(true);
208
- expect(await fs.readFile(filePath, "utf8")).toBe("content");
209
- });
210
- });
211
-
212
- describe("ensureDirectoryExists", () => {
213
- it("should create directories recursively", async () => {
214
- const dirPath = path.join(tmpDir, "nested", "deep", "directory");
215
-
216
- await ensureDirectoryExists(dirPath);
217
-
218
- expect(await pathExists(dirPath)).toBe(true);
219
- const stats = await fs.stat(dirPath);
220
- expect(stats.isDirectory()).toBe(true);
221
- });
222
-
223
- it("should not fail if directory already exists", async () => {
224
- await ensureDirectoryExists(tmpDir);
225
- await ensureDirectoryExists(tmpDir); // Should not throw
226
-
227
- expect(await pathExists(tmpDir)).toBe(true);
228
- });
229
- });
230
-
231
- describe("removePath", () => {
232
- it("should remove files", async () => {
233
- const filePath = path.join(tmpDir, "toremove.txt");
234
- await fs.writeFile(filePath, "content");
235
-
236
- await removePath(filePath);
237
-
238
- expect(await pathExists(filePath)).toBe(false);
239
- });
240
-
241
- it("should remove directories recursively", async () => {
242
- const dirPath = path.join(tmpDir, "toremove");
243
- const filePath = path.join(dirPath, "file.txt");
244
- await fs.mkdir(dirPath);
245
- await fs.writeFile(filePath, "content");
246
-
247
- await removePath(dirPath);
248
-
249
- expect(await pathExists(dirPath)).toBe(false);
250
- });
251
-
252
- it("should not fail if path doesn't exist", async () => {
253
- const nonExistentPath = path.join(tmpDir, "nonexistent");
254
-
255
- await removePath(nonExistentPath); // Should not throw
256
-
257
- expect(await pathExists(nonExistentPath)).toBe(false);
258
- });
259
- });
260
-
261
- describe("listDirectory", () => {
262
- beforeEach(async () => {
263
- // Create test directory structure
264
- await fs.mkdir(path.join(tmpDir, "subdir"));
265
- await fs.writeFile(path.join(tmpDir, "file1.txt"), "content1");
266
- await fs.writeFile(path.join(tmpDir, "file2.txt"), "content2");
267
- await fs.writeFile(path.join(tmpDir, "subdir", "file3.txt"), "content3");
268
- });
269
-
270
- it("should list directory contents non-recursively", async () => {
271
- const entries = await listDirectory(tmpDir, false);
272
-
273
- const names = entries.map((e) => path.basename(e.path)).sort();
274
- expect(names).toEqual(["file1.txt", "file2.txt", "subdir"]);
275
- });
276
-
277
- it("should list directory contents recursively", async () => {
278
- const entries = await listDirectory(tmpDir, true);
279
-
280
- const relativePaths = entries
281
- .map((e) => path.relative(tmpDir, e.path))
282
- .sort();
283
-
284
- expect(relativePaths).toContain("file1.txt");
285
- expect(relativePaths).toContain("file2.txt");
286
- expect(relativePaths).toContain("subdir");
287
- expect(relativePaths).toContain(path.join("subdir", "file3.txt"));
288
- });
289
- });
290
-
291
- describe("calculateContentHash", () => {
292
- it("should generate consistent hashes for string content", async () => {
293
- const content = "test content";
294
-
295
- const hash1 = await calculateContentHash(content);
296
- const hash2 = await calculateContentHash(content);
297
-
298
- expect(hash1).toBe(hash2);
299
- expect(hash1).toHaveLength(64); // SHA-256 hex string
300
- });
301
-
302
- it("should generate consistent hashes for binary content", async () => {
303
- const content = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
304
-
305
- const hash1 = await calculateContentHash(content);
306
- const hash2 = await calculateContentHash(content);
307
-
308
- expect(hash1).toBe(hash2);
309
- expect(hash1).toHaveLength(64);
310
- });
311
-
312
- it("should generate different hashes for different content", async () => {
313
- const content1 = "content1";
314
- const content2 = "content2";
315
-
316
- const hash1 = await calculateContentHash(content1);
317
- const hash2 = await calculateContentHash(content2);
318
-
319
- expect(hash1).not.toBe(hash2);
320
- });
321
- });
322
-
323
- describe("getMimeType", () => {
324
- it("should return correct MIME type for text files", () => {
325
- expect(getMimeType("test.txt")).toBe("text/plain");
326
- expect(getMimeType("test.json")).toBe("application/json");
327
- expect(getMimeType("test.html")).toBe("text/html");
328
- });
329
-
330
- it("should return default MIME type for unknown extensions", () => {
331
- expect(getMimeType("test.unknown")).toBe("application/octet-stream");
332
- });
333
- });
334
-
335
- describe("getFileExtension", () => {
336
- it("should extract file extensions", () => {
337
- expect(getFileExtension("test.txt")).toBe("txt");
338
- expect(getFileExtension("archive.tar.gz")).toBe("gz");
339
- expect(getFileExtension("noextension")).toBe("");
340
- });
341
- });
342
-
343
- describe("normalizePath", () => {
344
- it("should normalize path separators", () => {
345
- expect(normalizePath("path\\to\\file")).toBe("path/to/file");
346
- expect(normalizePath("path/to/file")).toBe("path/to/file");
347
- expect(normalizePath("path//to//file")).toBe("path/to/file");
348
- });
349
- });
350
-
351
- describe("getRelativePath", () => {
352
- it("should return relative paths", () => {
353
- const base = "/home/user/project";
354
- const target = "/home/user/project/src/file.txt";
355
-
356
- expect(getRelativePath(base, target)).toBe("src/file.txt");
357
- });
358
-
359
- it("should handle same directory", () => {
360
- const base = "/home/user/project";
361
- const target = "/home/user/project";
362
-
363
- expect(getRelativePath(base, target)).toBe(".");
364
- });
365
- });
366
- });
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "nodenext",
5
- "moduleResolution": "nodenext",
6
- "lib": ["ES2020"],
7
- "outDir": "./dist",
8
- "rootDir": "./src",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "sourceMap": true,
16
- "resolveJsonModule": true,
17
- "types": ["node", "jest"],
18
- "noUnusedLocals": true,
19
- "noUnusedParameters": true
20
- },
21
- "include": ["src/**/*"],
22
- "exclude": ["node_modules", "dist", "test"]
23
- }