@vicin/sigil 1.3.0 → 2.0.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 CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.0.0] - 2026-02-20
6
+
7
+ ### Breaking changes
8
+
9
+ All `SigilRegistry`options, methods and classes are removed.
10
+
5
11
  ## [1.3.0] - 2026-02-18
6
12
 
7
13
  ### Added
package/README.md CHANGED
@@ -2,24 +2,27 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@vicin/sigil.svg)](https://www.npmjs.com/package/@vicin/sigil) [![npm downloads](https://img.shields.io/npm/dm/@vicin/sigil.svg)](https://www.npmjs.com/package/@vicin/sigil) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue) [![Build](https://github.com/ZiadTaha62/sigil/actions/workflows/ci.yml/badge.svg)](https://github.com/ZiadTaha62/sigil/actions/workflows/ci.yml)
4
4
 
5
- > - 🎉 First stable release — v1.2! Happy coding! 😄💻
5
+ > - 🎉 v2.0.0 is out! Happy coding! 😄💻
6
6
  > - 📄 **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
7
7
 
8
- `Sigil` is a lightweight TypeScript library for creating nominal identity classes with compile-time branding and reliable runtime type checks. It organizes class identities across your codebase and gives you the power of **nominal typing**, **safe cross-bundle class checks**, and a **central registry** where each class constructor is stored under a unique label.
8
+ `Sigil` is a lightweight TypeScript library for creating nominal identity classes with compile-time branding and reliable runtime type checks. It organizes class identities across your codebase and gives you the power of **nominal typing** and **safe cross-bundle class checks** where each class constructor is stored under a unique label.
9
9
 
10
10
  > **Key ideas:**
11
11
  >
12
12
  > - **Nominal Typing at Compile Time:** Distinguishes structurally similar types (e.g., UserId vs. PostId).
13
13
  > - **Reliable Runtime Checks:** Uses symbols instead of instanceof for cross-bundle reliability.
14
14
  > - **Inheritance Awareness:** Tracks lineages for subtype/supertype checks.
15
- > - **Central Registry:** Stores class references by unique labels for easy lookup.
16
15
 
17
16
  ## Important Notes Before Using
18
17
 
19
- - **Security:** The global registry stores constructors by default, which could expose them. Disable with `{ storeConstructor: false }` for sensitive classes.
20
- - **Performance:** Minimal overhead, but `.isOfType()` is slower than native `instanceof`. Avoid in ultra-hot paths.
18
+ - **Explicit class identity:** `Sigil` uses passed class label to identify classes, which means that dev is responsible for uniqueness of classes by passing unique labels.
19
+ - **Performance:** Minimal overhead, but `.isOfType()` is slightly slower than native `instanceof`. Avoid in ultra-hot paths.
21
20
  - **Private Constructors:** HOF pattern allows extending private constructors in types (TypeScript limitation).
22
- - **Simple instanceof Fix:** If you just need runtime checks without extras, see the [minimal mode](#minimal-mode) in Registry section.
21
+ - **Simple instanceof Fix:** If you just need runtime checks without extras, see the [minimal mode](#minimal-mode).
22
+
23
+ ## Why Registry is dropped
24
+
25
+ Although registry added label checks and central class management but it also introduced complexity, especially when mutiple packages tried to use it simultaneously, So in v2 we decided to omit it entirely and minimize API surface.
23
26
 
24
27
  ---
25
28
 
@@ -44,11 +47,8 @@
44
47
  - [Decorator pattern](#2-decorator-pattern)
45
48
  - [API reference](#api-reference)
46
49
  - [Options & configuration](#options--configuration)
47
- - [Registry](#registry)
48
- - [Security guidance](#security-guidance)
49
50
  - [Minimal mode](#minimal-mode)
50
51
  - [Troubleshooting & FAQ](#troubleshooting--faq)
51
- - [Deprecated API](#deprecated-api)
52
52
  - [Phantom](#phantom)
53
53
  - [Contributing](#contributing)
54
54
  - [License](#license)
@@ -190,9 +190,7 @@ This section states clearly what `Sigil` provides and what it does **not** provi
190
190
 
191
191
  **2. Reliable runtime identity (when used as intended).**
192
192
 
193
- **3. Optional central registry for discovery & serialization helpers.**
194
-
195
- **4. Nominal typing that is inheritance-aware**
193
+ **3. Nominal typing that is inheritance-aware**
196
194
 
197
195
  ### What Sigil does not guarantee
198
196
 
@@ -211,7 +209,6 @@ This section states clearly what `Sigil` provides and what it does **not** provi
211
209
  - **Type lineage**: Array of symbols for ancestry.
212
210
  - **Type set**: Set of symbols for fast checks.
213
211
  - **Brand**: TypeScript marker (`__SIGIL_BRAND__`) for nominal types.
214
- - **Registry**: A global Map of registered `Sigil` classes keyed by their labels.
215
212
 
216
213
  ---
217
214
 
@@ -222,7 +219,7 @@ Sigil addresses issues in large monorepos and Domain-Driven Design (DDD):
222
219
  - **Unreliable `instanceof`:** Bundling and HMR cause class redefinitions, breaking checks.
223
220
  - **Manual Branding Overhead:** Custom identifiers lead to boilerplate and maintenance issues.
224
221
 
225
- `Sigil` abstracts these into a **centralized system**, making identity management **explicit** and **error-resistant**.
222
+ `Sigil` abstracts these into a **centralized system**, making identity management **explicit** and **error-resistant** if defined the right way.
226
223
 
227
224
  ### Implementation Mechanics
228
225
 
@@ -386,11 +383,10 @@ class X extends Sigil {
386
383
  - `isDecorated(ctor)`
387
384
  - `isInheritanceChecked(ctor)`
388
385
 
389
- - **Options/Registry:**
390
- - `updateOptions(opts, mergeRegistries?)`
391
- - `SigilRegistry`
392
- - `getActiveRegistry`
386
+ - **Options:**
387
+ - `updateOptions(opts)`
393
388
  - `DEFAULT_LABEL_REGEX`
389
+
394
390
  - **Types:**
395
391
  - `ISigil<Label, ParentSigil?>`
396
392
  - `ISigilStatic<Label, ParentSigil?>`
@@ -411,9 +407,7 @@ class X extends Sigil {
411
407
  - `withSigilTyped(Class, label?, opts?)`: like `withSigil` but narrows the TypeScript type to include brands.
412
408
  - `isSigilCtor(value)`: `true` if `value` is a `Sigil` constructor.
413
409
  - `isSigilInstance(value)`: `true` if `value` is an instance of a `Sigil` constructor.
414
- - `SigilRegistry`: `Sigil` Registry class used to centralize classes across app.
415
- - `getActiveRegistry`: Getter of active registry being used by `Sigil`.
416
- - `updateOptions(opts, mergeRegistries?)`: change global runtime options before `Sigil` decoration (e.g., `autofillLabels`, `devMarker`, etc.).
410
+ - `updateOptions(opts)`: change global runtime options before `Sigil` decoration (e.g., `autofillLabels`, `devMarker`, etc.).
417
411
  - `DEFAULT_LABEL_REGEX`: regex that ensures structure of `@scope/package.ClassName` to all labels, it's advised to use it as your `SigilOptions.labelValidation`
418
412
 
419
413
  ### Instance & static helpers provided by Sigilified constructors
@@ -421,11 +415,10 @@ class X extends Sigil {
421
415
  When a constructor is decorated/sigilified it will expose the following **static** getters/methods:
422
416
 
423
417
  - `SigilLabel` — the human label string.
424
- - `SigilType` — the runtime symbol for the label.
425
- - `SigilTypeLineage` — readonly array of symbols representing parent → child.
426
- - `SigilTypeSet` — readonly `Set<symbol>` for O(1) checks.
418
+ - `SigilLabelLineage` — readonly array of labels representing parent → child.
419
+ - `SigilLabelSet` — readonly `Set<string>` for O(1) checks.
427
420
  - `isSigilified(obj)` — runtime predicate that delegates to `isSigilInstance`.
428
- - `isOfType(other)` — O(1) membership test using `other`'s `__TYPE_SET__`.
421
+ - `isOfType(other)` — O(1) membership test using `other`'s `__LABEL_SET__`.
429
422
  - `isOfTypeStrict(other)` — strict lineage comparison element-by-element.
430
423
 
431
424
  Instances of sigilified classes expose instance helpers:
@@ -434,7 +427,7 @@ Instances of sigilified classes expose instance helpers:
434
427
  - `getSigilType()` — runtime symbol.
435
428
  - `getSigilTypeLineage()` — returns lineage array.
436
429
  - `getSigilTypeSet()` — returns readonly Set.
437
- - `isOfType(other)` — O(1) membership test using `other`'s `__TYPE_SET__`.
430
+ - `isOfType(other)` — O(1) membership test using `other`'s `__LABEL_SET__`.
438
431
  - `isOfTypeStrict(other)` — strict lineage comparison element-by-element.
439
432
 
440
433
  ---
@@ -444,16 +437,13 @@ Instances of sigilified classes expose instance helpers:
444
437
  Customize behavior globally at startup:
445
438
 
446
439
  ```ts
447
- import { updateOptions, SigilRegistry } from '@vicin/sigil';
440
+ import { updateOptions } from '@vicin/sigil';
448
441
 
449
442
  updateOptions({
450
443
  autofillLabels: false, // Automatically label unlabeled subclasses
451
444
  skipLabelInheritanceCheck: false, // Bypass dev inheritance checks -- ALMOST NEVER WANT TO SET THIS TO TRUE, Use 'autofillLabels: true' instead.
452
445
  labelValidation: null, // Function or regex, Enforce label format
453
446
  devMarker: process.env.NODE_ENV !== 'production', // Toggle dev safeguards
454
- registry: new SigilRegistry(), // Custom registry instance
455
- useGlobalRegistry: true, // Store in 'globalThis' for cross-bundle access
456
- storeConstructor: true, // Include constructors in registry
457
447
  });
458
448
  ```
459
449
 
@@ -461,81 +451,15 @@ Values defined in previous example are defaults, per-class overrides available i
461
451
 
462
452
  ---
463
453
 
464
- ## Registry
465
-
466
- The registry ensures **unique labels** and supports central class management for ops as serialization.
467
-
468
- - **Access:** `const registry = getActiveRegistry();` – Returns current `SigilRegistry` or `null`.
469
- - **Operations:** `has(label)`, `get(label)`, `listLabels()`, `register(label, ctor, opts?)`, `unregister(label)`, `clear()`, `size`.
470
- - **Replacement:** `updateOptions({ registry: new SigilRegistry(myMap) }, merge?);` – Optionally merge existing entries.
471
- - **Disable:** Set `registry: null` to skip all registry functions.
472
- - **Global Storage:** Defaults to `globalThis[Symbol.for('__SIGIL_REGISTRY__')];` disable with `useGlobalRegistry: false` if single-bundle guaranteed.
473
- - **Constructor Privacy:** Set `storeConstructor: false` globally or per-class to replace constructors with null in the map.
474
-
475
- ### Class typing in registry
476
-
477
- Unfortunately concrete types of classes is not supported and all classes are stored as `ISigil` type. if you want concrete typing, you can wrap registry:
478
-
479
- ```ts
480
- import { getActiveRegistry } from '@vicin/sigil';
481
- import type { MySigilClass1 } from './file1';
482
- import type { MySigilClass2 } from './file2';
483
-
484
- interface MyClasses {
485
- MySigilClass1: typeof MySigilClass1;
486
- MySigilClass2: typeof MySigilClass2;
487
- }
488
-
489
- export class MySigilRegistry {
490
- listLabels(): (keyof MyClasses)[] {
491
- return getActiveRegistry()?.listLabels();
492
- }
493
- has(label: string): boolean {
494
- return getActiveRegistry()?.has(label);
495
- }
496
- get<L extends keyof MyClasses>(label: L): MyClasses[L] {
497
- return getActiveRegistry()?.get(label) as any;
498
- }
499
- unregister(label: string): boolean {
500
- return getActiveRegistry()?.unregister(label);
501
- }
502
- clear(): void {
503
- getActiveRegistry()?.clear();
504
- }
505
- replaceRegistry(newRegistry: Map<string, ISigil> | null): void {
506
- getActiveRegistry()?.replaceRegistry(newRegistry);
507
- }
508
- get size(): number {
509
- return getActiveRegistry()?.size;
510
- }
511
- }
512
- ```
513
-
514
- Now you have fully typed central class registry!
515
-
516
- ---
517
-
518
- ## Security guidance
519
-
520
- - **Recommended for Untrusted Environments:** `updateOptions({ storeConstructor: false });` – Prevents constructors from being stored in the registry map (labels remain, but constructors are `null`).
521
-
522
- - **Trusted Environments:** Enable full registry for centralization (default behavior).
523
-
524
- - **Per-Class Control:** Use `{ storeConstructor: false }` for sensitive classes in decorator or HOF function.
525
-
526
- Always remember, Registry is metadata-only; avoid for sensitive data. Global access possible if enabled.
527
-
528
- ---
529
-
530
454
  ## Minimal mode
531
455
 
532
- `updateOptions({ autofillLabels: true, storeConstructor: false });` – Enables background operation without explicit labels or storage:
456
+ `updateOptions({ autofillLabels: true });` – Enables background operation without explicit labels:
533
457
 
534
458
  ```ts
535
459
  import { Sigil, updateOptions } from '@vicin/sigil';
536
460
 
537
461
  // run at the start of the app
538
- updateOptions({ autofillLabels: true, storeConstructor: false });
462
+ updateOptions({ autofillLabels: true });
539
463
 
540
464
  // No decorators or HOF needed to use 'isOfType' ('instanceof' replacement)
541
465
  class A extends Sigil {}
@@ -550,40 +474,6 @@ class C extends B {}
550
474
  - **Dev Extension Errors:** Add labels or enable autofillLabels.
551
475
  - **Anonymous Class Errors:** Export untyped bases.
552
476
  - **Selective Labeling:** Use `autofillLabels: true` or empty `@WithSigil()` for auto-generation.
553
- - **Registry Inspection:** `getActiveRegistry()?.listLabels()`.
554
-
555
- ---
556
-
557
- ## Deprecated API
558
-
559
- ### REGISTRY
560
-
561
- `Sigil` has moved from static reference registry to dynamic access and updates, now devs can create `SigilRegistry` class and pass it to `SigilOptions` to be used by the library internals. however change is done gracefully and `REGISTRY` is still supported with no change in behavior but it's **marked with `deprecated` and will be removed in v2.0.0**.
562
-
563
- ```ts
564
- import { REGISTRY, getActiveRegistry } from '@vicin/sigil';
565
-
566
- // from:
567
- const present = REGISTRY.has('label');
568
- // to:
569
- const registry = getActiveRegistry();
570
- const present = registry ? registry.has('label') : false;
571
- ```
572
-
573
- ```ts
574
- import { REGISTRY, updateOptions, SigilRegistry } from '@vicin/sigil';
575
-
576
- // from:
577
- const newRegistry = new Map();
578
- REGISTRY.replaceRegistry(newRegistry);
579
- // to
580
- const newRegistry = new SigilRegistry(); // can pass external map to constructor, this map will hold all classes
581
- updateOptions({ registry: newRegistry });
582
- ```
583
-
584
- ### typed
585
-
586
- Obsolete; mixins now handle typing natively. **marked with `deprecated` and will be removed in v2.0.0**
587
477
 
588
478
  ---
589
479