tiny-essentials 1.26.0 → 1.26.2

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.
@@ -0,0 +1,174 @@
1
+ # 🛠️ TinyClassManager
2
+
3
+ Welcome to **TinyClassManager**! This is a lightweight, linear mixin manager designed to compose base classes with optional modules (like features or "DLCs") in a safe, predictable, and sequential way. It handles dependencies and prevents multiple class reuses automatically.
4
+
5
+ ---
6
+
7
+ ## 🚀 Key Features
8
+
9
+ * **🔒 Immutable Chain State:** Each `.use()` call consumes the previous manager, preventing unwanted side effects or weird mutations.
10
+ * **🧩 Dependency Verification:** Automatically ensures that a required plugin is loaded before the dependent plugin is applied.
11
+ * **🛑 Conflict Protection:** Prevents you from installing the exact same plugin twice on the same class chain.
12
+
13
+ ---
14
+
15
+ ## 📐 API Overview
16
+
17
+ ### `TinyClassManager<T>`
18
+
19
+ #### Properties
20
+
21
+ * **`appliedPlugins`** (`string[]`): Returns an array of the names of all successfully installed plugins so far.
22
+ * **`size`** (`number`): The total count of applied plugins plus the core base class.
23
+ * **`currentClass`** (`T`): Accesses the current state of the class chain inside the manager.
24
+ * **`used`** (`boolean`): Indicates whether this specific manager instance has already been transitioned or finalized.
25
+
26
+ #### Methods
27
+
28
+ * **`constructor(coreClass)`**: Initialises the manager with your foundational core class.
29
+ * **`use(plugin)`**: Applies a new plugin to the chain. Returns a *new* `TinyClassManager` instance containing the extended class.
30
+ * **`build()`**: Finalizes the composition chain, marks the instance as consumed, and returns the fully compiled class ready for instantiation.
31
+
32
+ ---
33
+
34
+ ## 📖 Detailed Usage Guide & Step-by-Step Example
35
+
36
+ Let's break down exactly how to design, extend, and instantiate a class structure using `TinyClassManager`. You can mirror this step-by-step blueprint for your own features!
37
+
38
+ ### Step 1: Establish the Core Base 🧱
39
+
40
+ Every structure needs a solid foundation. The core class is the absolute minimum requirement and contains properties that every subsequent plugin might rely on.
41
+
42
+ ```javascript
43
+ import TinyClassManager from '../TinyClassManager.mjs';
44
+
45
+ // The foundational class
46
+ class EntityCore {
47
+ /**
48
+ * @param {string} id
49
+ */
50
+ constructor(id) {
51
+ /** @type {string} */
52
+ this.id = id;
53
+ }
54
+ }
55
+
56
+ ```
57
+
58
+ ### Step 2: Create an Independent Module 🏷️
59
+
60
+ Now, let's create our first module. A plugin is just a plain object with three specific keys: `name`, `dependencies`, and `apply`. This module doesn't depend on anything else, so its dependencies array is empty.
61
+
62
+ ```javascript
63
+ const Health = {
64
+ name: 'Health',
65
+ dependencies: [], // Works fine straight out of the box with the Core
66
+
67
+ /**
68
+ * @param {typeof EntityCore} Base - The incoming base class to extend.
69
+ */
70
+ apply: (Base) =>
71
+ class HealthModule extends Base {
72
+ /**
73
+ * @param {string} id
74
+ */
75
+ constructor(id) {
76
+ super(id); // Always remember to pass arguments down!
77
+
78
+ /** @type {number} */
79
+ this.hp = 100;
80
+ }
81
+
82
+ /**
83
+ * Deducts health from the entity.
84
+ * @param {number} amount - The amount of raw damage to deal.
85
+ */
86
+ takeDamage(amount) {
87
+ this.hp -= amount;
88
+ console.log(`Took ${amount} damage. HP left: ${this.hp}`);
89
+ }
90
+ },
91
+ };
92
+
93
+ ```
94
+
95
+ ### Step 3: Create a Dependent Module 🛡️
96
+
97
+ Here is where the magic happens! The `Armor` module strictly requires the `Health` module to be loaded first because it relies on overriding the `takeDamage` logic. We enforce this relationship inside the `dependencies` array.
98
+
99
+ ```javascript
100
+ const Armor = {
101
+ name: 'Armor',
102
+ dependencies: ['Health'], // Strictly requires the "Health" module!
103
+
104
+ /**
105
+ * @param {ReturnType<typeof Health.apply>} Base - The class containing Health features.
106
+ */
107
+ apply: (Base) =>
108
+ class ArmorModule extends Base {
109
+ /**
110
+ * @param {string} id
111
+ */
112
+ constructor(id) {
113
+ super(id);
114
+
115
+ /** @type {number} */
116
+ this.armor = 50;
117
+ }
118
+
119
+ /**
120
+ * Deducts health, factoring in damage mitigation provided by armor.
121
+ * @param {number} amount - The initial damage before armor reduction.
122
+ */
123
+ takeDamage(amount) {
124
+ // Mitigates damage using the armor stat
125
+ const reducedDamage = Math.max(0, amount - this.armor * 0.1);
126
+
127
+ // Pass the mitigated damage up to the Health layer
128
+ super.takeDamage(reducedDamage);
129
+ }
130
+ },
131
+ };
132
+
133
+ ```
134
+
135
+ ### Step 4: Chain and Build Your Custom Class 🏗️
136
+
137
+ Finally, use the manager to safely piece your modules together. Remember that `TinyClassManager` uses an explosive state pattern: once you run `.use()` or `.build()`, that specific instance is closed, forcing you to use the new returned chain instance.
138
+
139
+ ```javascript
140
+ try {
141
+ // 1. Wrap your core class
142
+ const CoreTest = new TinyClassManager(EntityCore);
143
+
144
+ // 2. Chain your modules and compile!
145
+ // If you try to swap the order (.use(Armor).use(Health)), it will throw an explicit dependency error.
146
+ const FullyArmoredEntity = CoreTest.use(Health).use(Armor).build();
147
+
148
+ // 3. Create your custom instance!
149
+ const myEntity = new FullyArmoredEntity('Player_1');
150
+
151
+ // 4. Test out the behaviors
152
+ myEntity.takeDamage(30);
153
+ // Output: "Took 25 damage. HP left: 75" (30 damage - 5 armor reduction = 25 damage)
154
+
155
+ console.log(`Armor value: ${myEntity.armor}`); // Output: Armor value: 50
156
+ console.log(`Current HP: ${myEntity.hp}`); // Output: Current HP: 75
157
+
158
+ } catch (error) {
159
+ if (error instanceof Error) {
160
+ console.error(error.message);
161
+ }
162
+ }
163
+
164
+ ```
165
+
166
+ ---
167
+
168
+ ## 💡 How to Mimic This Pattern
169
+
170
+ When you want to build a new set of mechanics for your game or application using this architecture, always remember to follow this loop:
171
+
172
+ 1. **Define your Base State**: Keep it clean and focused on global data configurations.
173
+ 2. **Declare Plugins as Pure Objects**: Always structure them with `name`, `dependencies` (an array of strings matching other plugin names), and an `apply` method.
174
+ 3. **Use `super` Inheritances**: Inside your plugin classes, always call `super(...)` in constructors and use `super.methodName(...)` if you are overriding an existing skill or function to allow all mixed behaviors to fire smoothly down the pipeline!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-essentials",
3
- "version": "1.26.0",
3
+ "version": "1.26.2",
4
4
  "description": "Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.",
5
5
  "bin": {
6
6
  "tiny-essentials-fork": "./TinyFork.mjs"
@@ -268,6 +268,10 @@
268
268
  "require": "./dist/v1/libs/TinyAdvancedRaffle.cjs",
269
269
  "import": "./dist/v1/libs/TinyAdvancedRaffle.mjs"
270
270
  },
271
+ "./libs/TinyClassManager": {
272
+ "require": "./dist/v1/libs/TinyClassManager.cjs",
273
+ "import": "./dist/v1/libs/TinyClassManager.mjs"
274
+ },
271
275
  "./libs/TinyMamdaniInferenceSystem": {
272
276
  "require": "./dist/v1/libs/TinyMamdaniInferenceSystem.cjs",
273
277
  "import": "./dist/v1/libs/TinyMamdaniInferenceSystem.mjs"
File without changes