feat: workspace helpers - quoting paths, what a dropped file does, with node tests

This commit is contained in:
redtea committed 2026-10-15 20:00:26 +03:00
1 parent 0ada0899cf
commit 7b9daa524e
4 files changed
+90

No files matched your search

+5
View File
@@ -434,6 +434,11 @@ func assetHashes(fsys fs.FS) map[string]string {
func staticHandler(fsys fs.FS, hashes map[string]string) http.Handler { func staticHandler(fsys fs.FS, hashes map[string]string) http.Handler {
files := http.FileServer(http.FS(fsys)) files := http.FileServer(http.FS(fsys))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// The JS tests sit beside the scripts but are not served.
if strings.HasSuffix(r.URL.Path, ".test.js") {
http.NotFound(w, r)
return
}
h := hashes[strings.TrimPrefix(r.URL.Path, "/")] h := hashes[strings.TrimPrefix(r.URL.Path, "/")]
if h != "" { if h != "" {
w.Header().Set("ETag", `"`+h+`"`) w.Header().Set("ETag", `"`+h+`"`)
+23
View File
@@ -0,0 +1,23 @@
package server
import (
"net/http"
"net/http/httptest"
"testing"
"testing/fstest"
)
func TestStaticHidesTests(t *testing.T) {
fsys := fstest.MapFS{
"wsutil.js": {Data: []byte("x")},
"wsutil.test.js": {Data: []byte("y")},
}
h := staticHandler(fsys, map[string]string{})
for path, want := range map[string]int{"/wsutil.js": 200, "/wsutil.test.js": 404} {
w := httptest.NewRecorder()
h.ServeHTTP(w, httptest.NewRequest(http.MethodGet, path, nil))
if w.Code != want {
t.Errorf("%s: got %d, want %d", path, w.Code, want)
}
}
}
+27
View File
@@ -0,0 +1,27 @@
// Pure helpers of the workspace: quoting paths for a shell, what a dropped
// file does where it lands, sizes. No DOM here, so node can test them.
(function (root) {
'use strict';
function shellQuote(p) { return "'" + String(p).replace(/'/g, "'\\''") + "'"; }
function shellQuoteAll(ps) { return ps.map(shellQuote).join(' '); }
const same = (a, b) => a.kind === b.kind && a.id === b.id;
// dropAction says what dropping item on target does: a transfer between
// file panes, paths pasted into a terminal of the same place, nothing on
// its own folder, or a refusal with the reason.
function dropAction(item, target) {
if (target.kind === 'term') {
return same(item.source, target.source) ? {kind: 'paste'}
: {kind: 'deny', reason: 'Нельзя: файл на ' + item.source.label + ', а терминал на ' + target.source.label};
}
if (same(item.source, target.source) && target.dir === item.dir) return {kind: 'none'};
return {kind: 'transfer'};
}
function fmtSize(n) {
if (n < 1024) return n + ' B';
if (n < 1048576) return (n / 1024).toFixed(1) + ' K';
if (n < 1073741824) return (n / 1048576).toFixed(1) + ' M';
return (n / 1073741824).toFixed(1) + ' G';
}
const api = {shellQuote, shellQuoteAll, dropAction, fmtSize};
if (typeof module !== 'undefined') module.exports = api; else root.WSUtil = api;
})(this);
+35
View File
@@ -0,0 +1,35 @@
'use strict';
const test = require('node:test');
const assert = require('node:assert');
const U = require('./wsutil.js');
test('shellQuote keeps a path one literal word', () => {
assert.strictEqual(U.shellQuote('/srv/a b'), "'/srv/a b'");
assert.strictEqual(U.shellQuote("/x/it's"), "'/x/it'\\''s'");
assert.strictEqual(U.shellQuote('/x/$HOME;rm'), "'/x/$HOME;rm'");
assert.strictEqual(U.shellQuoteAll(['/a', '/b c']), "'/a' '/b c'");
});
const m1 = {kind: 'agent', id: 'm1', label: 'web'};
const m2 = {kind: 'agent', id: 'm2', label: 'db'};
const s1 = {kind: 'ssh', id: 'm1|root@h:22', label: 'root@h'};
const item = {source: m1, paths: ['/etc/x'], dir: '/etc'};
test('dropAction: files into a file pane is a transfer', () => {
assert.deepStrictEqual(U.dropAction(item, {kind: 'files', source: m2, dir: '/tmp'}), {kind: 'transfer'});
assert.deepStrictEqual(U.dropAction(item, {kind: 'folder', source: m1, dir: '/var'}), {kind: 'transfer'});
});
test('dropAction: into its own folder does nothing', () => {
assert.deepStrictEqual(U.dropAction(item, {kind: 'files', source: m1, dir: '/etc'}), {kind: 'none'});
});
test('dropAction: terminal of the same place pastes, of another is denied', () => {
assert.deepStrictEqual(U.dropAction(item, {kind: 'term', source: m1}), {kind: 'paste'});
const d = U.dropAction(item, {kind: 'term', source: m2});
assert.strictEqual(d.kind, 'deny');
assert.strictEqual(d.reason, 'Нельзя: файл на web, а терминал на db');
assert.strictEqual(U.dropAction({source: s1, paths: ['/a'], dir: '/'}, {kind: 'term', source: s1}).kind, 'paste');
});
test('fmtSize', () => {
assert.strictEqual(U.fmtSize(10), '10 B');
assert.strictEqual(U.fmtSize(2048), '2.0 K');
});