diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 27f58bac..00000000
--- a/.eslintrc
+++ /dev/null
@@ -1,22 +0,0 @@
-root: true
-extends: silverwind
-
-overrides:
- - files: ["packages/client/**/*.js"]
- rules:
- prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
- env:
- browser: true
- es6: true
- jquery: true
- globals:
- CodeMirror: false
- fileExtension: false
- Handlebars: false
- Mousetrap: false
- pdfjsLib: false
- PhotoSwipe: false
- PhotoSwipeUI_Default: false
- Plyr: false
- screenfull: false
- Uppie: false
diff --git a/.gitignore b/.gitignore
index 40497a6c..a1fc9731 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
-/.vscode/
+.vscode/*
+!.vscode/extensions.json
dist/
node_modules
npm-debug.log*
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..8ccf0e74
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["dbaeumer.vscode-eslint"]
+}
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..10d37bed
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,50 @@
+import globals from "globals";
+
+import js from "@eslint/js";
+
+import babelParser from "@babel/eslint-parser";
+
+export default [
+ js.configs.recommended,
+
+ {
+ languageOptions: {
+ ecmaVersion: 2022,
+ sourceType: "module",
+ globals: {
+ ...globals.browser,
+ ...globals.node,
+
+ // TODO: remove when moved to ES modules in client
+ $: "readonly",
+ CodeMirror: "readonly",
+ Mousetrap: "readonly",
+ Handlebars: "readonly",
+ _: "readonly",
+ fileExtension: "readonly",
+ screenfull: "readonly",
+ Uppie: "readonly",
+ PhotoSwipe: "readonly",
+ PhotoSwipeUI_Default: "readonly",
+ pdfjsLib: "readonly",
+ Plyr: "readonly",
+ },
+ parser: babelParser,
+ parserOptions: {
+ requireConfigFile: false,
+ babelOptions: {
+ babelrc: false,
+ configFile: false,
+ plugins: ["@babel/plugin-syntax-import-assertions"],
+ },
+ },
+ },
+ rules: {
+ "no-unused-vars": "warn",
+ "no-undef": "warn",
+ },
+ },
+ {
+ ignores: ["packages/svgstore/tests"],
+ },
+];
diff --git a/package.json b/package.json
index 289acfc2..351a3c2f 100644
--- a/package.json
+++ b/package.json
@@ -55,11 +55,16 @@
"yazl": "2.5.1"
},
"devDependencies": {
+ "@babel/core": "^7",
+ "@babel/eslint-parser": "^7.25.1",
+ "@babel/plugin-syntax-import-assertions": "^7.25.6",
+ "@eslint/eslintrc": "^3.1.0",
+ "@eslint/js": "^9.11.1",
"babel-jest": "^27.1.1",
"clean-css": "5.1.5",
- "eslint": "7.32.0",
- "eslint-config-silverwind": "18.0.2",
- "eslint-plugin-unicorn": "21.0.0",
+ "eslint": "9.11.1",
+ "eslint-config-standard": "^17.1.0",
+ "globals": "^15.9.0",
"html-minifier": "4.0.0",
"husky": "^7.0.2",
"jest": "^27.1.1",
@@ -93,7 +98,7 @@
],
"browserslist": "defaults",
"volta": {
- "node": "18.20.4",
+ "node": "20.17.0",
"yarn": "1.22.10"
},
"lint-staged": {
diff --git a/packages/cli/lib/cli.js b/packages/cli/lib/cli.js
index f4b8c75e..279c7151 100644
--- a/packages/cli/lib/cli.js
+++ b/packages/cli/lib/cli.js
@@ -2,19 +2,25 @@
"use strict";
-const fs = require("fs");
-const untildify = require("untildify");
-const path = require("path");
-const util = require("util");
+import fs from "fs";
+import untildify from "untildify";
+import path from "path";
+import util from "util";
+import { fileURLToPath } from "url";
-const pkg = require("../package.json");
+import pkg from "../package.json" with { type: "json" };
-const {server, paths, resources, log, cfg, db} = require("@droppyjs/server");
+import { server, paths, resources, log, cfg, db } from "@droppyjs/server";
+
+import minimist from "minimist";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
util.inspect.defaultOptions.depth = 4;
-const argv = require("minimist")(process.argv.slice(2), {
- boolean: ["color", "d", "daemon", "dev"]
+const argv = minimist(process.argv.slice(2), {
+ boolean: ["color", "d", "daemon", "dev"],
});
if (!argv.dev) {
@@ -36,7 +42,8 @@ const cmds = {
};
const opts = {
- configdir: "-c, --configdir
Config directory. Default: ~/.droppy/config",
+ configdir:
+ "-c, --configdir Config directory. Default: ~/.droppy/config",
filesdir: "-f, --filesdir Files directory. Default: ~/.droppy/files",
daemon: "-d, --daemon Daemonize (background) process",
log: "-l, --log Log to file instead of stdout",
@@ -60,7 +67,9 @@ if (argv.configdir || argv.filesdir || argv.c || argv.f) {
if (argv.log || argv.l) {
try {
- log.setLogFile(fs.openSync(untildify(path.resolve(argv.log || argv.l)), "a", "644"));
+ log.setLogFile(
+ fs.openSync(untildify(path.resolve(argv.log || argv.l)), "a", "644")
+ );
} catch (err) {
console.error(`Unable to open log file for writing: ${err.message}`);
process.exit(1);
@@ -81,7 +90,7 @@ switch (cmd) {
break;
case "start":
- server(null, true, argv.dev, err => {
+ server(null, true, argv.dev, (err) => {
if (err) {
log.error(err);
process.exit(1);
@@ -91,28 +100,30 @@ switch (cmd) {
case "stop": {
const ps = require("ps-node");
- ps.lookup({command: pkg.name}, async (err, procs) => {
+ ps.lookup({ command: pkg.name }, async (err, procs) => {
if (err) {
log.error(err);
process.exit(1);
} else {
- procs = procs.filter(proc => Number(proc.pid) !== process.pid);
+ procs = procs.filter((proc) => Number(proc.pid) !== process.pid);
if (!procs.length) {
log.info("No processes found");
process.exit(0);
}
- const pids = await Promise.all(procs.map(proc => {
- return new Promise(resolve => {
- ps.kill(proc.pid, err => {
- if (err) {
- log.error(err);
- return process.exit(1);
- }
- resolve(proc.pid);
+ const pids = await Promise.all(
+ procs.map((proc) => {
+ return new Promise((resolve) => {
+ ps.kill(proc.pid, (err) => {
+ if (err) {
+ log.error(err);
+ return process.exit(1);
+ }
+ resolve(proc.pid);
+ });
});
- });
- }));
+ })
+ );
if (pids.length) {
console.info(`Killed PIDs: ${pids.join(", ")}`);
@@ -125,7 +136,7 @@ switch (cmd) {
case "build":
console.info("Building resources ...");
- resources.build(err => {
+ resources.build((err) => {
console.info(err || "Resources built successfully");
process.exit(err ? 1 : 0);
});
@@ -138,14 +149,19 @@ switch (cmd) {
case "config": {
const ourPaths = paths.get();
const edit = () => {
- findEditor(editor => {
- if (!editor) return console.error(`No suitable editor found, please edit ${ourPaths.cfgFile}`);
- require("child_process").spawn(editor, [ourPaths.cfgFile], {stdio: "inherit"});
+ findEditor((editor) => {
+ if (!editor)
+ return console.error(
+ `No suitable editor found, please edit ${ourPaths.cfgFile}`
+ );
+ require("child_process").spawn(editor, [ourPaths.cfgFile], {
+ stdio: "inherit",
+ });
});
};
- fs.stat(ourPaths.cfgFile, err => {
+ fs.stat(ourPaths.cfgFile, (err) => {
if (err && err.code === "ENOENT") {
- fs.mkdir(ourPaths.config, {recursive: true}, async () => {
+ fs.mkdir(ourPaths.config, { recursive: true }, async () => {
try {
await cfg.init(null);
edit();
@@ -193,13 +209,13 @@ switch (cmd) {
function printHelp() {
let help = `Usage: ${pkg.name} command [options]\n\n Commands:`;
- Object.keys(cmds).forEach(command => {
+ Object.keys(cmds).forEach((command) => {
help += `\n ${cmds[command]}`;
});
help += "\n\n Options:";
- Object.keys(opts).forEach(option => {
+ Object.keys(opts).forEach((option) => {
help += `\n ${opts[option]}`;
});
@@ -211,16 +227,20 @@ function printUsers(users) {
if (Object.keys(users).length === 0) {
console.info("No users defined. Use 'add' to add one.");
} else {
- console.info(`Current Users:\n${Object.keys(users).map(user => {
- return ` - ${user}`;
- }).join("\n")}`);
+ console.info(
+ `Current Users:\n${Object.keys(users)
+ .map((user) => {
+ return ` - ${user}`;
+ })
+ .join("\n")}`
+ );
}
}
function findEditor(cb) {
- const editors = ["vim", "nano", "vi", "npp", "pico", "emacs", "notepad"];
- const basename = require("path").basename;
- const which = require("which");
+ const editors = ["vim", "nano", "vi", "npp", "pico", "emacs", "notepad"];
+ const basename = require("path").basename;
+ const which = require("which");
const userEditor = basename(process.env.VISUAL || process.env.EDITOR);
if (!editors.includes(userEditor)) {
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 81d43449..4e11ab9d 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -6,6 +6,7 @@
"homepage": "https://github.com/droppyjs/droppy#readme",
"license": "BSD-2-Clause",
"main": "lib/cli.js",
+ "type": "module",
"dependencies": {
"@droppyjs/server": "1.0.1",
"daemonize-process": "^3.0.0",
diff --git a/packages/client/lib/client.js b/packages/client/lib/client.js
index a735a438..0be01b59 100644
--- a/packages/client/lib/client.js
+++ b/packages/client/lib/client.js
@@ -1,9 +1,9 @@
"use strict";
function promisify(fn) {
- return function() {
- return new Promise(resolve => {
- fn(result => resolve(result));
+ return function () {
+ return new Promise((resolve) => {
+ fn((result) => resolve(result));
});
};
}
@@ -18,43 +18,52 @@ initVariables();
// Feature Detects
// ============================================================================
droppy.detects = {
- directoryUpload: (function() {
+ directoryUpload: (function () {
const el = document.createElement("input");
return droppy.dir.some((prop) => {
return prop in el;
});
})(),
- audioTypes: (function() {
+ audioTypes: (function () {
const types = {},
el = document.createElement("audio");
Object.keys(droppy.audioTypes).forEach((type) => {
- types[droppy.audioTypes[type]] = Boolean(el.canPlayType(droppy.audioTypes[type]).replace(/no/, ""));
+ types[droppy.audioTypes[type]] = Boolean(
+ el.canPlayType(droppy.audioTypes[type]).replace(/no/, "")
+ );
});
return types;
})(),
- videoTypes: (function() {
+ videoTypes: (function () {
const types = {},
el = document.createElement("video");
Object.keys(droppy.videoTypes).forEach((type) => {
- types[droppy.videoTypes[type]] = Boolean(el.canPlayType(droppy.videoTypes[type]).replace(/no/, ""));
+ types[droppy.videoTypes[type]] = Boolean(
+ el.canPlayType(droppy.videoTypes[type]).replace(/no/, "")
+ );
});
return types;
})(),
- webp: document.createElement("canvas").toDataURL("image/webp").indexOf("data:image/webp") === 0,
+ webp:
+ document
+ .createElement("canvas")
+ .toDataURL("image/webp")
+ .indexOf("data:image/webp") === 0,
notification: "Notification" in window,
mobile: /Mobi/.test(navigator.userAgent),
- safari: /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
+ safari:
+ /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
};
// Transition of freshly inserted elements
-$.fn.transition = function(oldClass, newClass) {
+$.fn.transition = function (oldClass, newClass) {
if (!newClass) {
newClass = oldClass;
oldClass = null;
}
- // Force a reflow
- // https://gist.github.com/paulirish/5d52fb081b3570c81e3a
+ // Force a reflow
+ // https://gist.github.com/paulirish/5d52fb081b3570c81e3a
this.r = this[0].offsetTop;
delete this.r;
@@ -68,9 +77,10 @@ $.fn.transition = function(oldClass, newClass) {
};
// transitionend helper, makes sure the callback gets fired regardless if the transition gets cancelled
-$.fn.transitionend = function(callback) {
+$.fn.transitionend = function (callback) {
if (!this.length) return;
- let duration, called = false;
+ let duration,
+ called = false;
const el = this[0];
function doCallback(event) {
@@ -80,18 +90,24 @@ $.fn.transitionend = function(callback) {
}
duration = getComputedStyle(el).transitionDuration;
- duration = (duration.includes("ms")) ? parseFloat(duration) : parseFloat(duration) * 1000;
+ duration = duration.includes("ms")
+ ? parseFloat(duration)
+ : parseFloat(duration) * 1000;
- setTimeout(() => { // Call back if "transitionend" hasn't fired in duration + 30
- doCallback({target: el}); // Just mimic the event.target property on our fake event
+ setTimeout(() => {
+ // Call back if "transitionend" hasn't fired in duration + 30
+ doCallback({ target: el }); // Just mimic the event.target property on our fake event
}, duration + 30);
return this.one("transitionend", doCallback);
};
// Class swapping helper
-$.fn.replaceClass = function(search, replacement) {
- let el, classes, matches, i = this.length,
+$.fn.replaceClass = function (search, replacement) {
+ let el,
+ classes,
+ matches,
+ i = this.length,
hasClass = false;
while (--i >= 0) {
el = this[i];
@@ -100,9 +116,13 @@ $.fn.replaceClass = function(search, replacement) {
if (className === search) return false;
if (className === replacement) hasClass = true;
- matches = search instanceof RegExp ? search.exec(className) : className.match(search);
- // filter out if the entire capture matches the entire className
- if (matches) return matches[0] !== className || matches[0] === replacement;
+ matches =
+ search instanceof RegExp
+ ? search.exec(className)
+ : className.match(search);
+ // filter out if the entire capture matches the entire className
+ if (matches)
+ return matches[0] !== className || matches[0] === replacement;
else return true;
});
if (!hasClass) classes.push(replacement);
@@ -115,21 +135,23 @@ $.fn.replaceClass = function(search, replacement) {
return this;
};
-Handlebars.registerHelper("select", function(sel, opts) {
+Handlebars.registerHelper("select", function (sel, opts) {
return opts.fn(this).replace(new RegExp(` value="${sel}"`), "$& selected=");
});
-Handlebars.registerHelper("is", function(a, b, opts) {
+Handlebars.registerHelper("is", function (a, b, opts) {
return a === b ? opts.fn(this) : opts.inverse(this);
});
function svg(which) {
- // Manually clone instead of