web-signature 0.1.3 → 0.1.4

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.
@@ -91,15 +91,93 @@ declare abstract class Component implements Component$1 {
91
91
  }
92
92
  type ComponentConstructor = new () => Component;
93
93
 
94
+ type LibMeta = {
95
+ name: string;
96
+ version?: string;
97
+ author?: string;
98
+ components: string[];
99
+ dependencies: Record<string, LibMeta>;
100
+ };
101
+ declare class Library {
102
+ readonly name: string;
103
+ readonly version?: string;
104
+ readonly author?: string;
105
+ libs: Record<string, LibMeta>;
106
+ private components;
107
+ /**
108
+ * @param {string} name The name of the library.
109
+ * @param {string} [author] Optional author of the library.
110
+ * @param {string} [version] Optional version of the library.
111
+ */
112
+ constructor(name: string, author?: string, version?: string);
113
+ /**
114
+ * Registers a component in the library.
115
+ * @param {ComponentConstructor} component The component to register.
116
+ * @param {string} [name] Optional name for the component. If not provided, uses the component's name property.
117
+ */
118
+ add(component: ComponentConstructor, name?: string): void;
119
+ /**
120
+ * Registers a library.
121
+ * @import {Library} from "./Library.js";
122
+ * @param {Library} library The library to register.
123
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
124
+ */
125
+ register(library: Library, ...exclude: string[]): void;
126
+ /**
127
+ * Retrieves a component by its name.
128
+ * @param {string} name The name of the component to retrieve.
129
+ * @return {ComponentConstructor | undefined} The component associated with the name, or undefined if it does not exist.
130
+ */
131
+ get(name: string): ComponentConstructor | undefined;
132
+ /**
133
+ * Returns a library.
134
+ * @param {string} name The name of the library.
135
+ * @return {LibMeta}
136
+ */
137
+ lib(name: string): LibMeta | undefined;
138
+ /**
139
+ * Lists all registered components in the library.
140
+ * @return {Array<{ component: ComponentConstructor, name: string }>} An array of objects containing component constructors and their names.
141
+ */
142
+ list(): Array<{
143
+ component: ComponentConstructor;
144
+ name: string;
145
+ }>;
146
+ }
147
+
148
+ type ResolvedLib = {
149
+ components: string[];
150
+ dependencies: Record<string, ResolvedLib>;
151
+ };
94
152
  declare class Signature {
95
153
  private components;
96
154
  private refs;
155
+ private libs;
97
156
  constructor();
98
157
  /**
99
158
  * Adds a component to the signature.
100
159
  * @param {ComponentConstructor} component The component to add.
160
+ * @param {string} name Optional name for the component. If not provided, uses the component's name property.
161
+ */
162
+ add(component: ComponentConstructor, name?: string): void;
163
+ /**
164
+ * Registers a library in the signature.
165
+ * @import {Library} from "./Library.js";
166
+ * @param {Library} library The library to register.
167
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
168
+ */
169
+ register(library: Library, ...exclude: string[]): void;
170
+ /**
171
+ * Returns a library.
172
+ * @param {string} name The name of the library.
173
+ * @return {LibMeta}
174
+ */
175
+ lib(name: string): LibMeta | undefined;
176
+ /**
177
+ * Returns a formatted object of all libraries in the signature.
178
+ * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
101
179
  */
102
- add(component: ComponentConstructor): void;
180
+ libraries(): Record<string, ResolvedLib>;
103
181
  /**
104
182
  * Returns a reference.
105
183
  * @param {string} name The name of the reference.
@@ -141,4 +219,4 @@ declare class Prop<T extends keyof TypesMap> implements Prop$1 {
141
219
 
142
220
  declare function export_default(): Signature;
143
221
 
144
- export { Component, Prop, Signature, export_default as default };
222
+ export { Component, Library, Prop, Signature, export_default as default };
package/bundle/index.js CHANGED
@@ -22,17 +22,79 @@ let _counter = 0;
22
22
  class Signature {
23
23
  components = {};
24
24
  refs = {};
25
+ libs = {};
25
26
  constructor() {
26
27
  }
27
28
  /**
28
29
  * Adds a component to the signature.
29
30
  * @param {ComponentConstructor} component The component to add.
31
+ * @param {string} name Optional name for the component. If not provided, uses the component's name property.
30
32
  */
31
- add(component) {
32
- if (this.components[component.name]) {
33
- console.warn(new Error(`Component with name ${component.name} already exists.`));
33
+ add(component, name) {
34
+ const key = typeof name === "string" ? name : component.name;
35
+ if (this.components[key]) {
36
+ console.warn(new Error(`Component with name ${key} already exists.`));
34
37
  }
35
- this.components[component.name] = component;
38
+ this.components[key] = component;
39
+ }
40
+ /**
41
+ * Registers a library in the signature.
42
+ * @import {Library} from "./Library.js";
43
+ * @param {Library} library The library to register.
44
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
45
+ */
46
+ register(library, ...exclude) {
47
+ if (this.libs[library.name]) {
48
+ console.warn(new Error(`Library with name ${library.name} already exists.`));
49
+ }
50
+ const components = library.list().filter(com => !(com.name in exclude));
51
+ this.libs[library.name] = {
52
+ name: library.name,
53
+ version: library.version,
54
+ author: library.author,
55
+ components: components.map(com => com.name),
56
+ dependencies: library.libs
57
+ };
58
+ for (const com of components) {
59
+ this.add(com.component, `${library.name}-${com.name}`);
60
+ }
61
+ }
62
+ /**
63
+ * Returns a library.
64
+ * @param {string} name The name of the library.
65
+ * @return {LibMeta}
66
+ */
67
+ lib(name) {
68
+ return this.libs[name];
69
+ }
70
+ /**
71
+ * Returns a formatted object of all libraries in the signature.
72
+ * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
73
+ */
74
+ libraries() {
75
+ const formatKey = (lib) => {
76
+ let key = lib.name;
77
+ if (lib.version)
78
+ key += `@${lib.version}`;
79
+ if (lib.author)
80
+ key += `#${lib.author}`;
81
+ return key;
82
+ };
83
+ const resolve = (libs, visited = new Set()) => {
84
+ const result = {};
85
+ for (const [_, lib] of Object.entries(libs)) {
86
+ const key = formatKey(lib);
87
+ if (visited.has(key))
88
+ continue;
89
+ visited.add(key);
90
+ result[key] = {
91
+ components: lib.components,
92
+ dependencies: resolve(lib.dependencies, visited)
93
+ };
94
+ }
95
+ return result;
96
+ };
97
+ return resolve(this.libs);
36
98
  }
37
99
  /**
38
100
  * Returns a reference.
@@ -276,8 +338,87 @@ class Prop {
276
338
  }
277
339
  }
278
340
 
341
+ class Library {
342
+ name;
343
+ version;
344
+ author;
345
+ libs = {};
346
+ components = {};
347
+ /**
348
+ * @param {string} name The name of the library.
349
+ * @param {string} [author] Optional author of the library.
350
+ * @param {string} [version] Optional version of the library.
351
+ */
352
+ constructor(name, author, version) {
353
+ this.name = name;
354
+ // optional properties
355
+ this.author = author;
356
+ this.version = version;
357
+ }
358
+ /**
359
+ * Registers a component in the library.
360
+ * @param {ComponentConstructor} component The component to register.
361
+ * @param {string} [name] Optional name for the component. If not provided, uses the component's name property.
362
+ */
363
+ add(component, name) {
364
+ const key = typeof name === "string" ? name : component.name;
365
+ if (this.components[key]) {
366
+ console.warn(new Error(`Component with name ${key} already exists.`));
367
+ }
368
+ this.components[key] = component;
369
+ }
370
+ /**
371
+ * Registers a library.
372
+ * @import {Library} from "./Library.js";
373
+ * @param {Library} library The library to register.
374
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
375
+ */
376
+ register(library, ...exclude) {
377
+ if (this.libs[library.name]) {
378
+ console.warn(new Error(`Library with name ${library.name} already exists in ${this.name}.`));
379
+ }
380
+ const components = library.list().filter(com => !(com.name in exclude));
381
+ this.libs[library.name] = {
382
+ name: library.name,
383
+ version: library.version,
384
+ author: library.author,
385
+ components: components.map(com => com.name),
386
+ dependencies: library.libs
387
+ };
388
+ for (const com of components) {
389
+ this.add(com.component, `${library.name}-${com.name}`);
390
+ }
391
+ }
392
+ /**
393
+ * Retrieves a component by its name.
394
+ * @param {string} name The name of the component to retrieve.
395
+ * @return {ComponentConstructor | undefined} The component associated with the name, or undefined if it does not exist.
396
+ */
397
+ get(name) {
398
+ return this.components[name];
399
+ }
400
+ /**
401
+ * Returns a library.
402
+ * @param {string} name The name of the library.
403
+ * @return {LibMeta}
404
+ */
405
+ lib(name) {
406
+ return this.libs[name];
407
+ }
408
+ /**
409
+ * Lists all registered components in the library.
410
+ * @return {Array<{ component: ComponentConstructor, name: string }>} An array of objects containing component constructors and their names.
411
+ */
412
+ list() {
413
+ return Object.entries(this.components).map(([name, component]) => ({
414
+ component,
415
+ name
416
+ }));
417
+ }
418
+ }
419
+
279
420
  function index () {
280
421
  return new Signature();
281
422
  }
282
423
 
283
- export { Component, Prop, Signature, index as default };
424
+ export { Component, Library, Prop, Signature, index as default };
@@ -1 +1 @@
1
- class e{element;instance;constructor(e,t){this.instance=e,this.element=t}}const t={"element-not-found":"Element not found for selector: #selector","prop-is-required":"Property '#prop' in component '#component' is required but not provided.","unsupported-type-for-property":"Unsupported type for property '#prop' in component '#component': #type","invalid-value-for-property":"Invalid value for property '#prop' in component '#component': #value (value: #attr)","multiple-root-elements":"Component '#component' must render a single root element. \n\t#elements","ref-collision":"Ref collision detected for ref '#ref' in component '#component'.",unknown:"An unknown error occurred.","unknown-from":"An unknown error occurred in component '#from'."};let n=0;class r{components={};refs={};constructor(){}add(e){this.components[e.name]&&console.warn(new Error(`Component with name ${e.name} already exists.`)),this.components[e.name]=e}ref(e){return this.refs[e]?.element}contactWith(e,...t){const n=this.refs[e];if(!n)throw new Error(`Ref with name ${e} does not exist.`);const r=n.instance;return r.onContact?.(...t)}updateRef(e){const t=this.refs[e];if(!t)throw new Error(`Ref with name ${e} does not exist.`);const n=t.instance,r=n.render().trim(),o=document.createElement("template");if(o.innerHTML=r,1!==o.content.children.length)throw new Error(`Component '${n.name}' must render a single root element.`);const i=o.content.firstElementChild;this.render(o),n.onRender?.(),t.element.replaceWith(i),t.element=i,n.onMount?.(i)}contact(e){new Promise((t,n)=>{try{const t=document.querySelector(e);if(!t)return void n({id:"element-not-found",selector:e});const r=document.createElement("div");r.innerHTML=t.innerHTML,this.render(r),t.replaceChildren(...Array.from(r.childNodes))}catch(e){e instanceof Error?n({id:"unknown",err:e}):n(e)}}).then(()=>{}).catch(e=>{let n=t[e.id];throw Object.keys(e).filter(e=>!(e in["id","err"])).forEach(t=>{n=n.replace(`#${t}`,String(e[t]))}),e.id in["unknown","unknown-from"]?console.error(`[${e.id}] ${n}`,e.err):console.error(`[${e.id}] ${n}`),"Page rendering was interrupted by Signature due to the above error."})}render(t){for(const r of Object.keys(this.components)){const o=this.components[r];for(const i of Array.from(t.querySelectorAll(r))){const t=new o;if(t.onInit?.(),i instanceof HTMLElement){t.content=i.innerHTML.trim();for(const e of Object.keys(t.props)){const n=i.getAttribute(e);if(null===n){if(t.props[e].required)throw{id:"prop-is-required",component:r,prop:e};t.data[e]=null}else if(""===n){if(t.props[e].required)throw{id:"prop-is-required",component:r,prop:e};t.props[e].isValid(n)&&(t.data[e]=null)}else{let o;switch(t.props[e].type){case"boolean":o=Boolean(n);break;case"number":o=Number(n);break;case"string":o=String(n);break;default:if(t.props[e].required)throw{id:"unsupported-type-for-property",component:r,prop:e,type:t.props[e].type}}if(void 0!==o){if(!t.props[e].isValid(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:n};if(t.props[e].validate&&!t.props[e].validate(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:n};t.data[e]=o,t.onPropParsed?.(t.props[e],o)}}}t.onPropsParsed?.()}const s=document.createElement("template");try{s.innerHTML=t.render().trim()}catch(e){if(e instanceof Error)throw{id:"unknown-from",from:t.name,err:e}}if(s.content.children.length>1)throw{id:"multiple-root-elements",component:r,elements:s.innerHTML};this.render(s),t.onRender?.();const p=s.content.firstElementChild;if(i.hasAttribute("ref")){let o=i.getAttribute("ref");if(n++,""===o&&(o=`r${n}${Math.random().toString(36).substring(2,15)}${n}`),this.refs[o])throw{id:"ref-collision",ref:o,component:r};this.refs[o]=new e(t,p),p.setAttribute("ref",o)}i.replaceWith(s.content),t.onMount?.(p)}}}}class o{content;props={};data={}}class i{type;required=!0;validate;constructor(e,t=!0,n){this.type=e,this.required=t,this.validate=n||(()=>!0)}isValid(e){switch(this.type){case"boolean":return"boolean"==typeof e;case"number":return"number"==typeof e&&!isNaN(e);case"string":return"string"==typeof e;case"null":return null===e;default:return!1}}}function s(){return new r}export{o as Component,i as Prop,r as Signature,s as default};
1
+ class e{element;instance;constructor(e,n){this.instance=e,this.element=n}}const n={"element-not-found":"Element not found for selector: #selector","prop-is-required":"Property '#prop' in component '#component' is required but not provided.","unsupported-type-for-property":"Unsupported type for property '#prop' in component '#component': #type","invalid-value-for-property":"Invalid value for property '#prop' in component '#component': #value (value: #attr)","multiple-root-elements":"Component '#component' must render a single root element. \n\t#elements","ref-collision":"Ref collision detected for ref '#ref' in component '#component'.",unknown:"An unknown error occurred.","unknown-from":"An unknown error occurred in component '#from'."};let t=0;class r{components={};refs={};libs={};constructor(){}add(e,n){const t="string"==typeof n?n:e.name;this.components[t]&&console.warn(new Error(`Component with name ${t} already exists.`)),this.components[t]=e}register(e,...n){this.libs[e.name]&&console.warn(new Error(`Library with name ${e.name} already exists.`));const t=e.list().filter(e=>!(e.name in n));this.libs[e.name]={name:e.name,version:e.version,author:e.author,components:t.map(e=>e.name),dependencies:e.libs};for(const n of t)this.add(n.component,`${e.name}-${n.name}`)}lib(e){return this.libs[e]}libraries(){const e=e=>{let n=e.name;return e.version&&(n+=`@${e.version}`),e.author&&(n+=`#${e.author}`),n},n=(t,r=new Set)=>{const o={};for(const[i,s]of Object.entries(t)){const t=e(s);r.has(t)||(r.add(t),o[t]={components:s.components,dependencies:n(s.dependencies,r)})}return o};return n(this.libs)}ref(e){return this.refs[e]?.element}contactWith(e,...n){const t=this.refs[e];if(!t)throw new Error(`Ref with name ${e} does not exist.`);const r=t.instance;return r.onContact?.(...n)}updateRef(e){const n=this.refs[e];if(!n)throw new Error(`Ref with name ${e} does not exist.`);const t=n.instance,r=t.render().trim(),o=document.createElement("template");if(o.innerHTML=r,1!==o.content.children.length)throw new Error(`Component '${t.name}' must render a single root element.`);const i=o.content.firstElementChild;this.render(o),t.onRender?.(),n.element.replaceWith(i),n.element=i,t.onMount?.(i)}contact(e){new Promise((n,t)=>{try{const n=document.querySelector(e);if(!n)return void t({id:"element-not-found",selector:e});const r=document.createElement("div");r.innerHTML=n.innerHTML,this.render(r),n.replaceChildren(...Array.from(r.childNodes))}catch(e){e instanceof Error?t({id:"unknown",err:e}):t(e)}}).then(()=>{}).catch(e=>{let t=n[e.id];throw Object.keys(e).filter(e=>!(e in["id","err"])).forEach(n=>{t=t.replace(`#${n}`,String(e[n]))}),e.id in["unknown","unknown-from"]?console.error(`[${e.id}] ${t}`,e.err):console.error(`[${e.id}] ${t}`),"Page rendering was interrupted by Signature due to the above error."})}render(n){for(const r of Object.keys(this.components)){const o=this.components[r];for(const i of Array.from(n.querySelectorAll(r))){const n=new o;if(n.onInit?.(),i instanceof HTMLElement){n.content=i.innerHTML.trim();for(const e of Object.keys(n.props)){const t=i.getAttribute(e);if(null===t){if(n.props[e].required)throw{id:"prop-is-required",component:r,prop:e};n.data[e]=null}else if(""===t){if(n.props[e].required)throw{id:"prop-is-required",component:r,prop:e};n.props[e].isValid(t)&&(n.data[e]=null)}else{let o;switch(n.props[e].type){case"boolean":o=Boolean(t);break;case"number":o=Number(t);break;case"string":o=String(t);break;default:if(n.props[e].required)throw{id:"unsupported-type-for-property",component:r,prop:e,type:n.props[e].type}}if(void 0!==o){if(!n.props[e].isValid(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:t};if(n.props[e].validate&&!n.props[e].validate(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:t};n.data[e]=o,n.onPropParsed?.(n.props[e],o)}}}n.onPropsParsed?.()}const s=document.createElement("template");try{s.innerHTML=n.render().trim()}catch(e){if(e instanceof Error)throw{id:"unknown-from",from:n.name,err:e}}if(s.content.children.length>1)throw{id:"multiple-root-elements",component:r,elements:s.innerHTML};this.render(s),n.onRender?.();const a=s.content.firstElementChild;if(i.hasAttribute("ref")){let o=i.getAttribute("ref");if(t++,""===o&&(o=`r${t}${Math.random().toString(36).substring(2,15)}${t}`),this.refs[o])throw{id:"ref-collision",ref:o,component:r};this.refs[o]=new e(n,a),a.setAttribute("ref",o)}i.replaceWith(s.content),n.onMount?.(a)}}}}class o{content;props={};data={}}class i{type;required=!0;validate;constructor(e,n=!0,t){this.type=e,this.required=n,this.validate=t||(()=>!0)}isValid(e){switch(this.type){case"boolean":return"boolean"==typeof e;case"number":return"number"==typeof e&&!isNaN(e);case"string":return"string"==typeof e;case"null":return null===e;default:return!1}}}class s{name;version;author;libs={};components={};constructor(e,n,t){this.name=e,this.author=n,this.version=t}add(e,n){const t="string"==typeof n?n:e.name;this.components[t]&&console.warn(new Error(`Component with name ${t} already exists.`)),this.components[t]=e}register(e,...n){this.libs[e.name]&&console.warn(new Error(`Library with name ${e.name} already exists in ${this.name}.`));const t=e.list().filter(e=>!(e.name in n));this.libs[e.name]={name:e.name,version:e.version,author:e.author,components:t.map(e=>e.name),dependencies:e.libs};for(const n of t)this.add(n.component,`${e.name}-${n.name}`)}get(e){return this.components[e]}lib(e){return this.libs[e]}list(){return Object.entries(this.components).map(([e,n])=>({component:n,name:e}))}}function a(){return new r}export{o as Component,s as Library,i as Prop,r as Signature,a as default};
@@ -0,0 +1,78 @@
1
+ export default class Library {
2
+ name;
3
+ version;
4
+ author;
5
+ libs = {};
6
+ components = {};
7
+ /**
8
+ * @param {string} name The name of the library.
9
+ * @param {string} [author] Optional author of the library.
10
+ * @param {string} [version] Optional version of the library.
11
+ */
12
+ constructor(name, author, version) {
13
+ this.name = name;
14
+ // optional properties
15
+ this.author = author;
16
+ this.version = version;
17
+ }
18
+ /**
19
+ * Registers a component in the library.
20
+ * @param {ComponentConstructor} component The component to register.
21
+ * @param {string} [name] Optional name for the component. If not provided, uses the component's name property.
22
+ */
23
+ add(component, name) {
24
+ const key = typeof name === "string" ? name : component.name;
25
+ if (this.components[key]) {
26
+ console.warn(new Error(`Component with name ${key} already exists.`));
27
+ }
28
+ this.components[key] = component;
29
+ }
30
+ /**
31
+ * Registers a library.
32
+ * @import {Library} from "./Library.js";
33
+ * @param {Library} library The library to register.
34
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
35
+ */
36
+ register(library, ...exclude) {
37
+ if (this.libs[library.name]) {
38
+ console.warn(new Error(`Library with name ${library.name} already exists in ${this.name}.`));
39
+ }
40
+ const components = library.list().filter(com => !(com.name in exclude));
41
+ this.libs[library.name] = {
42
+ name: library.name,
43
+ version: library.version,
44
+ author: library.author,
45
+ components: components.map(com => com.name),
46
+ dependencies: library.libs
47
+ };
48
+ for (const com of components) {
49
+ this.add(com.component, `${library.name}-${com.name}`);
50
+ }
51
+ }
52
+ /**
53
+ * Retrieves a component by its name.
54
+ * @param {string} name The name of the component to retrieve.
55
+ * @return {ComponentConstructor | undefined} The component associated with the name, or undefined if it does not exist.
56
+ */
57
+ get(name) {
58
+ return this.components[name];
59
+ }
60
+ /**
61
+ * Returns a library.
62
+ * @param {string} name The name of the library.
63
+ * @return {LibMeta}
64
+ */
65
+ lib(name) {
66
+ return this.libs[name];
67
+ }
68
+ /**
69
+ * Lists all registered components in the library.
70
+ * @return {Array<{ component: ComponentConstructor, name: string }>} An array of objects containing component constructors and their names.
71
+ */
72
+ list() {
73
+ return Object.entries(this.components).map(([name, component]) => ({
74
+ component,
75
+ name
76
+ }));
77
+ }
78
+ }
package/dist/Signature.js CHANGED
@@ -4,17 +4,79 @@ let _counter = 0;
4
4
  export default class Signature {
5
5
  components = {};
6
6
  refs = {};
7
+ libs = {};
7
8
  constructor() {
8
9
  }
9
10
  /**
10
11
  * Adds a component to the signature.
11
12
  * @param {ComponentConstructor} component The component to add.
13
+ * @param {string} name Optional name for the component. If not provided, uses the component's name property.
12
14
  */
13
- add(component) {
14
- if (this.components[component.name]) {
15
- console.warn(new Error(`Component with name ${component.name} already exists.`));
15
+ add(component, name) {
16
+ const key = typeof name === "string" ? name : component.name;
17
+ if (this.components[key]) {
18
+ console.warn(new Error(`Component with name ${key} already exists.`));
16
19
  }
17
- this.components[component.name] = component;
20
+ this.components[key] = component;
21
+ }
22
+ /**
23
+ * Registers a library in the signature.
24
+ * @import {Library} from "./Library.js";
25
+ * @param {Library} library The library to register.
26
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
27
+ */
28
+ register(library, ...exclude) {
29
+ if (this.libs[library.name]) {
30
+ console.warn(new Error(`Library with name ${library.name} already exists.`));
31
+ }
32
+ const components = library.list().filter(com => !(com.name in exclude));
33
+ this.libs[library.name] = {
34
+ name: library.name,
35
+ version: library.version,
36
+ author: library.author,
37
+ components: components.map(com => com.name),
38
+ dependencies: library.libs
39
+ };
40
+ for (const com of components) {
41
+ this.add(com.component, `${library.name}-${com.name}`);
42
+ }
43
+ }
44
+ /**
45
+ * Returns a library.
46
+ * @param {string} name The name of the library.
47
+ * @return {LibMeta}
48
+ */
49
+ lib(name) {
50
+ return this.libs[name];
51
+ }
52
+ /**
53
+ * Returns a formatted object of all libraries in the signature.
54
+ * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
55
+ */
56
+ libraries() {
57
+ const formatKey = (lib) => {
58
+ let key = lib.name;
59
+ if (lib.version)
60
+ key += `@${lib.version}`;
61
+ if (lib.author)
62
+ key += `#${lib.author}`;
63
+ return key;
64
+ };
65
+ const resolve = (libs, visited = new Set()) => {
66
+ const result = {};
67
+ for (const [_, lib] of Object.entries(libs)) {
68
+ const key = formatKey(lib);
69
+ if (visited.has(key))
70
+ continue;
71
+ visited.add(key);
72
+ result[key] = {
73
+ components: lib.components,
74
+ dependencies: resolve(lib.dependencies, visited)
75
+ };
76
+ }
77
+ return result;
78
+ };
79
+ return resolve(this.libs);
18
80
  }
19
81
  /**
20
82
  * Returns a reference.
@@ -0,0 +1,55 @@
1
+ import { ComponentConstructor } from "./Component.js";
2
+ type LibMeta = {
3
+ name: string;
4
+ version?: string;
5
+ author?: string;
6
+ components: string[];
7
+ dependencies: Record<string, LibMeta>;
8
+ };
9
+ export default class Library {
10
+ readonly name: string;
11
+ readonly version?: string;
12
+ readonly author?: string;
13
+ libs: Record<string, LibMeta>;
14
+ private components;
15
+ /**
16
+ * @param {string} name The name of the library.
17
+ * @param {string} [author] Optional author of the library.
18
+ * @param {string} [version] Optional version of the library.
19
+ */
20
+ constructor(name: string, author?: string, version?: string);
21
+ /**
22
+ * Registers a component in the library.
23
+ * @param {ComponentConstructor} component The component to register.
24
+ * @param {string} [name] Optional name for the component. If not provided, uses the component's name property.
25
+ */
26
+ add(component: ComponentConstructor, name?: string): void;
27
+ /**
28
+ * Registers a library.
29
+ * @import {Library} from "./Library.js";
30
+ * @param {Library} library The library to register.
31
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
32
+ */
33
+ register(library: Library, ...exclude: string[]): void;
34
+ /**
35
+ * Retrieves a component by its name.
36
+ * @param {string} name The name of the component to retrieve.
37
+ * @return {ComponentConstructor | undefined} The component associated with the name, or undefined if it does not exist.
38
+ */
39
+ get(name: string): ComponentConstructor | undefined;
40
+ /**
41
+ * Returns a library.
42
+ * @param {string} name The name of the library.
43
+ * @return {LibMeta}
44
+ */
45
+ lib(name: string): LibMeta | undefined;
46
+ /**
47
+ * Lists all registered components in the library.
48
+ * @return {Array<{ component: ComponentConstructor, name: string }>} An array of objects containing component constructors and their names.
49
+ */
50
+ list(): Array<{
51
+ component: ComponentConstructor;
52
+ name: string;
53
+ }>;
54
+ }
55
+ export { LibMeta };
@@ -1,13 +1,38 @@
1
1
  import { ComponentConstructor } from "./Component.js";
2
+ import Library, { LibMeta } from "./Library.js";
3
+ type ResolvedLib = {
4
+ components: string[];
5
+ dependencies: Record<string, ResolvedLib>;
6
+ };
2
7
  export default class Signature {
3
8
  private components;
4
9
  private refs;
10
+ private libs;
5
11
  constructor();
6
12
  /**
7
13
  * Adds a component to the signature.
8
14
  * @param {ComponentConstructor} component The component to add.
15
+ * @param {string} name Optional name for the component. If not provided, uses the component's name property.
9
16
  */
10
- add(component: ComponentConstructor): void;
17
+ add(component: ComponentConstructor, name?: string): void;
18
+ /**
19
+ * Registers a library in the signature.
20
+ * @import {Library} from "./Library.js";
21
+ * @param {Library} library The library to register.
22
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
23
+ */
24
+ register(library: Library, ...exclude: string[]): void;
25
+ /**
26
+ * Returns a library.
27
+ * @param {string} name The name of the library.
28
+ * @return {LibMeta}
29
+ */
30
+ lib(name: string): LibMeta | undefined;
31
+ /**
32
+ * Returns a formatted object of all libraries in the signature.
33
+ * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
34
+ */
35
+ libraries(): Record<string, ResolvedLib>;
11
36
  /**
12
37
  * Returns a reference.
13
38
  * @param {string} name The name of the reference.
@@ -32,3 +57,4 @@ export default class Signature {
32
57
  contact(selector: string): void;
33
58
  private render;
34
59
  }
60
+ export {};
package/dist/d/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export default function (): Signature;
3
3
  export { default as Signature } from './Signature.js';
4
4
  export { default as Component } from './Component.js';
5
5
  export { default as Prop } from './Prop.js';
6
+ export { default as Library } from './Library.js';
package/dist/index.js CHANGED
@@ -5,3 +5,4 @@ export default function () {
5
5
  export { default as Signature } from './Signature.js';
6
6
  export { default as Component } from './Component.js';
7
7
  export { default as Prop } from './Prop.js';
8
+ export { default as Library } from './Library.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-signature",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Primitive and fast framework for rendering web interfaces",
5
5
  "license": "ISC",
6
6
  "author": "PinBib",
package/src/Library.ts ADDED
@@ -0,0 +1,108 @@
1
+ import {ComponentConstructor} from "./Component.js";
2
+
3
+ type LibMeta = {
4
+ name: string,
5
+ version?: string,
6
+ author?: string,
7
+ components: string[],
8
+ dependencies: Record<string, LibMeta>
9
+ };
10
+
11
+ export default class Library {
12
+ public readonly name: string;
13
+ public readonly version?: string;
14
+ public readonly author?: string;
15
+
16
+ public libs: Record<string, LibMeta> = {};
17
+
18
+ private components: Record<string, ComponentConstructor> = {};
19
+
20
+ /**
21
+ * @param {string} name The name of the library.
22
+ * @param {string} [author] Optional author of the library.
23
+ * @param {string} [version] Optional version of the library.
24
+ */
25
+ constructor(name: string, author?: string, version?: string) {
26
+ this.name = name;
27
+
28
+ // optional properties
29
+ this.author = author;
30
+ this.version = version;
31
+ }
32
+
33
+ /**
34
+ * Registers a component in the library.
35
+ * @param {ComponentConstructor} component The component to register.
36
+ * @param {string} [name] Optional name for the component. If not provided, uses the component's name property.
37
+ */
38
+ public add(component: ComponentConstructor, name?: string): void {
39
+ const key = typeof name === "string" ? name : component.name;
40
+
41
+ if (this.components[key]) {
42
+ console.warn(new Error(`Component with name ${key} already exists.`));
43
+ }
44
+
45
+ this.components[key] = component;
46
+ }
47
+
48
+ /**
49
+ * Registers a library.
50
+ * @import {Library} from "./Library.js";
51
+ * @param {Library} library The library to register.
52
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
53
+ */
54
+ public register(library: Library, ...exclude: string[]): void {
55
+ if (this.libs[library.name]) {
56
+ console.warn(new Error(`Library with name ${library.name} already exists in ${this.name}.`));
57
+ }
58
+
59
+ const components: Array<{
60
+ component: ComponentConstructor,
61
+ name: string
62
+ }> = library.list().filter(com => !(com.name in exclude));
63
+
64
+ this.libs[library.name] = {
65
+ name: library.name,
66
+ version: library.version,
67
+ author: library.author,
68
+ components: components.map(com => com.name),
69
+ dependencies: library.libs
70
+ };
71
+
72
+ for (const com of components) {
73
+ this.add(com.component, `${library.name}-${com.name}`);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Retrieves a component by its name.
79
+ * @param {string} name The name of the component to retrieve.
80
+ * @return {ComponentConstructor | undefined} The component associated with the name, or undefined if it does not exist.
81
+ */
82
+ public get(name: string): ComponentConstructor | undefined {
83
+ return this.components[name];
84
+ }
85
+
86
+ /**
87
+ * Returns a library.
88
+ * @param {string} name The name of the library.
89
+ * @return {LibMeta}
90
+ */
91
+ public lib(name: string): LibMeta | undefined {
92
+ return this.libs[name];
93
+ }
94
+
95
+ /**
96
+ * Lists all registered components in the library.
97
+ * @return {Array<{ component: ComponentConstructor, name: string }>} An array of objects containing component constructors and their names.
98
+ */
99
+ public list(): Array<{ component: ComponentConstructor, name: string }> {
100
+ return Object.entries(this.components).map(([name, component]) => ({
101
+ component,
102
+ name
103
+ }));
104
+ }
105
+
106
+ }
107
+
108
+ export {LibMeta};
package/src/Signature.ts CHANGED
@@ -2,12 +2,19 @@ import Component, {ComponentConstructor} from "./Component.js";
2
2
  import Ref from "./Ref.js";
3
3
  import ErrorUnion from "./types/Errors.js";
4
4
  import Errors from "./Errors.js";
5
+ import Library, {LibMeta} from "./Library.js";
5
6
 
6
7
  let _counter = 0;
7
8
 
9
+ type ResolvedLib = {
10
+ components: string[],
11
+ dependencies: Record<string, ResolvedLib>
12
+ };
13
+
8
14
  export default class Signature {
9
15
  private components: Record<string, ComponentConstructor> = {};
10
16
  private refs: Record<string, Ref> = {};
17
+ private libs: Record<string, LibMeta> = {};
11
18
 
12
19
  constructor() {
13
20
  }
@@ -15,13 +22,89 @@ export default class Signature {
15
22
  /**
16
23
  * Adds a component to the signature.
17
24
  * @param {ComponentConstructor} component The component to add.
25
+ * @param {string} name Optional name for the component. If not provided, uses the component's name property.
18
26
  */
19
- public add(component: ComponentConstructor): void {
20
- if (this.components[component.name]) {
21
- console.warn(new Error(`Component with name ${component.name} already exists.`));
27
+ public add(component: ComponentConstructor, name?: string): void {
28
+ const key = typeof name === "string" ? name : component.name;
29
+
30
+ if (this.components[key]) {
31
+ console.warn(new Error(`Component with name ${key} already exists.`));
22
32
  }
23
33
 
24
- this.components[component.name] = component;
34
+ this.components[key] = component;
35
+ }
36
+
37
+ /**
38
+ * Registers a library in the signature.
39
+ * @import {Library} from "./Library.js";
40
+ * @param {Library} library The library to register.
41
+ * @param {string[]} exclude Optional array of component names to exclude from the library registration.
42
+ */
43
+ public register(library: Library, ...exclude: string[]): void {
44
+ if (this.libs[library.name]) {
45
+ console.warn(new Error(`Library with name ${library.name} already exists.`));
46
+ }
47
+
48
+ const components: Array<{
49
+ component: ComponentConstructor,
50
+ name: string
51
+ }> = library.list().filter(com => !(com.name in exclude));
52
+
53
+ this.libs[library.name] = {
54
+ name: library.name,
55
+ version: library.version,
56
+ author: library.author,
57
+ components: components.map(com => com.name),
58
+ dependencies: library.libs
59
+ };
60
+
61
+ for (const com of components) {
62
+ this.add(com.component, `${library.name}-${com.name}`);
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Returns a library.
68
+ * @param {string} name The name of the library.
69
+ * @return {LibMeta}
70
+ */
71
+ public lib(name: string): LibMeta | undefined {
72
+ return this.libs[name];
73
+ }
74
+
75
+ /**
76
+ * Returns a formatted object of all libraries in the signature.
77
+ * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
78
+ */
79
+ public libraries(): Record<string, ResolvedLib> {
80
+ const formatKey = (lib: LibMeta): string => {
81
+ let key = lib.name;
82
+
83
+ if (lib.version) key += `@${lib.version}`;
84
+ if (lib.author) key += `#${lib.author}`;
85
+
86
+ return key;
87
+ };
88
+
89
+ const resolve = (libs: Record<string, LibMeta>, visited = new Set<string>()): Record<string, ResolvedLib> => {
90
+ const result: Record<string, ResolvedLib> = {};
91
+
92
+ for (const [_, lib] of Object.entries(libs)) {
93
+ const key = formatKey(lib);
94
+
95
+ if (visited.has(key)) continue;
96
+ visited.add(key);
97
+
98
+ result[key] = {
99
+ components: lib.components,
100
+ dependencies: resolve(lib.dependencies, visited)
101
+ };
102
+ }
103
+
104
+ return result;
105
+ };
106
+
107
+ return resolve(this.libs);
25
108
  }
26
109
 
27
110
  /**
package/src/index.ts CHANGED
@@ -6,4 +6,5 @@ export default function (): Signature {
6
6
 
7
7
  export {default as Signature} from './Signature.js';
8
8
  export {default as Component} from './Component.js';
9
- export {default as Prop} from './Prop.js';
9
+ export {default as Prop} from './Prop.js';
10
+ export {default as Library} from './Library.js';