just-kit 0.8.0

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.
package/just-kit.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * just-kit – small collection of lightweight JavaScript utilities
3
+ *
4
+ * @module just-kit
5
+ */
6
+
7
+ export { default as Next } from './just-next.js';
8
+ export { default as JustPool } from './just-pool.js';
9
+ export { default as Prompt } from './just-prompt.js';
package/just-next.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * NextUp - Simple sequential or random cycling through a list of items
3
+ */
4
+
5
+ const MODE_SEQUENTIAL = 'sequential';
6
+ const MODE_RANDOM = 'random';
7
+
8
+ export default class Next {
9
+ #items = [];
10
+ #mode = MODE_SEQUENTIAL;
11
+ #index = 0;
12
+
13
+ /**
14
+ * @param {any[]} [items=[]] Initial items
15
+ * @param {'sequential'|'random'} [mode='sequential']
16
+ */
17
+ constructor(items = [], mode = MODE_SEQUENTIAL) {
18
+ this.setItems(items);
19
+ this.setMode(mode);
20
+ }
21
+
22
+ /** Replace all items and reset position */
23
+ setItems(items) {
24
+ if (!Array.isArray(items)) throw new Error('Items must be an array');
25
+ this.#items = [...items];
26
+ this.#index = 0;
27
+ }
28
+
29
+ /** Add one or more items */
30
+ add(...items) {
31
+ this.#items.push(...items);
32
+ }
33
+
34
+ /** Set retrieval mode */
35
+ setMode(mode) {
36
+ if (![MODE_SEQUENTIAL, MODE_RANDOM].includes(mode)) {
37
+ throw new Error("Mode must be 'sequential' or 'random'");
38
+ }
39
+ this.#mode = mode;
40
+ }
41
+
42
+ /** Get current mode */
43
+ get mode() {
44
+ return this.#mode;
45
+ }
46
+
47
+ /** Get current number of items */
48
+ get length() {
49
+ return this.#items.length;
50
+ }
51
+
52
+ /** Reset position to beginning (affects sequential mode only) */
53
+ reset() {
54
+ this.#index = 0;
55
+ }
56
+
57
+ /** Get next item according to current mode */
58
+ next() {
59
+ if (this.#items.length === 0) return undefined;
60
+
61
+ if (this.#mode === MODE_RANDOM) {
62
+ const i = Math.floor(Math.random() * this.#items.length);
63
+ return this.#items[i];
64
+ }
65
+
66
+ // sequential
67
+ const item = this.#items[this.#index];
68
+ this.#index = (this.#index + 1) % this.#items.length;
69
+ return item;
70
+ }
71
+
72
+ /** Preview next item without advancing position */
73
+ peek() {
74
+ if (this.#items.length === 0) return undefined;
75
+
76
+ if (this.#mode === MODE_RANDOM) {
77
+ const i = Math.floor(Math.random() * this.#items.length);
78
+ return this.#items[i];
79
+ }
80
+
81
+ return this.#items[this.#index];
82
+ }
83
+
84
+ /** Get a shallow copy of all items */
85
+ getAll() {
86
+ return [...this.#items];
87
+ }
88
+
89
+ /** Remove all items */
90
+ clear() {
91
+ this.#items = [];
92
+ this.#index = 0;
93
+ }
94
+ }
95
+
package/just-pool.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * JustPool – lazy instance creator & holder
3
+ * Creates objects only when first requested via .get(key)
4
+ * Reuses the same instance on repeated .get() calls with same key
5
+ */
6
+ export default class JustPool {
7
+ /**
8
+ * @param {function(key: any): T} factory - called to create new instance when needed
9
+ */
10
+ constructor(factory) {
11
+ if (typeof factory !== 'function') {
12
+ throw new TypeError('Factory must be a function');
13
+ }
14
+
15
+ this.factory = factory;
16
+ this.cache = Object.create(null);
17
+ }
18
+
19
+ /**
20
+ * Get (or lazily create) the instance for given key
21
+ * @param {any} key
22
+ * @returns {T}
23
+ */
24
+ get(key) {
25
+ if (key in this.cache) {
26
+ return this.cache[key];
27
+ }
28
+
29
+ const instance = this.factory(key);
30
+ this.cache[key] = instance;
31
+ return instance;
32
+ }
33
+
34
+ /**
35
+ * Check if an instance already exists for this key
36
+ */
37
+ has(key) {
38
+ return key in this.cache;
39
+ }
40
+
41
+ /**
42
+ * Remove instance for given key
43
+ * @returns {boolean} true if something was removed
44
+ */
45
+ delete(key) {
46
+ if (key in this.cache) {
47
+ delete this.cache[key];
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+
53
+ /**
54
+ * Clear all cached instances
55
+ */
56
+ clear() {
57
+ this.cache = Object.create(null);
58
+ }
59
+
60
+ /**
61
+ * Approximate number of cached items
62
+ */
63
+ size() {
64
+ return Object.keys(this.cache).length;
65
+ }
66
+
67
+ /**
68
+ * Get all currently used keys (only string/symbol keys are enumerated)
69
+ */
70
+ keys() {
71
+ return Object.keys(this.cache);
72
+ }
73
+
74
+ /**
75
+ * Get all cached values
76
+ */
77
+ values() {
78
+ return Object.values(this.cache);
79
+ }
80
+
81
+ /**
82
+ * Iterate over all cached entries
83
+ * @param {(value: T, key: any) => void} callback
84
+ */
85
+ forEach(callback) {
86
+ for (const key in this.cache) {
87
+ if (Object.hasOwn(this.cache, key)) {
88
+ callback(this.cache[key], key);
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+
package/just-prompt.js ADDED
@@ -0,0 +1,53 @@
1
+ import readline from 'readline';
2
+
3
+ export default class Prompt {
4
+ #rl;
5
+ #onexit;
6
+
7
+ constructor(message, targetCommand, work) {
8
+ this.message = message;
9
+ this.targetCommand = targetCommand;
10
+ this.work = work;
11
+ this.#rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout
14
+ });
15
+ }
16
+
17
+ onExit(callback) {
18
+ this.#onexit = callback;
19
+ }
20
+
21
+ write(message) {
22
+ process.stdout.write(message);
23
+ }
24
+
25
+ // Start prompting the user
26
+ start() {
27
+ return new Promise((resolve) => {
28
+ const ask = () => {
29
+ this.#rl.question(this.message, async (input) => {
30
+ const trimmed = input.trim();
31
+
32
+ if (trimmed.toLowerCase() === this.targetCommand.toLowerCase()) {
33
+ this.stop();
34
+ resolve(input);
35
+ } else {
36
+ await this.work(trimmed);
37
+ ask();
38
+ }
39
+ });
40
+ };
41
+ ask();
42
+ });
43
+ }
44
+
45
+ // Stop the readline interface
46
+ stop() {
47
+ this.#rl.close();
48
+ this.#onexit?.();
49
+ }
50
+
51
+ static app = (message, targetCommand, work) => new Prompt(message, targetCommand, work);
52
+ }
53
+
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "just-kit",
3
+ "version": "0.8.0",
4
+ "description": "simple nodejs utility",
5
+ "keywords": [
6
+ "just",
7
+ "just-kit",
8
+ "prompt",
9
+ "next",
10
+ "pool"
11
+ ],
12
+ "homepage": "https://github.com/just-node/just-kit#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/just-node/just-kit/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/just-node/just-kit.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "littlejustnode",
22
+ "type": "module",
23
+ "main": "just-kit.js",
24
+ "scripts": {
25
+ "test": "n/a"
26
+ }
27
+ }
package/test.js ADDED
@@ -0,0 +1,22 @@
1
+ import { Next, JustPool, Prompt } from './just-kit.js';
2
+
3
+ // 1. Cycling list
4
+ const playlist = new Next(['song1.mp3', 'song2.mp3', 'song3.mp3'], 'random');
5
+ console.log(playlist.next()); // → random song
6
+ console.log(playlist.peek()); // → another (or same) random song
7
+
8
+ // 2. Lazy pool
9
+ const dbPool = new JustPool((dbName) => "hello: "+dbName);
10
+ const db1 = dbPool.get('users'); // created once
11
+ const db2 = dbPool.get('users'); // same instance
12
+
13
+
14
+
15
+
16
+ Prompt.app(
17
+ 'Type your message (type "exit" to quit): ',
18
+ 'exit',
19
+ async (input) => {
20
+ console.log(`You said: ${input}`);
21
+ }
22
+ ).start();