@noya-app/noya-file-explorer 0.0.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.
@@ -0,0 +1,348 @@
1
+ import { MediaMap } from "@noya-app/noya-schemas";
2
+ import { expect, it } from "bun:test";
3
+ import { moveMediaInsideFolder } from "../utils/files";
4
+ import {
5
+ createMediaAsset,
6
+ createMediaFolder,
7
+ createMediaItemTree,
8
+ rootMediaItem,
9
+ } from "../utils/mediaItemTree";
10
+
11
+ it("should move an item into a target folder", () => {
12
+ // Create a folder structure:
13
+ // Root
14
+ // ├── Folder 1
15
+ // └── Asset 1
16
+ const folder1 = createMediaFolder();
17
+ const asset1 = createMediaAsset({
18
+ assetId: "asset1",
19
+ });
20
+ const media: MediaMap = {
21
+ folder1,
22
+ asset1,
23
+ };
24
+ const tree = createMediaItemTree(media);
25
+
26
+ // Move Asset 1 into Folder 1
27
+ const result = moveMediaInsideFolder({
28
+ sourceItemIds: [asset1.id],
29
+ targetItemId: folder1.id,
30
+ media,
31
+ tree,
32
+ });
33
+
34
+ // Asset 1 should now have Folder 1 as its parent
35
+ const movedAsset = result["folder1/asset1"];
36
+ expect(movedAsset).toEqual(asset1);
37
+
38
+ // Folder 1 should remain unchanged
39
+ const folder = result["folder1"];
40
+ expect(folder).toEqual(folder1);
41
+ });
42
+
43
+ it("should move an item to the root level", () => {
44
+ // Create a folder structure:
45
+ // Root
46
+ // └── Folder 1
47
+ // └── Asset 1
48
+ const folder1 = createMediaFolder();
49
+ const asset1 = createMediaAsset({
50
+ assetId: "asset1",
51
+ });
52
+ const media: MediaMap = {
53
+ folder1,
54
+ "folder1/asset1": asset1,
55
+ };
56
+ const tree = createMediaItemTree(media);
57
+
58
+ // Move Asset 1 to root
59
+ const result = moveMediaInsideFolder({
60
+ sourceItemIds: [asset1.id],
61
+ targetItemId: rootMediaItem.id,
62
+ media,
63
+ tree,
64
+ });
65
+
66
+ // Asset 1 should now have undefined as its parentId (root)
67
+ const movedAsset = result["asset1"];
68
+ expect(movedAsset).toEqual(asset1);
69
+ const oldAssetKey = "folder1/asset1";
70
+ expect(result[oldAssetKey]).toBeUndefined();
71
+ });
72
+
73
+ it("should move a folder into another folder", () => {
74
+ // Create a folder structure:
75
+ // Root
76
+ // ├── Folder 1
77
+ // └── Folder 2
78
+ const folder1 = createMediaFolder();
79
+ const folder2 = createMediaFolder();
80
+ const media: MediaMap = {
81
+ folder1,
82
+ folder2,
83
+ };
84
+ const tree = createMediaItemTree(media);
85
+ // Move Folder 2 into Folder 1
86
+ const result = moveMediaInsideFolder({
87
+ sourceItemIds: [folder2.id],
88
+ targetItemId: folder1.id,
89
+ media,
90
+ tree,
91
+ });
92
+
93
+ // Folder 2 should now have Folder 1 as its parent
94
+ const movedFolder = result["folder1/folder2"];
95
+ expect(movedFolder).toEqual(folder2);
96
+ const oldFolderKey = "folder2";
97
+ expect(result[oldFolderKey]).toBeUndefined();
98
+
99
+ // Folder 1 should remain unchanged
100
+ const folder = result["folder1"];
101
+ expect(folder).toEqual(folder1);
102
+ });
103
+
104
+ it("should not modify other items in the array", () => {
105
+ // Create a folder structure:
106
+ // Root
107
+ // ├── Folder 1
108
+ // ├── Folder 2
109
+ // └── Asset 1
110
+ const folder1 = createMediaFolder();
111
+ const folder2 = createMediaFolder();
112
+ const asset1 = createMediaAsset({
113
+ assetId: "asset1",
114
+ });
115
+ const media: MediaMap = {
116
+ folder1,
117
+ folder2,
118
+ asset1,
119
+ };
120
+ const tree = createMediaItemTree(media);
121
+
122
+ // Move Asset 1 into Folder 1
123
+ const result = moveMediaInsideFolder({
124
+ sourceItemIds: [asset1.id],
125
+ targetItemId: folder1.id,
126
+ media,
127
+ tree,
128
+ });
129
+
130
+ // Only Asset 1 should be modified
131
+ expect(result["folder1"]).toEqual(folder1);
132
+ expect(result["folder2"]).toEqual(folder2);
133
+ const movedAsset = result["folder1/asset1"];
134
+ expect(movedAsset).toEqual(asset1);
135
+ const oldAssetKey = "asset1";
136
+ expect(result[oldAssetKey]).toBeUndefined();
137
+ });
138
+
139
+ it("should handle moving an item that doesn't exist", () => {
140
+ const folder1 = createMediaFolder();
141
+ const media: MediaMap = {
142
+ folder1,
143
+ };
144
+ const tree = createMediaItemTree(media);
145
+ // Try to move a non-existent item
146
+ const result = moveMediaInsideFolder({
147
+ sourceItemIds: ["nonexistent"],
148
+ targetItemId: folder1.id,
149
+ media,
150
+ tree,
151
+ });
152
+
153
+ // The result should be the same as the input
154
+ expect(result).toEqual(media);
155
+ });
156
+
157
+ it("should handle moving to a target that doesn't exist", () => {
158
+ const asset1 = createMediaAsset({
159
+ assetId: "asset1",
160
+ });
161
+ const media: MediaMap = {
162
+ asset1,
163
+ };
164
+ const tree = createMediaItemTree(media);
165
+
166
+ // Try to move to a non-existent folder
167
+ const result = moveMediaInsideFolder({
168
+ sourceItemIds: [asset1.id],
169
+ targetItemId: "nonexistent",
170
+ media,
171
+ tree,
172
+ });
173
+
174
+ // The item should still be moved to the specified target
175
+ const movedAsset = result["nonexistent/asset1"];
176
+ expect(movedAsset).toBeUndefined();
177
+ });
178
+
179
+ it("should move a folder and all its descendants into another folder", () => {
180
+ // Create a nested folder structure:
181
+ // Root
182
+ // ├── Folder 1
183
+ // └── Folder 2
184
+ // └── Folder 3
185
+ // └── Asset 1
186
+ const folder1 = createMediaFolder();
187
+ const folder2 = createMediaFolder();
188
+ const folder3 = createMediaFolder();
189
+ const asset1 = createMediaAsset({
190
+ assetId: "asset1",
191
+ });
192
+ const media: MediaMap = {
193
+ folder1,
194
+ folder2,
195
+ "folder2/folder3": folder3,
196
+ "folder2/folder3/asset1": asset1,
197
+ };
198
+ const tree = createMediaItemTree(media);
199
+
200
+ // Move Folder 2 (and its descendants) into Folder 1
201
+ const result = moveMediaInsideFolder({
202
+ sourceItemIds: [folder2.id],
203
+ targetItemId: folder1.id,
204
+ media,
205
+ tree,
206
+ });
207
+
208
+ // Folder 2 should now be inside Folder 1
209
+ expect(result["folder1/folder2"]).toEqual(folder2);
210
+
211
+ // Asset 1 should be inside Folder 3, which is inside Folder 2, which is inside Folder 1
212
+ expect(result["folder1/folder2/folder3/asset1"]).toEqual(asset1);
213
+
214
+ // Original paths should be removed
215
+ expect(result["folder2"]).toBeUndefined();
216
+ expect(result["folder2/asset1"]).toBeUndefined();
217
+
218
+ // Folder 1 should remain unchanged
219
+ expect(result["folder1"]).toEqual(folder1);
220
+ });
221
+
222
+ it("should move a folder and all its descendants to the root", () => {
223
+ // Create a nested folder structure:
224
+ // Root
225
+ // └── Folder 1
226
+ // └── Folder 2
227
+ // └── Asset 1
228
+ const folder1 = createMediaFolder();
229
+ const folder2 = createMediaFolder();
230
+ const asset1 = createMediaAsset({
231
+ assetId: "asset1",
232
+ });
233
+ const media: MediaMap = {
234
+ folder1,
235
+ "folder1/folder2": folder2,
236
+ "folder1/folder2/asset1": asset1,
237
+ };
238
+ const tree = createMediaItemTree(media);
239
+
240
+ // Move Folder 2 (and its descendants) to the root
241
+ const result = moveMediaInsideFolder({
242
+ sourceItemIds: [folder2.id],
243
+ targetItemId: rootMediaItem.id,
244
+ media,
245
+ tree,
246
+ });
247
+
248
+ // Folder 2 should now be at the root
249
+ expect(result["folder2"]).toEqual(folder2);
250
+
251
+ // Asset 1 should be inside Folder 2 at the root
252
+ expect(result["folder2/asset1"]).toEqual(asset1);
253
+
254
+ // Original paths should be removed
255
+ expect(result["folder1/folder2"]).toBeUndefined();
256
+ expect(result["folder1/folder2/asset1"]).toBeUndefined();
257
+
258
+ // Folder 1 should remain unchanged
259
+ expect(result["folder1"]).toEqual(folder1);
260
+ });
261
+
262
+ it("should preserve the structure when moving a folder with multiple levels of nesting", () => {
263
+ // Create a deeply nested folder structure:
264
+ // Root
265
+ // ├── Target Folder
266
+ // └── Source Folder
267
+ // └── Level 1
268
+ // └── Level 2
269
+ // └── Asset 1
270
+ const targetFolder = createMediaFolder();
271
+ const sourceFolder = createMediaFolder();
272
+ const level1 = createMediaFolder();
273
+ const level2 = createMediaFolder();
274
+ const asset1 = createMediaAsset({
275
+ assetId: "asset1",
276
+ });
277
+ const media: MediaMap = {
278
+ targetFolder,
279
+ sourceFolder,
280
+ "sourceFolder/level1": level1,
281
+ "sourceFolder/level1/level2": level2,
282
+ "sourceFolder/level1/level2/asset1": asset1,
283
+ };
284
+ const tree = createMediaItemTree(media);
285
+
286
+ // Move the source folder to the target folder
287
+ const result = moveMediaInsideFolder({
288
+ sourceItemIds: [sourceFolder.id],
289
+ targetItemId: targetFolder.id,
290
+ media,
291
+ tree,
292
+ });
293
+
294
+ // The entire structure should be preserved but moved under the target folder
295
+ expect(result["targetFolder/sourceFolder"]).toEqual(sourceFolder);
296
+ expect(result["targetFolder/sourceFolder/level1"]).toEqual(level1);
297
+ expect(result["targetFolder/sourceFolder/level1/level2"]).toEqual(level2);
298
+ expect(result["targetFolder/sourceFolder/level1/level2/asset1"]).toEqual(
299
+ asset1
300
+ );
301
+
302
+ // Original paths should be removed
303
+ expect(result["sourceFolder"]).toBeUndefined();
304
+ expect(result["sourceFolder/level1"]).toBeUndefined();
305
+ expect(result["sourceFolder/level1/level2"]).toBeUndefined();
306
+ expect(result["sourceFolder/level1/level2/asset1"]).toBeUndefined();
307
+
308
+ // Target folder should remain unchanged
309
+ expect(result["targetFolder"]).toEqual(targetFolder);
310
+ });
311
+
312
+ it("should handle moving both a sibling item and a folder to another folder", () => {
313
+ // Create a folder structure:
314
+ // Root
315
+ // ├── Folder 1
316
+ // └── Folder 2
317
+ // └── Asset 1
318
+ // └── Folder 3
319
+ // └── Asset 2
320
+ const folder1 = createMediaFolder();
321
+ const folder2 = createMediaFolder();
322
+ const folder3 = createMediaFolder();
323
+ const asset1 = createMediaAsset({
324
+ assetId: "asset1",
325
+ });
326
+ const asset2 = createMediaAsset({
327
+ assetId: "asset2",
328
+ });
329
+ const media: MediaMap = {
330
+ folder1,
331
+ folder2,
332
+ "folder2/asset1": asset1,
333
+ "folder2/folder3": folder3,
334
+ asset2: asset2,
335
+ };
336
+ const tree = createMediaItemTree(media);
337
+ // move folder 3 and asset 1 to folder 1
338
+ const result = moveMediaInsideFolder({
339
+ sourceItemIds: [folder3.id, asset1.id],
340
+ targetItemId: folder1.id,
341
+ media,
342
+ tree,
343
+ });
344
+ expect(result["folder1/folder3"]).toEqual(folder3);
345
+ expect(result["folder1/asset1"]).toEqual(asset1);
346
+ expect(result["folder2"]).toEqual(folder2);
347
+ expect(result["folder2/asset1"]).toBeUndefined();
348
+ });
@@ -0,0 +1,229 @@
1
+ import { MediaMap } from "@noya-app/noya-schemas";
2
+ import { expect, it } from "bun:test";
3
+ import { movePathsIntoTarget } from "../utils/files";
4
+ import {
5
+ createMediaAsset,
6
+ createMediaFolder,
7
+ createMediaItemTree,
8
+ } from "../utils/mediaItemTree";
9
+
10
+ it("should move a single file to a target directory", () => {
11
+ // Setup
12
+ const file1 = createMediaAsset({ assetId: "1" });
13
+ const targetFolder = createMediaFolder();
14
+ const media: MediaMap = {
15
+ "file1.jpg": file1,
16
+ target: targetFolder,
17
+ };
18
+ const tree = createMediaItemTree(media);
19
+
20
+ // Execute
21
+ const result = movePathsIntoTarget({
22
+ media: media,
23
+ sourceItemPaths: ["file1.jpg"],
24
+ targetItemPath: "target",
25
+ tree,
26
+ });
27
+
28
+ // Verify
29
+ expect(result["file1.jpg"]).toBeUndefined();
30
+ expect(result["target/file1.jpg"]).toEqual(file1);
31
+ expect(result["target"]).toEqual(targetFolder);
32
+ });
33
+
34
+ it("should move a folder and its contents to a target directory", () => {
35
+ // Setup
36
+ const sourceFolder = createMediaFolder();
37
+ const file1 = createMediaAsset({ assetId: "1" });
38
+ const file2 = createMediaAsset({ assetId: "2" });
39
+ const targetFolder = createMediaFolder();
40
+
41
+ const media: MediaMap = {
42
+ source: sourceFolder,
43
+ "source/file1.jpg": file1,
44
+ "source/file2.jpg": file2,
45
+ target: targetFolder,
46
+ };
47
+ const tree = createMediaItemTree(media);
48
+
49
+ // Execute
50
+ const result = movePathsIntoTarget({
51
+ media: media,
52
+ sourceItemPaths: ["source"],
53
+ targetItemPath: "target",
54
+ tree,
55
+ });
56
+
57
+ // Verify
58
+ expect(result["source"]).toBeUndefined();
59
+ expect(result["source/file1.jpg"]).toBeUndefined();
60
+ expect(result["source/file2.jpg"]).toBeUndefined();
61
+ expect(result["target"]).toEqual(targetFolder);
62
+ expect(result["target/source"]).toEqual(sourceFolder);
63
+ expect(result["target/source/file1.jpg"]).toEqual(file1);
64
+ expect(result["target/source/file2.jpg"]).toEqual(file2);
65
+ });
66
+
67
+ it("should move multiple items to a target directory", () => {
68
+ // Setup
69
+ const file1 = createMediaAsset({ assetId: "1" });
70
+ const file2 = createMediaAsset({ assetId: "2" });
71
+ const targetFolder = createMediaFolder();
72
+
73
+ const media: MediaMap = {
74
+ "file1.jpg": file1,
75
+ "file2.jpg": file2,
76
+ target: targetFolder,
77
+ };
78
+ const tree = createMediaItemTree(media);
79
+
80
+ // Execute
81
+ const result = movePathsIntoTarget({
82
+ media: media,
83
+ sourceItemPaths: ["file1.jpg", "file2.jpg"],
84
+ targetItemPath: "target",
85
+ tree,
86
+ });
87
+
88
+ // Verify
89
+ expect(result["file1.jpg"]).toBeUndefined();
90
+ expect(result["file2.jpg"]).toBeUndefined();
91
+ expect(result["target"]).toEqual(targetFolder);
92
+ expect(result["target/file1.jpg"]).toEqual(file1);
93
+ expect(result["target/file2.jpg"]).toEqual(file2);
94
+ });
95
+
96
+ it("should handle nested folder structures correctly", () => {
97
+ // Setup
98
+ const folder1 = createMediaFolder();
99
+ const folder2 = createMediaFolder();
100
+ const file1 = createMediaAsset({ assetId: "1" });
101
+ const file2 = createMediaAsset({ assetId: "2" });
102
+ const targetFolder = createMediaFolder();
103
+
104
+ const media: MediaMap = {
105
+ folder1: folder1,
106
+ "folder1/folder2": folder2,
107
+ "folder1/folder2/file1.jpg": file1,
108
+ "folder1/file2.jpg": file2,
109
+ target: targetFolder,
110
+ };
111
+ const tree = createMediaItemTree(media);
112
+
113
+ // Execute
114
+ const result = movePathsIntoTarget({
115
+ media: media,
116
+ sourceItemPaths: ["folder1"],
117
+ targetItemPath: "target",
118
+ tree,
119
+ });
120
+
121
+ // Verify
122
+ expect(result["folder1"]).toBeUndefined();
123
+ expect(result["folder1/folder2"]).toBeUndefined();
124
+ expect(result["folder1/folder2/file1.jpg"]).toBeUndefined();
125
+ expect(result["folder1/file2.jpg"]).toBeUndefined();
126
+ expect(result["target"]).toEqual(targetFolder);
127
+ expect(result["target/folder1"]).toEqual(folder1);
128
+ expect(result["target/folder1/folder2"]).toEqual(folder2);
129
+ expect(result["target/folder1/folder2/file1.jpg"]).toEqual(file1);
130
+ expect(result["target/folder1/file2.jpg"]).toEqual(file2);
131
+ });
132
+
133
+ it("should handle moving items to the root directory", () => {
134
+ // Setup
135
+ const folder = createMediaFolder();
136
+ const file1 = createMediaAsset({ assetId: "1" });
137
+
138
+ const media: MediaMap = {
139
+ folder: folder,
140
+ "folder/file1.jpg": file1,
141
+ };
142
+ const tree = createMediaItemTree(media);
143
+
144
+ // Execute
145
+ const result = movePathsIntoTarget({
146
+ media: media,
147
+ sourceItemPaths: ["folder/file1.jpg"],
148
+ targetItemPath: ".",
149
+ tree,
150
+ });
151
+
152
+ // Verify
153
+ expect(result["folder"]).toEqual(folder);
154
+ expect(result["folder/file1.jpg"]).toBeUndefined();
155
+ expect(result["file1.jpg"]).toEqual(file1);
156
+ });
157
+
158
+ it("should handle moving items with the same basename", () => {
159
+ // Setup
160
+ const folder1 = createMediaFolder();
161
+ const folder2 = createMediaFolder();
162
+ const file1 = createMediaAsset({ assetId: "1" });
163
+ const file2 = createMediaAsset({ assetId: "2" });
164
+
165
+ const media: MediaMap = {
166
+ folder1: folder1,
167
+ "folder1/file.jpg": file1,
168
+ folder2: folder2,
169
+ "folder2/file.jpg": file2,
170
+ };
171
+ const tree = createMediaItemTree(media);
172
+
173
+ // Execute
174
+ const result = movePathsIntoTarget({
175
+ media: media,
176
+ sourceItemPaths: ["folder1/file.jpg", "folder2/file.jpg"],
177
+ targetItemPath: ".",
178
+ tree,
179
+ });
180
+
181
+ // Verify - the second file should overwrite the first one with the same name
182
+ expect(result["folder1"]).toEqual(folder1);
183
+ expect(result["folder2"]).toEqual(folder2);
184
+ expect(result["folder1/file.jpg"]).toBeUndefined();
185
+ expect(result["folder2/file.jpg"]).toBeUndefined();
186
+ expect(result["file.jpg"]).toEqual(file2); // Last one wins
187
+ });
188
+
189
+ it("should handle empty source paths array", () => {
190
+ // Setup
191
+ const targetFolder = createMediaFolder();
192
+
193
+ const media: MediaMap = {
194
+ target: targetFolder,
195
+ };
196
+ const tree = createMediaItemTree(media);
197
+
198
+ // Execute
199
+ const result = movePathsIntoTarget({
200
+ media: media,
201
+ sourceItemPaths: [],
202
+ targetItemPath: "target",
203
+ tree,
204
+ });
205
+
206
+ // Verify nothing changed
207
+ expect(result).toEqual(media);
208
+ });
209
+
210
+ it("should handle non-existent source paths", () => {
211
+ // Setup
212
+ const targetFolder = createMediaFolder();
213
+
214
+ const media: MediaMap = {
215
+ target: targetFolder,
216
+ };
217
+ const tree = createMediaItemTree(media);
218
+
219
+ // Execute
220
+ const result = movePathsIntoTarget({
221
+ media: media,
222
+ sourceItemPaths: ["non-existent.jpg"],
223
+ targetItemPath: "target",
224
+ tree,
225
+ });
226
+
227
+ // Verify nothing changed
228
+ expect(result).toEqual(media);
229
+ });