@vicin/sigil 3.3.0 → 3.4.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/CHANGELOG.md +18 -1
- package/README.md +111 -70
- package/dist/index.d.mts +58 -55
- package/dist/index.d.ts +58 -55
- package/dist/index.global.js +93 -227
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +93 -227
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +92 -228
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [3.4.0] - 2026-02-28
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Updated internal logic to handle edge-cases
|
|
10
|
+
- Edge cases part added to tests
|
|
11
|
+
- Updated README.md
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `AttachSigil` / `attachSigil` which are `WithSigil` / `withSigil` renamed for clarity
|
|
16
|
+
|
|
17
|
+
### Deprecated
|
|
18
|
+
|
|
19
|
+
- `WithSigil` / `withSigil` renamed for clarity. old names will be removed in v4
|
|
20
|
+
- `SigilLabelSet` / `getSigilLabelSet` methods to minimize api surface and bundle size as they are redundant (internall 'new Set(this.SigilLabelLineage)' only). will be removed in v4
|
|
21
|
+
|
|
5
22
|
## [3.3.0] - 2026-02-27
|
|
6
23
|
|
|
7
24
|
### Changed
|
|
@@ -27,7 +44,7 @@ All notable changes to this project will be documented in this file.
|
|
|
27
44
|
|
|
28
45
|
### Deprecated
|
|
29
46
|
|
|
30
|
-
- `DEFAULT_LABEL_REGEX` is deprecated
|
|
47
|
+
- `DEFAULT_LABEL_REGEX` is deprecated use `RECOMMENDED_LABEL_REGEX` instead, will be removed in v4
|
|
31
48
|
|
|
32
49
|
## [3.1.4] - 2026-02-26
|
|
33
50
|
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
- ✅ **Drop-in `instanceof` replacement** that works across bundles, HMR and monorepos,
|
|
12
|
+
- ✅ **Drop-in `instanceof` replacement** that works across bundles, HMR and monorepos, and adds an **exact-class-instance check**
|
|
13
13
|
- ✅ **Simple nominal typing** with just one line of code for each class (e.g., `UserId` vs. `PostId`)
|
|
14
14
|
- ✅ **Tiny less than 1.6 KB minified and brotlied** measured using [size-limit](https://www.npmjs.com/package/size-limit)
|
|
15
15
|
- ✅ **Performant as native instanceof** but with guaranteed checks
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
- [Install](#install)
|
|
25
25
|
- [Basic usage](#basic-usage)
|
|
26
26
|
- [Decorator pattern](#decorator-pattern)
|
|
27
|
-
- [
|
|
27
|
+
- [Function pattern](#function-pattern)
|
|
28
28
|
- [Migration](#migration)
|
|
29
29
|
- [Core concepts](#core-concepts)
|
|
30
30
|
- [Terminology](#terminology)
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
- [Minimal mode](#minimal-mode)
|
|
38
38
|
- [Strict mode](#strict-mode)
|
|
39
39
|
- [Hot module reload](#hot-module-reload)
|
|
40
|
+
- [Edge cases](#edge-cases)
|
|
40
41
|
- [Benchmarks](#benchmarks)
|
|
41
42
|
- [Bundle Size](#bundle-size)
|
|
42
43
|
- [Tests](#tests)
|
|
@@ -58,7 +59,9 @@ yarn add @vicin/sigil
|
|
|
58
59
|
pnpm add @vicin/sigil
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
Requires TypeScript 5.0+ for decorators;
|
|
62
|
+
Requires TypeScript 5.0+ for decorators; attach functions work on older versions. Node.js 18+ recommended.
|
|
63
|
+
|
|
64
|
+
> No tsconfig changes are needed as we use **Stage 3 decorators** which are supported by default in TypeScript 5.0+
|
|
62
65
|
|
|
63
66
|
### Basic usage
|
|
64
67
|
|
|
@@ -92,26 +95,28 @@ After opting into the `Sigil` contract, labels are passed to child classes to un
|
|
|
92
95
|
|
|
93
96
|
##### Decorator pattern
|
|
94
97
|
|
|
95
|
-
Apply a label with the `@
|
|
98
|
+
Apply a label with the `@AttachSigil` decorator:
|
|
96
99
|
|
|
97
100
|
```ts
|
|
98
|
-
import { Sigil,
|
|
101
|
+
import { Sigil, AttachSigil } from '@vicin/sigil';
|
|
99
102
|
|
|
100
|
-
@
|
|
103
|
+
@AttachSigil('@myorg/mypkg.User')
|
|
101
104
|
class User extends Sigil {}
|
|
102
105
|
```
|
|
103
106
|
|
|
104
|
-
#####
|
|
107
|
+
##### Function pattern
|
|
105
108
|
|
|
106
|
-
Apply a label using `
|
|
109
|
+
Apply a label using `attachSigil` function:
|
|
107
110
|
|
|
108
111
|
```ts
|
|
109
|
-
import { Sigil,
|
|
112
|
+
import { Sigil, attachSigil } from '@vicin/sigil';
|
|
110
113
|
|
|
111
|
-
class
|
|
112
|
-
|
|
114
|
+
class User extends Sigil {}
|
|
115
|
+
attachSigil(User, '@myorg/mypkg.User');
|
|
113
116
|
```
|
|
114
117
|
|
|
118
|
+
> Note: Function pattern is susceptible to some [Edge case subtle pitfalls](#edge-cases) if not used appropriately, so we advise to use decorator pattern
|
|
119
|
+
|
|
115
120
|
### Migration
|
|
116
121
|
|
|
117
122
|
Migrating old code into `Sigil` can be done with extra couple lines of code only:
|
|
@@ -163,9 +168,9 @@ if (User.isOfType(obj)) { ... } // This still works even if User was bundled twi
|
|
|
163
168
|
if (User.isExactType(obj)) { ... } // Or check for exactly same constructor not its children
|
|
164
169
|
```
|
|
165
170
|
|
|
166
|
-
Also by utilizing unique passed labels it
|
|
171
|
+
Also by utilizing unique passed labels it solves another problem in Domain-Driven Design (DDD):
|
|
167
172
|
|
|
168
|
-
- **Manual Branding Overhead:** Custom identifiers lead to boilerplate and maintenance issues, `Sigil`
|
|
173
|
+
- **Manual Branding Overhead:** Custom identifiers lead to boilerplate and maintenance issues, `Sigil` adds reliable inheritance-aware nominal branding with just one line of code.
|
|
169
174
|
|
|
170
175
|
```ts
|
|
171
176
|
import { sigil } from '@vicin/sigil';
|
|
@@ -181,43 +186,40 @@ type test2 = Sigil extends User ? true : false; // false
|
|
|
181
186
|
### Implementation Mechanics
|
|
182
187
|
|
|
183
188
|
- **Runtime Contract:** Established via extending `Sigil` or using `Sigilify` mixin.
|
|
184
|
-
- **Update metadata:** With each new child, use
|
|
189
|
+
- **Update metadata:** With each new child, use decorator (`AttachSigil`) or function (`attachSigil`) to attach run-time metadata, also use `ExtendSigil` on `[sigil]` field to update nominal type.
|
|
185
190
|
|
|
186
191
|
```ts
|
|
187
|
-
import { Sigil,
|
|
192
|
+
import { Sigil, AttachSigil, sigil, ExtendSigil } from '@vicin/sigil';
|
|
188
193
|
|
|
189
|
-
@
|
|
194
|
+
@AttachSigil('@scope/package.MyClass') // <-- Run-time values update
|
|
190
195
|
class MyClass extends Sigil {
|
|
191
196
|
declare [sigil]: ExtendSigil<'MyClass', Sigil>; // <-- compile-time type update
|
|
192
197
|
}
|
|
193
198
|
```
|
|
194
199
|
|
|
195
|
-
You can avoid decorators and use
|
|
200
|
+
You can avoid decorators and use normal functions if needed:
|
|
196
201
|
|
|
197
202
|
```ts
|
|
198
|
-
import { Sigil,
|
|
203
|
+
import { Sigil, attachSigil, sigil, ExtendSigil } from '@vicin/sigil';
|
|
199
204
|
|
|
200
|
-
class
|
|
205
|
+
class MyClass extends Sigil {
|
|
201
206
|
declare [sigil]: ExtendSigil<'MyClass', Sigil>;
|
|
202
207
|
}
|
|
203
208
|
|
|
204
|
-
|
|
205
|
-
type MyClass = InstanceType<typeof MyClass>;
|
|
209
|
+
attachSigil(MyClass, '@scope/package.MyClass');
|
|
206
210
|
```
|
|
207
211
|
|
|
208
|
-
Note that you can't use `InstanceType` on `private` or `protected` classes, however you can use `GetPrototype<T>` in such cases.
|
|
209
|
-
|
|
210
212
|
### Example
|
|
211
213
|
|
|
212
214
|
```ts
|
|
213
|
-
import { Sigil,
|
|
215
|
+
import { Sigil, AttachSigil } from '@vicin/sigil';
|
|
214
216
|
|
|
215
|
-
@
|
|
217
|
+
@AttachSigil('@myorg/User')
|
|
216
218
|
class User extends Sigil {
|
|
217
219
|
declare [sigil]: ExtendSigil<'User', Sigil>;
|
|
218
220
|
}
|
|
219
221
|
|
|
220
|
-
@
|
|
222
|
+
@AttachSigil('@myorg/Admin')
|
|
221
223
|
class Admin extends User {
|
|
222
224
|
declare [sigil]: ExtendSigil<'Admin', User>;
|
|
223
225
|
}
|
|
@@ -248,51 +250,40 @@ type test1 = Admin extends User ? true : false; // true
|
|
|
248
250
|
type test2 = User extends Admin ? true : false; // false
|
|
249
251
|
|
|
250
252
|
// Passed label must be unique (enforced by Sigil) so can be used as stable Id for class
|
|
251
|
-
// Also 'SigilLabelLineage'
|
|
253
|
+
// Also 'SigilLabelLineage' is useful for logging & debugging
|
|
252
254
|
console.log(Admin.SigilLabel); // '@myorg/Admin'
|
|
253
255
|
console.log(Admin.SigilEffectiveLabel); // '@myorg/Admin'
|
|
254
256
|
console.log(Admin.SigilLabelLineage); // ['Sigil', '@myorg/User', '@myorg/Admin']
|
|
255
|
-
console.log(Admin.SigilLabelSet); // Set(['Sigil', '@myorg/User', '@myorg/Admin'])
|
|
256
257
|
console.log(admin.getSigilLabel()); // '@myorg/Admin'
|
|
257
258
|
console.log(admin.getSigilEffectiveLabel()); // '@myorg/Admin'
|
|
258
259
|
console.log(admin.getSigilLabelLineage()); // ['Sigil', '@myorg/User', '@myorg/Admin']
|
|
259
|
-
console.log(admin.getSigilLabelSet()); // Set(['Sigil', '@myorg/User', '@myorg/Admin'])
|
|
260
260
|
```
|
|
261
261
|
|
|
262
262
|
### Errors & throws
|
|
263
263
|
|
|
264
264
|
Run-time errors that can be thrown by `Sigil`:
|
|
265
265
|
|
|
266
|
-
#### Double
|
|
266
|
+
#### Double Sigilify
|
|
267
267
|
|
|
268
268
|
```ts
|
|
269
269
|
class A {}
|
|
270
|
-
|
|
271
|
-
const C = Sigilify(B, 'B'); // Throws: [Sigil Error] Class 'Sigilified' with label 'A' is already sigilified
|
|
270
|
+
Sigilify(Sigilify(A, 'A'), 'B'); // Throws: [Sigil Error] Class 'Sigilified' with label 'A' is already sigilified
|
|
272
271
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
#### `@WithSigil() / withSigil()` on non-Sigil class
|
|
279
|
-
|
|
280
|
-
```ts
|
|
281
|
-
@WithSigil('A')
|
|
282
|
-
class A {} // Throws: [Sigil Error] 'WithSigil' decorator accept only Sigil classes but used on class 'A'
|
|
272
|
+
@AttachSigil('B')
|
|
273
|
+
@AttachSigil('A')
|
|
274
|
+
class A extends Sigil {} // Throws: [Sigil Error] Class 'A' with label 'A' is already sigilified
|
|
283
275
|
|
|
284
|
-
|
|
276
|
+
class A extends Sigil {}
|
|
277
|
+
attachSigil(attachSigil(A, 'A'), 'B'); // Throws: [Sigil Error] Class 'A' with label 'A' is already sigilified
|
|
285
278
|
```
|
|
286
279
|
|
|
287
|
-
####
|
|
280
|
+
#### `@AttachSigil() / attachSigil()` on non-Sigil class
|
|
288
281
|
|
|
289
282
|
```ts
|
|
290
|
-
@
|
|
291
|
-
|
|
292
|
-
class A extends Sigil {} // Throws: [Sigil Error] Class 'A' with label 'A' is already sigilified
|
|
283
|
+
@AttachSigil('A') // Throws: [Sigil Error] 'AttachSigil' decorator accept only Sigil classes but used on class 'A'
|
|
284
|
+
class A {}
|
|
293
285
|
|
|
294
|
-
class
|
|
295
|
-
withSigil(withSigil(_A, 'A'), 'B'); // Throws: [Sigil Error] Class 'A' with label 'A' is already sigilified
|
|
286
|
+
attachSigil(class A {}); // Throws: [Sigil Error] 'AttachSigil' function accept only Sigil classes but used on class 'A'
|
|
296
287
|
```
|
|
297
288
|
|
|
298
289
|
#### No label is passed with `autofillLabels: false`
|
|
@@ -307,10 +298,10 @@ new A(); // Throws: [Sigil Error] Class 'A' is not sigilified, Make sure to sigi
|
|
|
307
298
|
#### Same label is passed twice to `Sigil`
|
|
308
299
|
|
|
309
300
|
```ts
|
|
310
|
-
@
|
|
301
|
+
@AttachSigil('Label')
|
|
311
302
|
class A extends Sigil {}
|
|
312
303
|
|
|
313
|
-
@
|
|
304
|
+
@AttachSigil('Label')
|
|
314
305
|
class B extends Sigil {} // Throws: [Sigil Error] Passed label 'Label' to class 'B' is re-used, passed labels must be unique
|
|
315
306
|
```
|
|
316
307
|
|
|
@@ -319,15 +310,15 @@ class B extends Sigil {} // Throws: [Sigil Error] Passed label 'Label' to class
|
|
|
319
310
|
```ts
|
|
320
311
|
updateSigilOptions({ labelValidation: RECOMMENDED_LABEL_REGEX });
|
|
321
312
|
|
|
322
|
-
@
|
|
313
|
+
@AttachSigil('InvalidLabel')
|
|
323
314
|
class A extends Sigil {} // Throws: [Sigil Error] Invalid Sigil label 'InvalidLabel'. Make sure that supplied label matches validation regex or function
|
|
324
315
|
```
|
|
325
316
|
|
|
326
317
|
#### Using '@Sigil-auto' prefix
|
|
327
318
|
|
|
328
319
|
```ts
|
|
329
|
-
@
|
|
330
|
-
class X extends Sigil {} // Throws: '@Sigil-auto' is a
|
|
320
|
+
@AttachSigil('@Sigil-auto:label')
|
|
321
|
+
class X extends Sigil {} // Throws: '@Sigil-auto' is a prefix reserved by the library
|
|
331
322
|
```
|
|
332
323
|
|
|
333
324
|
#### Invalid options passed to `updateOptions`
|
|
@@ -353,10 +344,10 @@ updateSigilOptions({ skipLabelUniquenessCheck: 'str' as any }); // Throws: 'upda
|
|
|
353
344
|
- `SigilError`
|
|
354
345
|
|
|
355
346
|
- **Decorator:**
|
|
356
|
-
- `
|
|
347
|
+
- `AttachSigil(label, opts?)`
|
|
357
348
|
|
|
358
|
-
- **
|
|
359
|
-
- `
|
|
349
|
+
- **Attach function:**
|
|
350
|
+
- `attachSigil(Class, label, opts?)`
|
|
360
351
|
|
|
361
352
|
- **Helpers:**
|
|
362
353
|
- `isSigilCtor(ctor)`
|
|
@@ -382,8 +373,8 @@ updateSigilOptions({ skipLabelUniquenessCheck: 'str' as any }); // Throws: 'upda
|
|
|
382
373
|
- `SigilError`: an `Error` class decorated with a `Sigil` so it can be identified at runtime.
|
|
383
374
|
- `Sigilify(Base, label, opts?)`: mixin function that returns a new constructor with `Sigil` types and instance helpers.
|
|
384
375
|
- `SigilifyAbstract(Base, label, opts?)`: Same as `Sigilify` but for abstract classes.
|
|
385
|
-
- `
|
|
386
|
-
- `
|
|
376
|
+
- `AttachSigil(label, opts?)`: class decorator that attaches `Sigil` metadata at declaration time.
|
|
377
|
+
- `attachSigil(Class, label, opts?)`: function that validates and decorates an existing class constructor.
|
|
387
378
|
- `isSigilCtor(value)`: `true` if `value` is a `Sigil` constructor.
|
|
388
379
|
- `isSigilInstance(value)`: `true` if `value` is an instance of a `Sigil` constructor.
|
|
389
380
|
- `getSigilLabels()`: Get `Sigil` labels registered.
|
|
@@ -397,7 +388,6 @@ When a constructor is sigilified it will expose the following **static** getters
|
|
|
397
388
|
- `SigilLabel` — the identity label string.
|
|
398
389
|
- `SigilEffectiveLabel` — the human label string.
|
|
399
390
|
- `SigilLabelLineage` — readonly array of labels representing parent → child for debugging.
|
|
400
|
-
- `SigilLabelSet` — readonly `Set<string>` of sigil labels for debugging.
|
|
401
391
|
- `isOfType(other)` — check if other is an instance of this constructor or its children.
|
|
402
392
|
- `isExactType(other) `— check if other is an instance exactly this constructor.
|
|
403
393
|
|
|
@@ -406,7 +396,6 @@ Instances of sigilified classes expose instance helpers:
|
|
|
406
396
|
- `getSigilLabel()` — returns the identity label.
|
|
407
397
|
- `getSigilEffectiveLabel()` — returns the human label.
|
|
408
398
|
- `getSigilLabelLineage()` — returns lineage array.
|
|
409
|
-
- `getSigilLabelSet()` — returns readonly Set.
|
|
410
399
|
- `isOfType(other)` — check if other is an instance of the same class or its children as this.
|
|
411
400
|
- `isExactType(other) `— check if other is an instance exactly the same constructor.
|
|
412
401
|
|
|
@@ -426,18 +415,18 @@ updateSigilOptions({
|
|
|
426
415
|
});
|
|
427
416
|
```
|
|
428
417
|
|
|
429
|
-
Values defined in previous example are defaults, per-class overrides available in mixin
|
|
418
|
+
Values defined in previous example are defaults, per-class overrides available in mixin and attach function / decorator.
|
|
430
419
|
|
|
431
420
|
---
|
|
432
421
|
|
|
433
422
|
## Minimal mode
|
|
434
423
|
|
|
435
|
-
By default `Sigil` works with minimal mode, You can ignore all decorators and
|
|
424
|
+
By default `Sigil` works with minimal mode, You can ignore all decorators and functions and just make base class extend `Sigil`:
|
|
436
425
|
|
|
437
426
|
```ts
|
|
438
427
|
import { Sigil, updateSigilOptions } from '@vicin/sigil';
|
|
439
428
|
|
|
440
|
-
// No decorators or
|
|
429
|
+
// No decorators or functions needed to use 'isOfType' ('instanceof' replacement)
|
|
441
430
|
class A extends Sigil {}
|
|
442
431
|
class B extends A {}
|
|
443
432
|
class C extends B {}
|
|
@@ -468,11 +457,11 @@ import { updateSigilOptions } from '@vicin/sigil';
|
|
|
468
457
|
updateSigilOptions({ skipLabelUniquenessCheck: true });
|
|
469
458
|
```
|
|
470
459
|
|
|
471
|
-
But this can cause
|
|
460
|
+
But this can cause unexpected behavior if same label is used for two different classes as checks are disabled globally.
|
|
472
461
|
If you need more strict mode you can pass this options to the re-loaded class only:
|
|
473
462
|
|
|
474
463
|
```ts
|
|
475
|
-
@
|
|
464
|
+
@AttachSigil('HmrClassLabel', { skipLabelUniquenessCheck: true })
|
|
476
465
|
class HmrClass extends Sigil {}
|
|
477
466
|
```
|
|
478
467
|
|
|
@@ -480,6 +469,57 @@ With this approach `skipLabelUniquenessCheck` affects only `HmrClass`, and if `H
|
|
|
480
469
|
|
|
481
470
|
---
|
|
482
471
|
|
|
472
|
+
## Edge cases
|
|
473
|
+
|
|
474
|
+
### Accessing Sigil `metadata` before running 'attachSigil' function
|
|
475
|
+
|
|
476
|
+
If you didn't make sure that `attachSigil` runs right after class declaration and used one of `Sigil` methods this will occur:
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
class A extends Sigil {}
|
|
480
|
+
|
|
481
|
+
console.log(A.SigilLabel); // returns auto-generated label (e.g. @Sigil-auto:A:6:a3f15bhl) or throws in strict mode
|
|
482
|
+
|
|
483
|
+
attachSigil(A, 'A');
|
|
484
|
+
|
|
485
|
+
console.log(A.SigilLabel); // A
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
To avoid this bug entirely you can use the return of `attachSigil` in your code so you are enforced to respect order:
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
class _A extends Sigil {}
|
|
492
|
+
|
|
493
|
+
const A = attachSigil(_A, 'A');
|
|
494
|
+
type A = InstanceType<typeof A>;
|
|
495
|
+
|
|
496
|
+
console.log(A.SigilLabel); // A
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Note that you can't use `InstanceType` on `private` or `protected` classes, however you can use `GetPrototype<T>` in such cases.
|
|
500
|
+
|
|
501
|
+
#### Static blocks & IIFE static initializer
|
|
502
|
+
|
|
503
|
+
Decorators ensure that metadata is appended before static blocks or IIFE static initializers, however `attachSigil` function runs after them so accessing label inside them will return auto-generated label or throw:
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
class A extends Sigil {
|
|
507
|
+
static IIFE = (() => {
|
|
508
|
+
const label = A.SigilLabel; // returns auto-generated label (e.g. @Sigil-auto:A:6:a3f15bhl) or throws in strict mode
|
|
509
|
+
})();
|
|
510
|
+
|
|
511
|
+
static {
|
|
512
|
+
const label = this.SigilLabel; // returns auto-generated label (e.g. @Sigil-auto:A:6:a3f15bhl) or throws in strict mode
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
attachSigil(A, 'A');
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
This behavior can't be avoided, so make sure not to call any `Sigil` method inside them or move to decorators (`@AttachSigil`)
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
483
523
|
## Benchmarks
|
|
484
524
|
|
|
485
525
|
Sigil is built for **real-world performance**. Below are the latest micro-benchmark results (run on **Node.js v20.12.0**).
|
|
@@ -529,7 +569,7 @@ npm run bench
|
|
|
529
569
|
|
|
530
570
|
## Bundle Size
|
|
531
571
|
|
|
532
|
-
**Less than 1.6 KB (1.
|
|
572
|
+
**Less than 1.6 KB (1.52 KB)** (minified + Brotli, including all dependencies)
|
|
533
573
|
|
|
534
574
|
This makes Sigil one of the smallest full-featured solutions for nominal typing + reliable runtime identity.
|
|
535
575
|
|
|
@@ -546,7 +586,7 @@ npm run size
|
|
|
546
586
|
|
|
547
587
|
## Tests
|
|
548
588
|
|
|
549
|
-
Reliability is a core pillar of `Sigil`. The library is backed by a comprehensive suite of unit tests that cover everything from basic mixins to
|
|
589
|
+
Reliability is a core pillar of `Sigil`. The library is backed by a comprehensive suite of unit tests ( 71 total tests ) that cover everything from basic mixins to edge cases.
|
|
550
590
|
|
|
551
591
|
**Coverage Status**
|
|
552
592
|
|
|
@@ -561,11 +601,12 @@ We maintain **100%** test coverage across the entire codebase to ensure that run
|
|
|
561
601
|
|
|
562
602
|
**Key Test Areas**
|
|
563
603
|
|
|
564
|
-
- **Mixins,
|
|
604
|
+
- **Mixins, Attach function & decorator:** Validating `Sigilify`, `AttachSigil` and `attachSigil` behaviors.
|
|
565
605
|
- **Sigil methods:** Ensuring `Sigil` class methods (e.g. `SigilLabel`, `getSigilLabel`) work as expected.
|
|
566
|
-
- **Lazy Evaluation:** Ensuring metadata is attached before being accessed via `Sigil` methods.
|
|
606
|
+
- **Lazy Evaluation:** Ensuring metadata is attached before being accessed via `Sigil` methods even when no attach function or decorator is used.
|
|
567
607
|
- **Lineage:** Verifying that `isOfType` and `isExactType` work across complex inheritance chains.
|
|
568
608
|
- **Error Handling:** Strict validation for all errors and throws.
|
|
609
|
+
- **Edge cases**: Known edge cases.
|
|
569
610
|
|
|
570
611
|
**Running Tests**
|
|
571
612
|
|