@vicin/sigil 1.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.
Files changed (51) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +620 -0
  3. package/dist/core/classes.d.ts +48 -0
  4. package/dist/core/classes.d.ts.map +1 -0
  5. package/dist/core/classes.js +18 -0
  6. package/dist/core/classes.js.map +1 -0
  7. package/dist/core/decorator.d.ts +28 -0
  8. package/dist/core/decorator.d.ts.map +1 -0
  9. package/dist/core/decorator.js +48 -0
  10. package/dist/core/decorator.js.map +1 -0
  11. package/dist/core/enhancers.d.ts +58 -0
  12. package/dist/core/enhancers.d.ts.map +1 -0
  13. package/dist/core/enhancers.js +101 -0
  14. package/dist/core/enhancers.js.map +1 -0
  15. package/dist/core/helpers.d.ts +192 -0
  16. package/dist/core/helpers.d.ts.map +1 -0
  17. package/dist/core/helpers.js +349 -0
  18. package/dist/core/helpers.js.map +1 -0
  19. package/dist/core/index.d.ts +9 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +8 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/core/mixin.d.ts +115 -0
  24. package/dist/core/mixin.d.ts.map +1 -0
  25. package/dist/core/mixin.js +209 -0
  26. package/dist/core/mixin.js.map +1 -0
  27. package/dist/core/options.d.ts +74 -0
  28. package/dist/core/options.d.ts.map +1 -0
  29. package/dist/core/options.js +39 -0
  30. package/dist/core/options.js.map +1 -0
  31. package/dist/core/registry.d.ts +104 -0
  32. package/dist/core/registry.d.ts.map +1 -0
  33. package/dist/core/registry.js +174 -0
  34. package/dist/core/registry.js.map +1 -0
  35. package/dist/core/symbols.d.ts +96 -0
  36. package/dist/core/symbols.d.ts.map +1 -0
  37. package/dist/core/symbols.js +96 -0
  38. package/dist/core/symbols.js.map +1 -0
  39. package/dist/core/types.d.ts +169 -0
  40. package/dist/core/types.d.ts.map +1 -0
  41. package/dist/core/types.js +2 -0
  42. package/dist/core/types.js.map +1 -0
  43. package/dist/index.d.ts +3 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +3 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/utils/index.d.ts +2 -0
  48. package/dist/utils/index.d.ts.map +1 -0
  49. package/dist/utils/index.js +2 -0
  50. package/dist/utils/index.js.map +1 -0
  51. package/package.json +57 -0
@@ -0,0 +1,209 @@
1
+ import { checkInheritance, decorateCtor, generateRandomLabel, getConstructor, isSigilCtor, isSigilInstance, markSigil, markSigilBase, verifyLabel, } from './helpers';
2
+ import { OPTIONS } from './options';
3
+ import { __LABEL__, __TYPE__, __TYPE_LINEAGE__, __TYPE_SET__ } from './symbols';
4
+ /**
5
+ * Mixin factory that augments an existing class with Sigil runtime metadata and
6
+ * helpers. The returned class:
7
+ * - registers a stable symbol for the provided `label` (via `WithSigil`)
8
+ * - exposes static helpers such as `SigilLabel`, `SigilType`, `isOfType`, and `isOfTypeStrict`
9
+ * - exposes instance helpers such as `getSigilLabel`, `getSigilType`, etc.
10
+ *
11
+ * Notes:
12
+ * - Uses `Symbol.for(label)` internally so symbols are stable across bundles/realms
13
+ * that share the global symbol registry.
14
+ * - Throws if `Base` is already a sigil constructor.
15
+ *
16
+ * @param Base - The base constructor to extend.
17
+ * @param label - Optional identity label to attach to the resulting class (e.g. '@scope/pkg.ClassName').
18
+ * If not passed a random label is generated instead.
19
+ * @param opts - Options object to override any global options if needed.
20
+ * @returns A new abstract constructor that extends `Base` and includes Sigil statics/instance methods.
21
+ * @throws Error if `Base` is already sigilized.
22
+ */
23
+ export function Sigilify(Base, label, opts) {
24
+ // if siglified throw
25
+ if (isSigilCtor(Base))
26
+ throw new Error(`[Sigil Error] 'Sigilify(${label})' already siglified.`);
27
+ // generate random label if not passed and verify it
28
+ let l;
29
+ if (label) {
30
+ verifyLabel(label, opts);
31
+ l = label;
32
+ }
33
+ else
34
+ l = generateRandomLabel();
35
+ // extend actual class
36
+ class Sigilified extends Base {
37
+ /**
38
+ * Class-level human-readable label constant for this sigil constructor.
39
+ */
40
+ static get SigilLabel() {
41
+ return this[__LABEL__];
42
+ }
43
+ /**
44
+ * Class-level unique runtime symbol used as the type identifier.
45
+ *
46
+ * This symbol is created with `Symbol.for(label)` during decoration so it is
47
+ * stable across realms that share the same global symbol registry.
48
+ */
49
+ static get SigilType() {
50
+ return this[__TYPE__];
51
+ }
52
+ /**
53
+ * Copy of the linearized sigil type symbol chain for the current constructor.
54
+ *
55
+ * Useful for debugging and performing strict lineage comparisons.
56
+ *
57
+ * @returns An array of symbols representing parent → child type symbols.
58
+ */
59
+ static get SigilTypeLineage() {
60
+ return [...(this[__TYPE_LINEAGE__] ?? [])];
61
+ }
62
+ /**
63
+ * Copy of the sigil type symbol set for the current constructor.
64
+ *
65
+ * Useful for quick membership checks (O(1) lookups) and debugging.
66
+ *
67
+ * @returns A Readonly Set of symbols that represent the type lineage.
68
+ */
69
+ static get SigilTypeSet() {
70
+ const set = new Set();
71
+ for (const s of this[__TYPE_SET__])
72
+ set.add(s);
73
+ return set;
74
+ }
75
+ constructor(...args) {
76
+ super(...args);
77
+ // Correct prototype chain when necessary (defensive for transpiled code / edge cases)
78
+ if (Object.getPrototypeOf(this) !== new.target.prototype)
79
+ Object.setPrototypeOf(this, new.target.prototype);
80
+ // Resolve constructor; defensive null-check helps catch weird runtime cases.
81
+ const ctor = getConstructor(this);
82
+ if (!ctor) {
83
+ if (opts?.devMarker ?? OPTIONS.devMarker)
84
+ throw new Error(`[Sigil Error] 'Sigilify(${label})' instance without constructor`);
85
+ return;
86
+ }
87
+ // Perform dev-only inheritance validation to ensure labels are unique across the chain.
88
+ checkInheritance(ctor);
89
+ }
90
+ /**
91
+ * Runtime predicate indicating whether `obj` is an instance produced by a sigil class.
92
+ *
93
+ * @param obj - The value to test.
94
+ * @returns `true` if `obj` is a sigil instance.
95
+ */
96
+ static isSigilified(obj) {
97
+ return isSigilInstance(obj);
98
+ }
99
+ /**
100
+ * Check whether `other` is (or inherits from) the type represented by the calling constructor.
101
+ *
102
+ * Implementation detail:
103
+ * - Uses the other instance's `__TYPE_SET__` for O(1) membership test.
104
+ * - O(1) and reliable as long as `OPTIONS.skipLabelInheritanceCheck` is `false`.
105
+ *
106
+ * This replaces `instanceof` so that checks remain valid across bundles/realms
107
+ * and when subclassing.
108
+ *
109
+ * @typeParam T - The calling constructor type (narrowing the returned instance type).
110
+ * @param this - The constructor performing the check.
111
+ * @param other - The object to test.
112
+ * @returns `true` if `other` is an instance of this type or a subtype.
113
+ */
114
+ static isOfType(other) {
115
+ if (!isSigilInstance(other))
116
+ return false;
117
+ const otherCtor = getConstructor(other);
118
+ if (!otherCtor)
119
+ return false;
120
+ const otherSet = otherCtor[__TYPE_SET__];
121
+ return !!otherSet && otherSet.has(this.SigilType);
122
+ }
123
+ /**
124
+ * Strict lineage check: compares the type symbol lineage arrays element-by-element.
125
+ *
126
+ * Implementation detail:
127
+ * - Works in O(n) time where n is the depth of the lineage.
128
+ * - Reliable when `OPTIONS.skipLabelInheritanceCheck` is `false`.
129
+ *
130
+ * @typeParam T - The calling constructor type.
131
+ * @param this - The constructor performing the check.
132
+ * @param other - The object to test.
133
+ * @returns `true` if `other` has an identical lineage up to the length of this constructor's lineage.
134
+ */
135
+ static isOfTypeStrict(other) {
136
+ if (!isSigilInstance(other))
137
+ return false;
138
+ const otherCtor = getConstructor(other);
139
+ if (!otherCtor)
140
+ return false;
141
+ const otherLineage = otherCtor[__TYPE_LINEAGE__];
142
+ const thisLineage = this[__TYPE_LINEAGE__];
143
+ return (!!otherLineage && thisLineage.every((s, i) => s === otherLineage[i]));
144
+ }
145
+ /**
146
+ * Returns the human-readable sigil label of this instance's constructor.
147
+ *
148
+ * @returns The label string (e.g. '@scope/pkg.ClassName') or '@Sigil.unknown' in DEV when constructor is missing.
149
+ */
150
+ getSigilLabel() {
151
+ const ctor = getConstructor(this);
152
+ if (!ctor) {
153
+ if (opts?.devMarker ?? OPTIONS.devMarker)
154
+ throw new Error(`[Sigil Error] 'Sigilify(${label})' instance without constructor`);
155
+ return '@Sigil.unknown';
156
+ }
157
+ return ctor.SigilLabel;
158
+ }
159
+ /**
160
+ * Returns the runtime sigil type symbol of this instance's constructor.
161
+ *
162
+ * @returns The symbol that identifies this type at runtime.
163
+ */
164
+ getSigilType() {
165
+ const ctor = getConstructor(this);
166
+ if (!ctor) {
167
+ if (opts?.devMarker ?? OPTIONS.devMarker)
168
+ throw new Error(`[Sigil Error] 'Sigilify(${label})' instance without constructor`);
169
+ return Symbol.for('@Sigil.unknown');
170
+ }
171
+ return ctor.SigilType;
172
+ }
173
+ /**
174
+ * Returns a copy of the sigil type symbol lineage for this instance's constructor.
175
+ *
176
+ * @returns readonly array of symbols representing the type lineage.
177
+ */
178
+ getSigilTypeLineage() {
179
+ const ctor = getConstructor(this);
180
+ if (!ctor) {
181
+ if (opts?.devMarker ?? OPTIONS.devMarker)
182
+ throw new Error(`[Sigil Error] 'Sigilify(${label})' instance without constructor`);
183
+ return [Symbol.for('@Sigil.unknown')];
184
+ }
185
+ return ctor.SigilTypeLineage;
186
+ }
187
+ /**
188
+ * Returns a readonly copy of the sigil type symbol set for this instance's constructor.
189
+ *
190
+ * @returns A Readonly Set of symbols representing the type lineage for O(1) membership tests.
191
+ */
192
+ getSigilTypeSet() {
193
+ const ctor = getConstructor(this);
194
+ if (!ctor) {
195
+ if (opts?.devMarker ?? OPTIONS.devMarker)
196
+ throw new Error(`[Sigil Error] 'Sigilify(${label})' instance without constructor`);
197
+ return new Set([Symbol.for('@Sigil.unknown')]);
198
+ }
199
+ return ctor.SigilTypeSet;
200
+ }
201
+ }
202
+ // Attach sigil metadata to constructor (registers label, sets symbols, marks decorated)
203
+ decorateCtor(Sigilified, l);
204
+ // Mark the returned constructor as sigil (runtime flag) and as a base.
205
+ markSigil(Sigilified);
206
+ markSigilBase(Sigilified);
207
+ return Sigilified;
208
+ }
209
+ //# sourceMappingURL=mixin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixin.js","sourceRoot":"","sources":["../../src/core/mixin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Configuration options for the Sigil library.
3
+ *
4
+ * These options control runtime validation, inheritance checks, label autofill behavior,
5
+ * and whether duplicate labels are permitted globally.
6
+ *
7
+ * Note: these options are read by runtime code during class decoration and inheritance
8
+ * checks. Some behaviors (like `skipLabelInheritanceCheck`) are meant primarily for
9
+ * development/test scenarios and may weaken type/identity guarantees when changed.
10
+ */
11
+ export interface SigilOptions {
12
+ /**
13
+ * Validation rule applied to sigil labels before registration.
14
+ *
15
+ * - A function receives the label and must return `true` if valid.
16
+ * - A `RegExp` must match the label.
17
+ * - `null` disables validation entirely.
18
+ *
19
+ * Defaults to `null`.
20
+ */
21
+ labelValidation?: ((label: string) => boolean) | RegExp | null;
22
+ /**
23
+ * Skips the runtime check that prevents subclasses from inheriting
24
+ * the same sigil label as their ancestors.
25
+ *
26
+ * When `false` (default), extending a sigil class without
27
+ * using `WithSigil(newLabel)` decorator will throw an error if the label
28
+ * is reused and `OPTIONS.autofillLabels` is set to `false`.
29
+ *
30
+ * Set this to `true` only if you intentionally want subclasses to inherit labels
31
+ * from their ancestors (this weakens the uniqueness guarantees).
32
+ */
33
+ skipLabelInheritanceCheck?: boolean;
34
+ /**
35
+ * When enabled, non-decorated subclasses that would otherwise inherit an ancestor's label
36
+ * will be assigned an autogenerated random label (so that explicit labels stay unique).
37
+ */
38
+ autofillLabels?: boolean;
39
+ /**
40
+ * Marker used internally to control dev only checks to optimize performace while preserving
41
+ * consistency for things like inheritance checks.
42
+ * defaults to 'process.env.NODE_ENV !== "production'.
43
+ */
44
+ devMarker?: boolean;
45
+ }
46
+ /**
47
+ * Default runtime options used by the Sigil library.
48
+ *
49
+ * These values may be mutated by calling `updateOptions` at app startup.
50
+ *
51
+ * @internal
52
+ */
53
+ export declare const OPTIONS: Required<SigilOptions>;
54
+ /**
55
+ * Update runtime options for the Sigil library.
56
+ * Call this early during application startup if you want non-default behavior.
57
+ *
58
+ * Example:
59
+ * ```ts
60
+ * updateOptions({ autofillLabels: true, labelValidation: /^@[\w-]+\/[\w-]+\.[A-Za-z0-9]+$/ });
61
+ * ```
62
+ *
63
+ * @param opts - Partial options to merge into the global `OPTIONS` object.
64
+ */
65
+ export declare const updateOptions: (opts: SigilOptions) => void;
66
+ /**
67
+ * Label validation regex. Labels must follow the pattern
68
+ * `@scope/package.ClassName` where `ClassName` begins with an uppercase
69
+ * letter. This avoids collisions across packages and helps debugging.
70
+ *
71
+ * It's advised to use this regex in 'SigilOptions.labelValidation'.
72
+ */
73
+ export declare const DEFAULT_LABEL_REGEX: RegExp;
74
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/core/options.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IAE/D;;;;;;;;;;OAUG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,YAAY,CAK1C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,YAAY,KAAG,IAElD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,QAA8C,CAAC"}
@@ -0,0 +1,39 @@
1
+ /** Dev check */
2
+ const DEV = process.env.NODE_ENV !== 'production';
3
+ /**
4
+ * Default runtime options used by the Sigil library.
5
+ *
6
+ * These values may be mutated by calling `updateOptions` at app startup.
7
+ *
8
+ * @internal
9
+ */
10
+ export const OPTIONS = {
11
+ labelValidation: null,
12
+ skipLabelInheritanceCheck: false,
13
+ autofillLabels: false,
14
+ devMarker: DEV,
15
+ };
16
+ /**
17
+ * Update runtime options for the Sigil library.
18
+ * Call this early during application startup if you want non-default behavior.
19
+ *
20
+ * Example:
21
+ * ```ts
22
+ * updateOptions({ autofillLabels: true, labelValidation: /^@[\w-]+\/[\w-]+\.[A-Za-z0-9]+$/ });
23
+ * ```
24
+ *
25
+ * @param opts - Partial options to merge into the global `OPTIONS` object.
26
+ */
27
+ export const updateOptions = (opts) => {
28
+ for (const [k, v] of Object.entries(opts))
29
+ OPTIONS[k] = v;
30
+ };
31
+ /**
32
+ * Label validation regex. Labels must follow the pattern
33
+ * `@scope/package.ClassName` where `ClassName` begins with an uppercase
34
+ * letter. This avoids collisions across packages and helps debugging.
35
+ *
36
+ * It's advised to use this regex in 'SigilOptions.labelValidation'.
37
+ */
38
+ export const DEFAULT_LABEL_REGEX = /^@[\w-]+(?:\/[\w-]+)*\.[A-Z][A-Za-z0-9]*$/;
39
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/core/options.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;AAmDlD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAA2B;IAC7C,eAAe,EAAE,IAAI;IACrB,yBAAyB,EAAE,KAAK;IAChC,cAAc,EAAE,KAAK;IACrB,SAAS,EAAE,GAAG;CACf,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAkB,EAAQ,EAAE;IACxD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QAAG,OAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACrE,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,2CAA2C,CAAC"}
@@ -0,0 +1,104 @@
1
+ import { type SigilOptions } from './options';
2
+ import type { ISigil } from './types';
3
+ /** --------------------------------
4
+ * Registry class
5
+ * -------------------------------- */
6
+ /**
7
+ * Small wrapper around a shared registry Set that provides safe operations
8
+ * and hot-reload-friendly behavior.
9
+ *
10
+ * Responsibilities:
11
+ * - Query the current registry (may be `null` to indicate disabled checks).
12
+ * - Register / unregister labels in a controlled manner.
13
+ * - Query class constructors using there 'SigilLabel'.
14
+ * - Support hot-reload tolerant registration (avoid throwing in DEV).
15
+ * - Replace / merge registries when a new Map is provided by the consumer.
16
+ *
17
+ * This class intentionally keeps a minimal API so consumers can use a single
18
+ * shared instance (`REGISTRY`) or instantiate their own if needed.
19
+ */
20
+ declare class Registry {
21
+ /** Internal pointer to the active registry (may be null to indicate checks disabled). */
22
+ private _registry;
23
+ /**
24
+ * Return a readonly view (array) of the current registry entries.
25
+ *
26
+ * @returns An array containing all registered labels, or an empty array when registry is disabled.
27
+ */
28
+ listLabels(): string[];
29
+ /**
30
+ * Determine whether the registry currently contains `label`.
31
+ *
32
+ * @param label - The label to test.
33
+ * @returns `true` if present; `false` otherwise or when registry is disabled.
34
+ */
35
+ has(label: string): boolean;
36
+ /**
37
+ * Get class constructor using its label.
38
+ *
39
+ * @param label - Label appended to Sigil class.
40
+ * @returns Reference to Sigil class constructor.
41
+ */
42
+ get(label: string): ISigil | undefined;
43
+ /**
44
+ * Register a label and class constructor in the active registry.
45
+ *
46
+ * Behavior:
47
+ * - If the registry is disabled (`null`), this is a no-op.
48
+ * - If the label already exists then:
49
+ * - In DEV builds: prints a console warning (HMR friendly) and returns early.
50
+ * - In non-DEV builds: throws an Error to prevent duplicate registration.
51
+ *
52
+ * @param label - Label string to register (e.g. '@scope/pkg.ClassName').
53
+ * @param Class - Constructor of the class being registered.
54
+ * @param opts - Optional per-call overrides.
55
+ */
56
+ register(label: string, Class: ISigil, opts?: Pick<SigilOptions, 'devMarker'>): void;
57
+ /**
58
+ * Unregister a previously registered class.
59
+ *
60
+ * @param label - The label to remove from the registry.
61
+ * @returns `true` if the label was present and removed; `false` otherwise (or when registry is disabled).
62
+ */
63
+ unregister(label: string): boolean;
64
+ /**
65
+ * Clear the registry completely.
66
+ *
67
+ * Useful for test teardown, or when explicitly resetting state during development.
68
+ * No-op when the registry is disabled.
69
+ */
70
+ clear(): void;
71
+ /**
72
+ * Replace the active registry with `newRegistry`.
73
+ *
74
+ * When replacing, any existing entries are merged into `newRegistry` so that
75
+ * registrations are not lost automatically. This design choice preserves
76
+ * previously registered labels while allowing callers to supply a custom Set
77
+ * instance (for example, a Set shared between worker threads or an external
78
+ * synchronization mechanism).
79
+ *
80
+ * Important notes:
81
+ * - Replacing the registry transfers existing entries into `newRegistry` when both are non-null.
82
+ * - The global default Set stored on `globalThis` is *not* updated by this method; responsibility
83
+ * for further management of the `newRegistry` (such as re-exposing it on `globalThis`) lies with the caller.
84
+ * - If you want to *disable* registry checks, call `replaceRegistry(null)`.
85
+ *
86
+ * @param newRegistry - New Set<string> instance to use as the active registry, or `null` to disable checks.
87
+ */
88
+ replaceRegistry(newRegistry: Map<string, ISigil> | null): void;
89
+ /**
90
+ * Get the size (number of entries) of the active registry.
91
+ *
92
+ * @returns The number of registered labels, or 0 when registry is disabled.
93
+ */
94
+ get size(): number;
95
+ }
96
+ /**
97
+ * Convenience singleton instance for consumers that prefer a single shared API.
98
+ *
99
+ * Use `REGISTRY` to register/unregister labels, inspect the registry, and (optionally)
100
+ * replace the active Set by calling `REGISTRY.replaceRegistry(...)`.
101
+ */
102
+ export declare const REGISTRY: Registry;
103
+ export {};
104
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAwCtC;;sCAEsC;AAEtC;;;;;;;;;;;;;GAaG;AACH,cAAM,QAAQ;IACZ,yFAAyF;IACzF,OAAO,CAAC,SAAS,CAAmD;IAEpE;;;;OAIG;IACH,UAAU,IAAI,MAAM,EAAE;IAItB;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI3B;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKtC;;;;;;;;;;;;OAYG;IACH,QAAQ,CACN,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,GACrC,IAAI;IAiBP;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAKlC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAKb;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI;IAO9D;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,UAAiB,CAAC"}
@@ -0,0 +1,174 @@
1
+ import { OPTIONS } from './options';
2
+ /** --------------------------------
3
+ * Default registry
4
+ * -------------------------------- */
5
+ /**
6
+ * Global registry key used on `globalThis` to store a map of Sigil labels and reference to there classes.
7
+ *
8
+ * We use `Symbol.for` so the same key survives across bundles that share the
9
+ * global symbol registry (useful for HMR/dev workflows).
10
+ *
11
+ * @internal
12
+ * @constant {symbol}
13
+ */
14
+ const __SIGIL_REGISTRY__ = Symbol.for('@Sigil.__SIGIL_REGISTRY__');
15
+ /**
16
+ * Lazily initialize and return the global label registry Map.
17
+ *
18
+ * The registry is stored on `globalThis` so it survives module reloads during HMR.
19
+ * If registry checks are intentionally disabled, users can replace the active registry
20
+ * with `null` via `REGISTRY.replaceRegistry(null)`.
21
+ *
22
+ * @returns A Map<string, ISigil> representing the active registry (created if missing).
23
+ */
24
+ const getGlobalRegistry = () => {
25
+ if (!(__SIGIL_REGISTRY__ in globalThis)) {
26
+ globalThis[__SIGIL_REGISTRY__] = new Map();
27
+ }
28
+ return globalThis[__SIGIL_REGISTRY__];
29
+ };
30
+ /**
31
+ * Update global map stored.
32
+ */
33
+ const updateGlobalRegistry = (map) => {
34
+ globalThis[__SIGIL_REGISTRY__] = map;
35
+ };
36
+ /** --------------------------------
37
+ * Registry class
38
+ * -------------------------------- */
39
+ /**
40
+ * Small wrapper around a shared registry Set that provides safe operations
41
+ * and hot-reload-friendly behavior.
42
+ *
43
+ * Responsibilities:
44
+ * - Query the current registry (may be `null` to indicate disabled checks).
45
+ * - Register / unregister labels in a controlled manner.
46
+ * - Query class constructors using there 'SigilLabel'.
47
+ * - Support hot-reload tolerant registration (avoid throwing in DEV).
48
+ * - Replace / merge registries when a new Map is provided by the consumer.
49
+ *
50
+ * This class intentionally keeps a minimal API so consumers can use a single
51
+ * shared instance (`REGISTRY`) or instantiate their own if needed.
52
+ */
53
+ class Registry {
54
+ /** Internal pointer to the active registry (may be null to indicate checks disabled). */
55
+ _registry = getGlobalRegistry();
56
+ /**
57
+ * Return a readonly view (array) of the current registry entries.
58
+ *
59
+ * @returns An array containing all registered labels, or an empty array when registry is disabled.
60
+ */
61
+ listLabels() {
62
+ return this._registry ? Array.from(this._registry.keys()) : [];
63
+ }
64
+ /**
65
+ * Determine whether the registry currently contains `label`.
66
+ *
67
+ * @param label - The label to test.
68
+ * @returns `true` if present; `false` otherwise or when registry is disabled.
69
+ */
70
+ has(label) {
71
+ return !!this._registry && this._registry.has(label);
72
+ }
73
+ /**
74
+ * Get class constructor using its label.
75
+ *
76
+ * @param label - Label appended to Sigil class.
77
+ * @returns Reference to Sigil class constructor.
78
+ */
79
+ get(label) {
80
+ if (!this._registry)
81
+ return;
82
+ return this._registry.get(label);
83
+ }
84
+ /**
85
+ * Register a label and class constructor in the active registry.
86
+ *
87
+ * Behavior:
88
+ * - If the registry is disabled (`null`), this is a no-op.
89
+ * - If the label already exists then:
90
+ * - In DEV builds: prints a console warning (HMR friendly) and returns early.
91
+ * - In non-DEV builds: throws an Error to prevent duplicate registration.
92
+ *
93
+ * @param label - Label string to register (e.g. '@scope/pkg.ClassName').
94
+ * @param Class - Constructor of the class being registered.
95
+ * @param opts - Optional per-call overrides.
96
+ */
97
+ register(label, Class, opts) {
98
+ if (!this._registry)
99
+ return;
100
+ if (this._registry.has(label)) {
101
+ if (opts?.devMarker ?? OPTIONS.devMarker)
102
+ // The console is intentional
103
+ // eslint-disable-next-line no-console
104
+ console.warn(`[Sigil] Duplicate label "${label}" may be due to HMR — ignore if you are sure that it's defined once.`);
105
+ else
106
+ throw new Error(`[Sigil Error] Duplicate label '${label}' detected. Labels must be unique.`);
107
+ }
108
+ else
109
+ this._registry.set(label, Class);
110
+ }
111
+ /**
112
+ * Unregister a previously registered class.
113
+ *
114
+ * @param label - The label to remove from the registry.
115
+ * @returns `true` if the label was present and removed; `false` otherwise (or when registry is disabled).
116
+ */
117
+ unregister(label) {
118
+ if (!this._registry)
119
+ return false;
120
+ return this._registry.delete(label);
121
+ }
122
+ /**
123
+ * Clear the registry completely.
124
+ *
125
+ * Useful for test teardown, or when explicitly resetting state during development.
126
+ * No-op when the registry is disabled.
127
+ */
128
+ clear() {
129
+ if (!this._registry)
130
+ return;
131
+ this._registry.clear();
132
+ }
133
+ /**
134
+ * Replace the active registry with `newRegistry`.
135
+ *
136
+ * When replacing, any existing entries are merged into `newRegistry` so that
137
+ * registrations are not lost automatically. This design choice preserves
138
+ * previously registered labels while allowing callers to supply a custom Set
139
+ * instance (for example, a Set shared between worker threads or an external
140
+ * synchronization mechanism).
141
+ *
142
+ * Important notes:
143
+ * - Replacing the registry transfers existing entries into `newRegistry` when both are non-null.
144
+ * - The global default Set stored on `globalThis` is *not* updated by this method; responsibility
145
+ * for further management of the `newRegistry` (such as re-exposing it on `globalThis`) lies with the caller.
146
+ * - If you want to *disable* registry checks, call `replaceRegistry(null)`.
147
+ *
148
+ * @param newRegistry - New Set<string> instance to use as the active registry, or `null` to disable checks.
149
+ */
150
+ replaceRegistry(newRegistry) {
151
+ const old = this._registry;
152
+ if (old && newRegistry)
153
+ for (const [l, c] of old)
154
+ newRegistry.set(l, c);
155
+ updateGlobalRegistry(newRegistry);
156
+ this._registry = newRegistry;
157
+ }
158
+ /**
159
+ * Get the size (number of entries) of the active registry.
160
+ *
161
+ * @returns The number of registered labels, or 0 when registry is disabled.
162
+ */
163
+ get size() {
164
+ return this._registry ? this._registry.size : 0;
165
+ }
166
+ }
167
+ /**
168
+ * Convenience singleton instance for consumers that prefer a single shared API.
169
+ *
170
+ * Use `REGISTRY` to register/unregister labels, inspect the registry, and (optionally)
171
+ * replace the active Set by calling `REGISTRY.replaceRegistry(...)`.
172
+ */
173
+ export const REGISTRY = new Registry();
174
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAqB,MAAM,WAAW,CAAC;AAGvD;;sCAEsC;AAEtC;;;;;;;;GAQG;AACH,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,iBAAiB,GAAG,GAAwB,EAAE;IAClD,IAAI,CAAC,CAAC,kBAAkB,IAAI,UAAU,CAAC,EAAE,CAAC;QACvC,UAAkB,CAAC,kBAAkB,CAAC,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtE,CAAC;IACD,OAAQ,UAAkB,CAAC,kBAAkB,CAAwB,CAAC;AACxE,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,oBAAoB,GAAG,CAAC,GAA+B,EAAQ,EAAE;IACpE,UAAkB,CAAC,kBAAkB,CAAC,GAAG,GAAG,CAAC;AAChD,CAAC,CAAC;AAEF;;sCAEsC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,QAAQ;IACZ,yFAAyF;IACjF,SAAS,GAA+B,iBAAiB,EAAE,CAAC;IAEpE;;;;OAIG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAa;QACf,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAa;QACf,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,QAAQ,CACN,KAAa,EACb,KAAa,EACb,IAAsC;QAEtC,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,IAAI,EAAE,SAAS,IAAI,OAAO,CAAC,SAAS;gBACtC,6BAA6B;gBAC7B,sCAAsC;gBACtC,OAAO,CAAC,IAAI,CACV,4BAA4B,KAAK,sEAAsE,CACxG,CAAC;;gBAEF,MAAM,IAAI,KAAK,CACb,kCAAkC,KAAK,oCAAoC,CAC5E,CAAC;QACN,CAAC;;YAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,KAAa;QACtB,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAClC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACH,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CAAC,WAAuC;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;QAC3B,IAAI,GAAG,IAAI,WAAW;YAAE,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG;gBAAE,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxE,oBAAoB,CAAC,WAAW,CAAC,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC"}