From 2994169bc5f13d42212d1fc53efe4b747092c7a7 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Sun, 23 Jun 2024 18:01:01 +0200 Subject: [PATCH 1/6] ESLint fix --- src/env/node.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/env/node.js b/src/env/node.js index 9753be8..dff0b40 100644 --- a/src/env/node.js +++ b/src/env/node.js @@ -1,16 +1,16 @@ // Native Node packages import fs from "fs"; import path from "path"; -import * as readline from 'node:readline'; +import * as readline from "node:readline"; // Dependencies -import logUpdate from 'log-update'; -import { AsciiTree } from 'oo-ascii-tree'; -import { globSync } from 'glob'; +import logUpdate from "log-update"; +import { AsciiTree } from "oo-ascii-tree"; +import { globSync } from "glob"; // Internal modules import format from "../format-console.js"; -import { getType } from '../util.js'; +import { getType } from "../util.js"; /** * Recursively traverse a subtree starting from `node` @@ -102,7 +102,7 @@ export default { format: "rich", get location () { return process.cwd(); - } + }, }, resolveLocation: async function (location) { if (fs.statSync(location).isDirectory()) { @@ -258,5 +258,5 @@ Use any other key to quit interactive mode. if (root.stats.fail > 0) { process.exitCode = 1; } - } -} + }, +}; From 407a8757ebc436b71944b5d42d26bc3d41d48a4f Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Sun, 23 Jun 2024 18:10:23 +0200 Subject: [PATCH 2/6] Ensure fresh copies are imported between the runs See https://github.com/sindresorhus/import-fresh#esm The author of this snippet stated that it causes memory leaks, so this method needs to be used with caution. --- src/env/node.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/env/node.js b/src/env/node.js index dff0b40..6eaf23c 100644 --- a/src/env/node.js +++ b/src/env/node.js @@ -91,7 +91,8 @@ async function getTestsIn (dir) { let cwd = process.cwd(); let paths = filenames.map(name => path.join(cwd, dir, name)); - return Promise.all(paths.map(path => import(path).then(module => module.default, err => { + // FIXME: Causes a memory leak. Any other workaround? + return Promise.all(paths.map(path => import(`${path}?${Date.now()}`).then(module => module.default, err => { console.error(`Error importing tests from ${path}:`, err); }))); } @@ -116,7 +117,7 @@ export default { paths = getType(paths) === "string" ? [paths] : paths; return paths.map(p => { p = path.join(process.cwd(), p); - return import(p).then(m => m.default ?? m); + return import(`${p}?${Date.now()}`).then(m => m.default ?? m); // FIXME: Causes a memory leak. Any other workaround? }); }); From 2de4b0a796fca0e1a38669adfdec7f1d862abeeb Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 24 Jun 2024 10:23:56 +0200 Subject: [PATCH 3/6] Import the built-in process --- src/env/node.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/env/node.js b/src/env/node.js index 6eaf23c..fdda1f2 100644 --- a/src/env/node.js +++ b/src/env/node.js @@ -1,6 +1,7 @@ // Native Node packages import fs from "fs"; import path from "path"; +import process from "node:process"; import * as readline from "node:readline"; // Dependencies From db45e27a184fa835d9a39657f01af7c42409ea97 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 24 Jun 2024 10:25:08 +0200 Subject: [PATCH 4/6] Provide a way to re-run the tests --- src/env/node.js | 214 +++++++++++++++++++++++++++--------------------- 1 file changed, 120 insertions(+), 94 deletions(-) diff --git a/src/env/node.js b/src/env/node.js index fdda1f2..982b632 100644 --- a/src/env/node.js +++ b/src/env/node.js @@ -12,6 +12,7 @@ import { globSync } from "glob"; // Internal modules import format from "../format-console.js"; import { getType } from "../util.js"; +import run from "../run.js"; /** * Recursively traverse a subtree starting from `node` @@ -98,6 +99,16 @@ async function getTestsIn (dir) { }))); } +/** + * Options shared between runs of the tests. + */ +let shared = { + firstRun: true, + location: undefined, // location of the tests + root: undefined, + active: undefined, // active (highlighted) group of tests that can be expanded/collapsed; root by default +}; + export default { name: "Node.js", defaultOptions: { @@ -107,6 +118,8 @@ export default { }, }, resolveLocation: async function (location) { + shared.location = location; + if (fs.statSync(location).isDirectory()) { // Directory provided, fetch all files return getTestsIn(location); @@ -136,125 +149,138 @@ export default { if (root.stats.pending === 0) { logUpdate.clear(); - let hint = ` + root.highlighted = true; + shared.root = root; + shared.active = root; + + if (!shared.firstRun) { + render(root, options); + } + else { + shared.firstRun = false; + + let hint = ` Use and arrow keys to navigate groups of tests, and to expand and collapse them, respectively. Use Ctrl+↑ and Ctrl+↓ to go to the first or last child group of the current group. To expand or collapse the current group and all its subgroups, use Ctrl+→ and Ctrl+←. Press Ctrl+Shift+→ and Ctrl+Shift+← to expand or collapse all groups, regardless of the current group. -Use any other key to quit interactive mode. +Press R to re-run the tests. Use any other key to quit interactive mode. `; - hint = format(hint); - console.log(hint); + hint = format(hint); + console.log(hint); - readline.emitKeypressEvents(process.stdin); - process.stdin.setRawMode(true); // handle keypress events instead of Node + readline.emitKeypressEvents(process.stdin); + process.stdin.setRawMode(true); // handle keypress events instead of Node - root.highlighted = true; - render(root, options); + render(root, options); - let active = root; // active (highlighted) group of tests that can be expanded/collapsed; root by default - process.stdin.on("keypress", (character, key) => { - let name = key.name; + process.stdin.on("keypress", (character, key) => { + let name = key.name; + let root = shared.root; - if (name === "up") { - // Figure out what group of tests is active (and should be highlighted) - let groups = getVisibleGroups(root, options); + if (name === "up") { + // Figure out what group of tests is active (and should be highlighted) + let groups = getVisibleGroups(root, options); - if (key.ctrl) { - let parent = active.parent; - if (parent) { - active = groups.filter(group => group.parent === parent)[0]; // the first one from all groups with the same parent + if (key.ctrl) { + let parent = shared.active.parent; + if (parent) { + shared.active = groups.filter(group => group.parent === parent)[0]; // the first one from all groups with the same parent + } } - } - else { - let index = groups.indexOf(active); - index = Math.max(0, index - 1); // choose the previous group, but don't go higher than the root - active = groups[index]; - } - - for (let group of groups) { - group.highlighted = false; - } - active.highlighted = true; - render(root, options); - } - else if (name === "down") { - let groups = getVisibleGroups(root, options); - - if (key.ctrl) { - let parent = active.parent; - if (parent) { - active = groups.filter(group => group.parent === parent).at(-1); // the last one from all groups with the same parent + else { + let index = groups.indexOf(shared.active); + index = Math.max(0, index - 1); // choose the previous group, but don't go higher than the root + shared.active = groups[index]; } - } - else { - let index = groups.indexOf(active); - index = Math.min(groups.length - 1, index + 1); // choose the next group, but don't go lower than the last one - active = groups[index]; - } - for (let group of groups) { - group.highlighted = false; - } - active.highlighted = true; - render(root, options); - } - else if (name === "left") { - if (key.ctrl && key.shift) { - // Collapse all groups on Ctrl+Shift+← - let groups = getVisibleGroups(root, options); for (let group of groups) { group.highlighted = false; } - - setCollapsed(root); - active = root; - active.highlighted = true; - render(root, options); - } - else if (key.ctrl) { - // Collapse the current group and all its subgroups on Ctrl+← - setCollapsed(active); + shared.active.highlighted = true; render(root, options); } - else if (active.collapsed === false) { - active.collapsed = true; - render(root, options); - } - else if (active.parent) { - // If the current group is collapsed, collapse its parent group + else if (name === "down") { let groups = getVisibleGroups(root, options); - let index = groups.indexOf(active.parent); - active = groups[index]; - active.collapsed = true; - groups = groups.map(group => group.highlighted = false); - active.highlighted = true; + if (key.ctrl) { + let parent = shared.active.parent; + if (parent) { + shared.active = groups.filter(group => group.parent === parent).at(-1); // the last one from all groups with the same parent + } + } + else { + let index = groups.indexOf(shared.active); + index = Math.min(groups.length - 1, index + 1); // choose the next group, but don't go lower than the last one + shared.active = groups[index]; + } + + for (let group of groups) { + group.highlighted = false; + } + shared.active.highlighted = true; render(root, options); } - } - else if (name === "right") { - if (key.ctrl && key.shift) { - // Expand all groups on Ctrl+Shift+→ - setCollapsed(root, false); - render(root, options); + else if (name === "left") { + if (key.ctrl && key.shift) { + // Collapse all groups on Ctrl+Shift+← + let groups = getVisibleGroups(root, options); + for (let group of groups) { + group.highlighted = false; + } + + setCollapsed(root); + shared.active = root; + shared.active.highlighted = true; + render(root, options); + } + else if (key.ctrl) { + // Collapse the current group and all its subgroups on Ctrl+← + setCollapsed(shared.active); + render(root, options); + } + else if (shared.active.collapsed === false) { + shared.active.collapsed = true; + render(root, options); + } + else if (shared.active.parent) { + // If the current group is collapsed, collapse its parent group + let groups = getVisibleGroups(root, options); + let index = groups.indexOf(shared.active.parent); + shared.active = groups[index]; + shared.active.collapsed = true; + + groups = groups.map(group => group.highlighted = false); + shared.active.highlighted = true; + render(root, options); + } } - else if (key.ctrl) { - // Expand the current group and all its subgroups on Ctrl+→ - setCollapsed(active, false); - render(root, options); + else if (name === "right") { + if (key.ctrl && key.shift) { + // Expand all groups on Ctrl+Shift+→ + setCollapsed(root, false); + render(root, options); + } + else if (key.ctrl) { + // Expand the current group and all its subgroups on Ctrl+→ + setCollapsed(shared.active, false); + render(root, options); + } + else if (shared.active.collapsed === true) { + shared.active.collapsed = false; + render(root, options); + } } - else if (active.collapsed === true) { - active.collapsed = false; - render(root, options); + else if (name === "r") { + run(shared.location, {...options}); } - } - else { - // Quit interactive mode on any other key - logUpdate.done(); - process.exit(); - } - }); + else { + // Quit interactive mode on any other key + logUpdate.done(); + process.exit(); + } + }); + } } if (root.stats.fail > 0) { From 38253d5a0f9720f40c87b7879c166431317b51fe Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 24 Jun 2024 10:29:47 +0200 Subject: [PATCH 5/6] Add basic support for the watch mode --- package-lock.json | 182 ++++++++++++++++++++++------------------------ package.json | 1 + src/cli.js | 17 ++++- 3 files changed, 104 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6ca4890..0e66a25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.15", "license": "MIT", "dependencies": { + "chokidar": "^3.6.0", "glob": "^10.3.10", "log-update": "^6.0.0", "oo-ascii-tree": "^1.91.0" @@ -1454,7 +1455,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1689,7 +1689,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, "engines": { "node": ">=8" } @@ -1768,12 +1767,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2074,7 +2072,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3451,10 +3448,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3648,7 +3644,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -3820,7 +3815,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4553,10 +4547,23 @@ "node": ">= 0.10" } }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, "node_modules/is-alphabetical": { @@ -4635,7 +4642,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -4748,7 +4754,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4765,7 +4770,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -4862,7 +4866,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -5172,6 +5175,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5919,7 +5928,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6258,13 +6266,12 @@ } }, "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "dependencies": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -6497,7 +6504,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -6754,7 +6760,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -7428,16 +7433,16 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -7455,12 +7460,6 @@ "node": ">= 14" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7755,7 +7754,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -8369,9 +8367,9 @@ } }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -9477,7 +9475,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -9637,8 +9634,7 @@ "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bl": { "version": "5.1.0", @@ -9701,12 +9697,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "buffer": { @@ -9909,7 +9904,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -10877,10 +10871,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -11030,7 +11023,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "optional": true }, "function-bind": { @@ -11169,7 +11161,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -11657,11 +11648,23 @@ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, - "ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", - "dev": true + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + } + } }, "is-alphabetical": { "version": "2.0.1", @@ -11719,7 +11722,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "requires": { "binary-extensions": "^2.0.0" } @@ -11788,8 +11790,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -11800,7 +11801,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -11857,8 +11857,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.0.7", @@ -12069,6 +12068,12 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -12617,8 +12622,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-url": { "version": "8.0.0", @@ -12848,13 +12852,12 @@ } }, "pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "requires": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" } }, @@ -13028,8 +13031,7 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "2.3.0", @@ -13219,7 +13221,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "requires": { "picomatch": "^2.2.1" } @@ -13695,21 +13696,13 @@ "dev": true }, "socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "requires": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" - }, - "dependencies": { - "ip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", - "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", - "dev": true - } } }, "socks-proxy-agent": { @@ -13932,7 +13925,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -14388,9 +14380,9 @@ } }, "ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 5152df3..460fd02 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "typedoc": "^0.25.12" }, "dependencies": { + "chokidar": "^3.6.0", "glob": "^10.3.10", "log-update": "^6.0.0", "oo-ascii-tree": "^1.91.0" diff --git a/src/cli.js b/src/cli.js index adf248c..6850199 100755 --- a/src/cli.js +++ b/src/cli.js @@ -4,6 +4,9 @@ import { globSync } from "glob"; import env from "./env/node.js"; import run from "./run.js"; +// Dependencies +import * as chokidar from "chokidar"; + const CONFIG_GLOB = "{,_,.}htest.{json,config.json,config.js}"; let config; @@ -50,5 +53,17 @@ export default async function cli (options = {}) { options.path = argv[1]; } - run(location, {env, ...options}); + if (options.watch) { + const watcher = chokidar.watch(location, { + persistent: true, + }); + + watcher.on("all", path => { + // TODO: Re-run the tests that *actually* changed + run(location, {env, ...options}); + }); + } + else { + run(location, {env, ...options}); + } } \ No newline at end of file From 7531d6a04b03d32ad548695db77fd7bf07f6c5fb Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 24 Jun 2024 14:45:24 +0200 Subject: [PATCH 6/6] Listen to the `change` event only --- src/cli.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cli.js b/src/cli.js index 6850199..50883a8 100755 --- a/src/cli.js +++ b/src/cli.js @@ -58,12 +58,11 @@ export default async function cli (options = {}) { persistent: true, }); - watcher.on("all", path => { - // TODO: Re-run the tests that *actually* changed + // TODO: Re-run the tests that *actually* changed + watcher.on("change", path => { run(location, {env, ...options}); }); } - else { - run(location, {env, ...options}); - } + + run(location, {env, ...options}); } \ No newline at end of file