filefive 1.3.0 → 1.4.1

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.
@@ -8,8 +8,8 @@ const Queue_1 = __importDefault(require("./Queue"));
8
8
  const types_1 = require("../types");
9
9
  const URI_1 = require("../utils/URI");
10
10
  class CopyQueue extends Queue_1.default {
11
- constructor(connId, src, dest, filter, onState, onConflict, onError, onComplete, watcher, move) {
12
- super(connId, connId, src, dest, filter, onState, onConflict, onComplete);
11
+ constructor(connId, src, dest, filter, fromRoot, onState, onConflict, onError, onComplete, watcher, move) {
12
+ super(connId, connId, src, dest, filter, fromRoot, onState, onConflict, onComplete);
13
13
  this.onError = onError;
14
14
  this.watcher = watcher;
15
15
  this.move = move;
@@ -8,8 +8,8 @@ const Queue_1 = __importDefault(require("./Queue"));
8
8
  const types_1 = require("../types");
9
9
  const Local_1 = require("../Local");
10
10
  class DownloadQueue extends Queue_1.default {
11
- constructor(connId, src, dest, filter, onState, onConflict, onError, onComplete) {
12
- super(connId, types_1.LocalFileSystemID, src, dest, filter, onState, onConflict, onComplete);
11
+ constructor(connId, src, dest, filter, fromRoot, onState, onConflict, onError, onComplete) {
12
+ super(connId, types_1.LocalFileSystemID, src, dest, filter, fromRoot, onState, onConflict, onComplete);
13
13
  this.onError = onError;
14
14
  }
15
15
  async transmit(fs, from, dirs, to) {
@@ -7,7 +7,7 @@ const Copy_1 = __importDefault(require("./Copy"));
7
7
  const types_1 = require("../types");
8
8
  class DuplicateQueue extends Copy_1.default {
9
9
  constructor(connId, src, dest, filter, onState, onConflict, onError, onComplete, watcher) {
10
- super(connId, src, dest, filter, onState, onConflict, onError, onComplete, watcher, false);
10
+ super(connId, src, dest, filter, null, onState, onConflict, onError, onComplete, watcher, false);
11
11
  this.newNames = new Map();
12
12
  this.resolve({ type: types_1.QueueActionType.Rename }, true);
13
13
  }
@@ -30,12 +30,13 @@ const lsRemote = (connId) => {
30
30
  };
31
31
  exports.lsRemote = lsRemote;
32
32
  class TransmitQueue {
33
- constructor(from, to, src, dest, filter, onState, onConflict, onComplete) {
33
+ constructor(from, to, src, dest, filter, fromRoot, onState, onConflict, onComplete) {
34
34
  this.from = from;
35
35
  this.to = to;
36
36
  this.src = src;
37
37
  this.dest = dest;
38
38
  this.filter = filter;
39
+ this.fromRoot = fromRoot;
39
40
  this.onState = onState;
40
41
  this.onConflict = onConflict;
41
42
  this.onComplete = onComplete;
@@ -57,7 +58,7 @@ class TransmitQueue {
57
58
  }
58
59
  const stat = this.stat(this.to);
59
60
  this.processing = this.queue$.subscribe(async ({ from, dirs, to, action }) => {
60
- let a = action ?? this.action;
61
+ const a = action ?? this.action;
61
62
  const existing = await stat((0, node_path_1.join)(to, ...dirs, from.name));
62
63
  if (existing) {
63
64
  if (a) {
@@ -115,7 +116,7 @@ class TransmitQueue {
115
116
  }
116
117
  }
117
118
  };
118
- await Promise.all(paths.map(path => add(path, dest)));
119
+ await Promise.all(paths.map(path => add(path, dest, this.fromRoot ? (0, node_path_1.dirname)(path).substring(this.fromRoot.length + 1).split('/') : [])));
119
120
  }
120
121
  stop() {
121
122
  if (!this.stopped) {
@@ -9,8 +9,8 @@ const types_1 = require("../types");
9
9
  const Local_1 = require("../Local");
10
10
  const URI_1 = require("../utils/URI");
11
11
  class UploadQueue extends Queue_1.default {
12
- constructor(connId, src, dest, filter, onState, onConflict, onError, onComplete, watcher) {
13
- super(types_1.LocalFileSystemID, connId, src, dest, filter, onState, onConflict, onComplete);
12
+ constructor(connId, src, dest, filter, fromRoot, onState, onConflict, onError, onComplete, watcher) {
13
+ super(types_1.LocalFileSystemID, connId, src, dest, filter, fromRoot, onState, onConflict, onComplete);
14
14
  this.onError = onError;
15
15
  this.watcher = watcher;
16
16
  this.touched = new Map();
@@ -34,7 +34,9 @@ class UploadQueue extends Queue_1.default {
34
34
  try {
35
35
  await fs.mkdir(targetDir);
36
36
  }
37
- catch (e) { }
37
+ catch {
38
+ // the targetDir already exists
39
+ }
38
40
  resolve();
39
41
  }));
40
42
  }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const types_1 = require("../types");
7
+ const git_1 = __importDefault(require("./git"));
8
+ class default_1 {
9
+ async transform(path, files) {
10
+ files = files.map(f => ({ ...f, [types_1.FileAttrsAttr]: {} }));
11
+ for (const f of [git_1.default]) {
12
+ files = await f(path, files);
13
+ }
14
+ return files;
15
+ }
16
+ }
17
+ exports.default = default_1;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const node_util_1 = require("node:util");
5
+ const node_child_process_1 = require("node:child_process");
6
+ const node_path_1 = require("node:path");
7
+ const types_1 = require("../types");
8
+ const ramda_1 = require("ramda");
9
+ async function default_1(path, files) {
10
+ const run = (0, node_util_1.promisify)(node_child_process_1.execFile);
11
+ try {
12
+ let { stdout: repoRoot } = await run('git', ['rev-parse', '--show-toplevel'], { cwd: path });
13
+ repoRoot = repoRoot.trim();
14
+ const { stdout: statuses } = await run('git', ['status', '-z', '.'], { cwd: path });
15
+ const [inRoot, inSubfolders] = (0, ramda_1.partition)(([p]) => (0, node_path_1.dirname)(p) == path, statuses
16
+ .replace(/\0$/, '')
17
+ .split('\0')
18
+ .map(s => [(0, node_path_1.join)(repoRoot, s.substring(3)), s.substring(0, 2)])
19
+ .map(([path, status]) => [path.replace(/\/$/, ''), status]));
20
+ if (inSubfolders.length == 1 && inSubfolders[0][0] == path && inSubfolders[0][1].includes('?')) {
21
+ files.forEach(f => {
22
+ const status = f.dir ? GitStatus.Contains : GitStatus.Untracked;
23
+ f[types_1.FileAttrsAttr][status] = statusNames[status];
24
+ });
25
+ }
26
+ else {
27
+ const topDir = new RegExp('^([^/]+)');
28
+ [...inRoot
29
+ .map(([path, s]) => [path, getStatusCode(s)])
30
+ .filter(([, status]) => status),
31
+ ...[...new Set(inSubfolders.map(([p]) => topDir.exec(p.substring(path.length + 1))?.[1]).filter(s => s))].map(dir => [(0, node_path_1.join)(path, dir), GitStatus.Contains])
32
+ ].forEach(([path, status]) => {
33
+ const f = files.find(f => f.path == path);
34
+ if (f) {
35
+ if (f.dir) {
36
+ status = GitStatus.Contains;
37
+ }
38
+ f[types_1.FileAttrsAttr][status] = status ? (statusNames[status] ?? '') : '';
39
+ }
40
+ });
41
+ }
42
+ const { stdout: ignored } = await run('git', ['ls-files', '--others', '--ignored', '--exclude-standard', '--directory', '-z'], { cwd: path });
43
+ if (ignored == './\0') {
44
+ files.forEach(f => f[types_1.FileAttrsAttr][GitStatus.Ignored] = statusNames[GitStatus.Ignored]);
45
+ }
46
+ else {
47
+ ignored
48
+ .replace(/\0$/, '')
49
+ .split('\0')
50
+ .map(s => (0, node_path_1.join)(path, s.replace(/\/$/, '')))
51
+ .forEach(path => {
52
+ const f = files.find(f => f.path == path);
53
+ f && (f[types_1.FileAttrsAttr][GitStatus.Ignored] = statusNames[GitStatus.Ignored]);
54
+ });
55
+ }
56
+ }
57
+ catch {
58
+ // either path is not in git repo or no git installed
59
+ }
60
+ return files;
61
+ }
62
+ var GitStatus;
63
+ (function (GitStatus) {
64
+ GitStatus["Untracked"] = "git_u";
65
+ GitStatus["Modified"] = "git_m";
66
+ GitStatus["Added"] = "git_a";
67
+ GitStatus["Contains"] = "git_c";
68
+ GitStatus["Ignored"] = "git_i";
69
+ })(GitStatus || (GitStatus = {}));
70
+ const statusNames = {
71
+ [GitStatus.Untracked]: 'Untracked',
72
+ [GitStatus.Modified]: 'Modified',
73
+ [GitStatus.Added]: 'Index Added',
74
+ [GitStatus.Contains]: 'Has uncommited items',
75
+ [GitStatus.Ignored]: 'Ignored'
76
+ };
77
+ function getStatusCode(s) {
78
+ if (s.includes('?')) {
79
+ return GitStatus.Untracked;
80
+ }
81
+ else if (s.includes('M')) {
82
+ return GitStatus.Modified;
83
+ }
84
+ else if (s.includes('A')) {
85
+ return GitStatus.Added;
86
+ }
87
+ return null;
88
+ }
package/dist/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FailureType = exports.QueueActionType = exports.QueueEventType = exports.QueueType = exports.SortOrder = exports.FileTagsAttr = exports.FileState = exports.FileStateAttr = exports.LocalFileSystemID = void 0;
3
+ exports.FailureType = exports.QueueActionType = exports.QueueEventType = exports.QueueType = exports.SortOrder = exports.FileAttrsAttr = exports.FileState = exports.FileStateAttr = exports.LocalFileSystemID = void 0;
4
4
  exports.LocalFileSystemID = 'file://';
5
5
  exports.FileStateAttr = Symbol.for('state');
6
6
  var FileState;
@@ -8,7 +8,7 @@ var FileState;
8
8
  FileState["Creating"] = "creating";
9
9
  FileState["Renaming"] = "renaming";
10
10
  })(FileState || (exports.FileState = FileState = {}));
11
- exports.FileTagsAttr = Symbol.for('tags');
11
+ exports.FileAttrsAttr = 'attributes';
12
12
  var SortOrder;
13
13
  (function (SortOrder) {
14
14
  SortOrder["Asc"] = "asc";
@@ -18,7 +18,7 @@ function filterRegExp(settings) {
18
18
  try {
19
19
  return new RegExp(source, settings.matchCase ? '' : 'i');
20
20
  }
21
- catch (e) {
21
+ catch {
22
22
  return null;
23
23
  }
24
24
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "filefive",
3
3
  "description": "A SFTP/FTP client and dual-panel file manager for macOS and Linux",
4
- "version": "1.3.0",
4
+ "version": "1.4.1",
5
5
  "license": "GPL-3.0",
6
6
  "author": "Max Miroshnikov",
7
7
  "bin": {
@@ -31,6 +31,8 @@
31
31
  "dev": "NODE_ENV=development nodemon src/index.ts",
32
32
  "build": "tsc -p .",
33
33
  "start": "node dist/index.js",
34
+ "test": "jest tests",
35
+ "lint": "eslint",
34
36
  "publish": "tsc -p . && npm publish"
35
37
  },
36
38
  "dependencies": {
@@ -48,17 +50,23 @@
48
50
  "ws": "^8.18.0"
49
51
  },
50
52
  "devDependencies": {
53
+ "@eslint/js": "^9.22.0",
51
54
  "@types/express": "^5.0.0",
52
55
  "@types/ftp": "^0.3.36",
56
+ "@types/jest": "^29.5.14",
53
57
  "@types/multer": "^1.4.12",
54
58
  "@types/node": "^22.12.0",
55
59
  "@types/ramda": "^0.30.2",
56
60
  "@types/ssh2": "^1.15.4",
57
61
  "@types/whatwg-url": "^13.0.0",
58
62
  "@types/ws": "^8.5.14",
63
+ "eslint": "^9.22.0",
64
+ "jest": "^29.7.0",
59
65
  "nodemon": "^3.1.9",
66
+ "ts-jest": "^29.3.2",
60
67
  "ts-node": "^10.9.2",
61
- "typescript": "^5.7.3"
68
+ "typescript": "^5.8.2",
69
+ "typescript-eslint": "^8.26.1"
62
70
  },
63
71
  "nodemonConfig": {
64
72
  "ignore": [
package/dist/transform.js DELETED
@@ -1,24 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.add = add;
7
- exports.remove = remove;
8
- exports.default = default_1;
9
- const uniqid_1 = __importDefault(require("./utils/uniqid"));
10
- const transformations = [];
11
- function add(f) {
12
- const id = (0, uniqid_1.default)();
13
- transformations.push({ id, f });
14
- return id;
15
- }
16
- function remove(id) {
17
- const i = transformations.findIndex(t => t.id == id);
18
- if (i >= 0) {
19
- transformations.splice(i, 1);
20
- }
21
- }
22
- function default_1(files) {
23
- return transformations.reduce((files, { f }) => f(files), files);
24
- }