@avstantso/utils-names-tree 1.2.1 → 1.3.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/README.md CHANGED
@@ -40,9 +40,9 @@ import '@avstantso/utils-names-tree';
40
40
 
41
41
  // Use utilities from the global namespace
42
42
  const formTree = AVStantso.NamesTree.Names({
43
- form: '',
44
- label: '',
45
- placeholder: ''
43
+ form: 1,
44
+ label: 1,
45
+ placeholder: 1
46
46
  });
47
47
  ```
48
48
 
@@ -55,9 +55,9 @@ import { NamesTree } from '@avstantso/utils-names-tree';
55
55
 
56
56
  // Use imported NamesTree namespace
57
57
  const formTree = NamesTree.Names({
58
- form: '',
59
- label: '',
60
- placeholder: ''
58
+ form: 1,
59
+ label: 1,
60
+ placeholder: 1
61
61
  });
62
62
 
63
63
  console.log(`${formTree.label}`); // 'label'
@@ -94,11 +94,11 @@ import { NamesTree } from '@avstantso/utils-names-tree';
94
94
 
95
95
  const data = {
96
96
  user: {
97
- profile: '',
98
- settings: ''
97
+ profile: 1,
98
+ settings: 1
99
99
  },
100
100
  admin: {
101
- dashboard: ''
101
+ dashboard: 1
102
102
  }
103
103
  };
104
104
 
@@ -116,37 +116,45 @@ console.log(tree.user.profile._path); // 'user/profile'
116
116
 
117
117
  ## Built-in Kinds
118
118
 
119
- NamesTree comes with several predefined kind methods that determine how tree paths are formatted.
120
-
121
- ### `name`
122
-
123
- Returns the last segment of the path (leaf node name).
124
-
125
- **Example:** `['user', 'profile']` becomes `'profile'`
126
-
127
- ### `path`
128
-
129
- Returns the full path with segments joined by `/`.
130
-
131
- **Example:** `['user', 'profile']` becomes `'user/profile'`
132
-
133
- ### `url`
134
-
135
- Returns the full path as a URL with leading `/`.
136
-
137
- **Example:** `['user', 'profile']` becomes `'/user/profile'`
138
-
139
- ### `i18n`
140
-
141
- Returns the full path with segments joined by `.` (dot notation).
142
-
143
- **Example:** `['schemas', 'login', 'required']` becomes `'schemas.login.required'`
144
-
145
- ### `domain`
146
-
147
- Returns the full path with segments joined by `.` (same as i18n).
148
-
149
- **Example:** `['api', 'v1', 'users']` becomes `'api.v1.users'`
119
+ NamesTree comes with 20+ predefined kind methods that determine how tree paths are formatted.
120
+
121
+ ### Basic Kinds
122
+
123
+ | Kind | Separator | Example Input | Example Output |
124
+ |------|-----------|---------------|----------------|
125
+ | `name` | - | `['user', 'profile']` | `'profile'` |
126
+ | `slash` / `path` | `/` | `['user', 'profile']` | `'user/profile'` |
127
+ | `backslash` | `\` | `['user', 'profile']` | `'user\profile'` |
128
+ | `dot` / `i18n` / `domain` | `.` | `['schemas', 'login']` | `'schemas.login'` |
129
+ | `dash` | `-` | `['btn', 'primary']` | `'btn-primary'` |
130
+ | `underscore` / `snake` | `_` | `['user', 'name']` | `'user_name'` |
131
+ | `doubleColon` / `namespace` | `::` | `['std', 'vector']` | `'std::vector'` |
132
+ | `colon` | `:` | `['a', 'b']` | `'a:b'` |
133
+ | `arrow` | `->` | `['a', 'b']` | `'a->b'` |
134
+ | `amp` | `&` | `['a', 'b']` | `'a&b'` |
135
+ | `hash` | `#` | `['a', 'b']` | `'a#b'` |
136
+ | `comma` / `csv` | `,` | `['a', 'b']` | `'a,b'` |
137
+ | `semicolon` | `;` | `['a', 'b']` | `'a;b'` |
138
+ | `space` / `title` | ` ` | `['hello', 'world']` | `'hello world'` |
139
+ | `pipe` | `\|` | `['a', 'b']` | `'a\|b'` |
140
+
141
+ ### Derived Kinds (with prefixes/transformations)
142
+
143
+ | Kind | Description | Example Input | Example Output |
144
+ |------|-------------|---------------|----------------|
145
+ | `url` | URL with leading `/` | `['user', 'profile']` | `'/user/profile'` |
146
+ | `query` | Query string | `['a', 'b']` | `'?a&b'` |
147
+ | `longArg` | CLI long argument | `['dry', 'run']` | `'--dry-run'` |
148
+ | `shortArg` | CLI short argument | `['v']` | `'-v'` |
149
+ | `envVar` | Environment variable | `['db', 'host']` | `'DB_HOST'` |
150
+ | `cssClass` | CSS class selector | `['btn', 'primary']` | `'.btn-primary'` |
151
+ | `cssId` | CSS ID selector | `['main', 'content']` | `'#main-content'` |
152
+ | `anchor` | HTML anchor | `['section']` | `'#section'` |
153
+ | `scoped` | Scoped package | `['org', 'pkg']` | `'@org/pkg'` |
154
+ | `param` | Route parameter (last) | `['users', 'id']` | `':id'` |
155
+ | `params` | Route parameters (all) | `['users', 'id']` | `':users/:id'` |
156
+ | `arg` | Template arg (last) | `['users', 'id']` | `'{id}'` |
157
+ | `args` | Template args (all) | `['users', 'id']` | `'{users}/{id}'` |
150
158
 
151
159
  ---
152
160
 
@@ -176,9 +184,9 @@ NamesTree.Names<T>(
176
184
  import { NamesTree } from '@avstantso/utils-names-tree';
177
185
 
178
186
  const form = {
179
- form: '',
180
- label: '',
181
- placeholder: ''
187
+ form: 1,
188
+ label: 1,
189
+ placeholder: 1
182
190
  };
183
191
 
184
192
  const formTree = NamesTree.Names(form);
@@ -197,12 +205,12 @@ console.log(formDict); // { form: 'form', label: 'label', placeholder: 'placehol
197
205
  import { NamesTree } from '@avstantso/utils-names-tree';
198
206
 
199
207
  const form = {
200
- form: '',
201
- label: '',
202
- placeholder: ''
208
+ form: 1,
209
+ label: 1,
210
+ placeholder: 1
203
211
  };
204
212
 
205
- const formTree = NamesTree.Names(form, { prefix: 'xxx-' });
213
+ const formTree = NamesTree.Names(form, { prefix: 'xxx-' } as const);
206
214
  const formDict = formTree.Name;
207
215
 
208
216
  console.log(formDict);
@@ -272,12 +280,12 @@ import { NamesTree } from '@avstantso/utils-names-tree';
272
280
  const validationKeys = NamesTree.I18ns({
273
281
  user: {
274
282
  email: {
275
- required: '',
276
- invalid: ''
283
+ required: 1,
284
+ invalid: 1
277
285
  },
278
286
  password: {
279
- required: '',
280
- tooShort: ''
287
+ required: 1,
288
+ tooShort: 1
281
289
  }
282
290
  }
283
291
  });
@@ -318,15 +326,15 @@ import { NamesTree } from '@avstantso/utils-names-tree';
318
326
 
319
327
  const Urls = {
320
328
  profile: {
321
- login: '',
322
- logout: '',
323
- settings: '',
324
- registration: '',
325
- reset: ''
329
+ login: 1,
330
+ logout: 1,
331
+ settings: 1,
332
+ registration: 1,
333
+ reset: 1
326
334
  },
327
335
  admin: {
328
- roles: '',
329
- users: ''
336
+ roles: 1,
337
+ users: 1
330
338
  }
331
339
  };
332
340
 
@@ -373,7 +381,7 @@ const Urls = { profile: { settings: '' } };
373
381
  const UrlsTree = NamesTree.Urls(Urls);
374
382
 
375
383
  // Get array of trees, one per kind
376
- const [NAMES, PATHS, URLS] = UrlsTree.splitted;
384
+ const [NAMES, PATHS, URLS] = UrlsTree.$splitted;
377
385
 
378
386
  console.log(`${NAMES.profile.settings}`); // 'settings'
379
387
  console.log(NAMES.profile.settings); // 'settings'
@@ -385,17 +393,48 @@ console.log(`${URLS.profile.settings}`); // '/profile/settings'
385
393
  console.log(URLS.profile.settings); // '/profile/settings'
386
394
  ```
387
395
 
396
+ **Using Root Alias:**
397
+ ```typescript
398
+ import { NamesTree } from '@avstantso/utils-names-tree';
399
+
400
+ const Urls = { profile: { settings: '' } };
401
+ const UrlsTree = NamesTree.Urls(Urls, { rootAlias: 'Home' } as const);
402
+
403
+ // Access root via alias
404
+ console.log(`${UrlsTree.Home}`); // ''
405
+ console.log(`${UrlsTree.Url.Home}`); // '/'
406
+
407
+ // Splitted trees also have the alias
408
+ const [NAMES, PATHS, URLS] = UrlsTree.$splitted;
409
+ console.log(`${URLS.Home}`); // '/'
410
+ ```
411
+
412
+ **Using Default Kind:**
413
+ ```typescript
414
+ import { NamesTree } from '@avstantso/utils-names-tree';
415
+
416
+ const data = { profile: { settings: '' } };
417
+
418
+ // Default toString() uses first kind ('name')
419
+ const tree1 = NamesTree(data, 'name', 'path', 'url');
420
+ console.log(`${tree1.profile.settings}`); // 'settings'
421
+
422
+ // Override default toString() to use 'url' kind
423
+ const tree2 = NamesTree(data, { defaultKind: 'url' } as const, 'name', 'path', 'url');
424
+ console.log(`${tree2.profile.settings}`); // '/profile/settings'
425
+ ```
426
+
388
427
  ---
389
428
 
390
429
  ## Advanced Features
391
430
 
392
431
  ### Tree Merging
393
432
 
394
- Combine multiple data sources into a single tree, useful for adding route handlers to URL structures.
433
+ Combine multiple data sources into a single tree. Can be used for extending basic trees or adding route handlers to URL structures.
395
434
 
396
435
  **Method:**
397
436
  ```typescript
398
- tree.merge<M>(data: M): NamesTree<T & M, Kinds>
437
+ tree.$merge<M>(data: M): NamesTree<T & M, Kinds>
399
438
  ```
400
439
 
401
440
  **Parameters:**
@@ -409,8 +448,8 @@ import { NamesTree } from '@avstantso/utils-names-tree';
409
448
 
410
449
  const Urls = {
411
450
  profile: {
412
- login: '',
413
- settings: ''
451
+ login: 1,
452
+ settings: 1
414
453
  }
415
454
  };
416
455
 
@@ -421,7 +460,7 @@ function profile() {
421
460
  return 123;
422
461
  }
423
462
 
424
- const merged = UrlsTree.merge({ profile });
463
+ const merged = UrlsTree.$merge({ profile });
425
464
 
426
465
  // Call the function
427
466
  console.log(merged.profile()); // 123
@@ -439,9 +478,9 @@ import express from 'express';
439
478
  const routes = {
440
479
  api: {
441
480
  users: {
442
- list: '',
443
- create: '',
444
- detail: ''
481
+ list: 1,
482
+ create: 1,
483
+ detail: 1
445
484
  }
446
485
  }
447
486
  };
@@ -456,7 +495,7 @@ const handlers = {
456
495
  }
457
496
  };
458
497
 
459
- const RoutesTree = NamesTree.Urls(routes).merge(handlers);
498
+ const RoutesTree = NamesTree.Urls(routes).$merge(handlers);
460
499
 
461
500
  const app = express();
462
501
 
@@ -476,7 +515,7 @@ Extract individual trees for each kind from a multi-kind tree.
476
515
 
477
516
  **Property:**
478
517
  ```typescript
479
- tree.splitted: Array<NamesTree<T, [Kind]>>
518
+ tree.$splitted: Array<NamesTree<T, [Kind]>>
480
519
  ```
481
520
 
482
521
  **Returns:** Array of single-kind trees in the order kinds were specified
@@ -485,10 +524,10 @@ tree.splitted: Array<NamesTree<T, [Kind]>>
485
524
  ```typescript
486
525
  import { NamesTree } from '@avstantso/utils-names-tree';
487
526
 
488
- const data = { user: { profile: '' } };
527
+ const data = { user: { profile: 1 } };
489
528
  const tree = NamesTree.Urls(data);
490
529
 
491
- const [names, paths, urls] = tree.splitted;
530
+ const [names, paths, urls] = tree.$splitted;
492
531
 
493
532
  console.log(`${names.user.profile}`); // 'profile'
494
533
  console.log(`${paths.user.profile}`); // 'user/profile'
@@ -514,34 +553,50 @@ NamesTree._RegKinds(kinds: Record<string, Kinds.Method>): void
514
553
  type Method = (path: string[], options?: Options) => string
515
554
  ```
516
555
 
556
+ **TypeScript Support:**
557
+
558
+ For proper type inference with custom kinds, extend the `KindsMeta` interface:
559
+
560
+ ```typescript
561
+ declare global {
562
+ namespace AVStantso {
563
+ namespace NamesTree {
564
+ interface KindsMeta {
565
+ bem: '__'; // separator or KindMeta object
566
+ }
567
+ }
568
+ }
569
+ }
570
+ ```
571
+
517
572
  **Example:**
518
573
  ```typescript
519
574
  import { NamesTree } from '@avstantso/utils-names-tree';
520
575
 
521
- // Register custom kind for CSS class names
576
+ // Register custom kind for BEM-style CSS (block__element)
522
577
  NamesTree._RegKinds({
523
- cssClass: (path, options) => {
578
+ bem: (path, options) => {
524
579
  const { prefix = '' } = options || {};
525
- return `${prefix}${path.join('__')}`; // BEM-style
580
+ return `${prefix}${path.join('__')}`;
526
581
  }
527
582
  });
528
583
 
529
584
  // Use custom kind
530
585
  const components = {
531
586
  button: {
532
- primary: '',
533
- secondary: ''
587
+ icon: 1,
588
+ label: 1
534
589
  }
535
590
  };
536
591
 
537
- const cssTree = NamesTree(components, 'cssClass');
592
+ const bemTree = NamesTree(components, 'bem');
538
593
 
539
- console.log(`${cssTree.button.primary}`); // 'button__primary'
540
- console.log(`${cssTree.button.secondary}`); // 'button__secondary'
594
+ console.log(`${bemTree.button.icon}`); // 'button__icon'
595
+ console.log(`${bemTree.button.label}`); // 'button__label'
541
596
 
542
597
  // With prefix
543
- const prefixedTree = NamesTree(components, { prefix: 'app-' }, 'cssClass');
544
- console.log(`${prefixedTree.button.primary}`); // 'app-button__primary'
598
+ const prefixedTree = NamesTree(components, { prefix: 'app-' } as const, 'bem');
599
+ console.log(`${prefixedTree.button.icon}`); // 'app-button__icon'
545
600
  ```
546
601
 
547
602
  **Example: GraphQL Field Paths**
@@ -556,9 +611,9 @@ NamesTree._RegKinds({
556
611
 
557
612
  const schema = {
558
613
  user: {
559
- firstName: '',
560
- lastName: '',
561
- emailAddress: ''
614
+ firstName: 1,
615
+ lastName: 1,
616
+ emailAddress: 1
562
617
  }
563
618
  };
564
619
 
@@ -578,14 +633,37 @@ Union type for valid tree source data.
578
633
 
579
634
  **Type Definition:**
580
635
  ```typescript
581
- type Source = Source.Root | string
636
+ type Source = TS.Type.Builtin // string | number | boolean | null | undefined | symbol | bigint
582
637
 
583
638
  namespace Source {
584
639
  type Root = object | Function
585
640
  }
586
641
  ```
587
642
 
588
- **Description:** Tree sources can be nested objects, functions, or string values at leaf nodes.
643
+ **Description:**
644
+ - `Source` — any built-in primitive type for leaf nodes (values are ignored)
645
+ - `Source.Root` — nested objects or functions for tree structure
646
+
647
+ Leaf node values are ignored — only the object structure (keys) matters for generating paths.
648
+
649
+ **Flexible Leaf Values:**
650
+ ```typescript
651
+ // All of these are equivalent - leaf values are ignored
652
+ const data1 = { user: { name: '' } };
653
+ const data2 = { user: { name: 1 } };
654
+ const data3 = { user: { name: true } };
655
+ const data4 = { user: { name: null } };
656
+
657
+ // Using numbers is shorter to type
658
+ const form = {
659
+ form: 1,
660
+ label: 1,
661
+ placeholder: 1
662
+ };
663
+
664
+ const tree = NamesTree.Names(form);
665
+ console.log(tree.Name); // { form: 'form', label: 'label', placeholder: 'placeholder' }
666
+ ```
589
667
 
590
668
  ---
591
669
 
@@ -610,11 +688,15 @@ Configuration options for tree creation.
610
688
  ```typescript
611
689
  interface Options {
612
690
  prefix?: string;
691
+ rootAlias?: string;
692
+ defaultKind?: Kind;
613
693
  }
614
694
  ```
615
695
 
616
696
  **Properties:**
617
697
  - `prefix` - Optional string to prepend to all generated values (default: `''`)
698
+ - `rootAlias` - Optional alias for tree root as additional property (e.g., `'Home'` for URL trees). The alias is `enumerable: true`, so it appears in `Object.keys()` and iterations
699
+ - `defaultKind` - Optional kind to use for default `toString()` output (defaults to first kind in tree)
618
700
 
619
701
  ---
620
702
 
@@ -626,17 +708,21 @@ Type-safe tree node structure.
626
708
  ```typescript
627
709
  type Node<
628
710
  T extends Source = Source,
711
+ O extends Options = Options,
629
712
  KDs extends readonly Kind[] = Kinds.All,
630
- S extends boolean = false
631
- > = NodeKinds<KDs> & Node.Data<T, KDs, S>
713
+ S extends boolean = false,
714
+ P extends TS.Keys = []
715
+ > = (S extends true ? unknown : _NodeKinds<O, KDs, P>) & Node.Data<T, O, KDs, S, P>
632
716
  ```
633
717
 
634
718
  **Type Parameters:**
635
719
  - `T` - Source data type
720
+ - `O` - Options type (for prefix inference)
636
721
  - `KDs` - Tuple of kinds available on this node
637
- - `S` - If true, allows string tail nodes (for splitted trees)
722
+ - `S` - If true, allows resolved string types for leaf nodes (for splitted trees)
723
+ - `P` - Path stack for compile-time kind resolution
638
724
 
639
- **Description:** Represents a tree node with properties for data access and kind-specific formatters.
725
+ **Description:** Represents a tree node with properties for data access and kind-specific formatters. The `P` parameter enables compile-time path tracking for precise type inference of kind accessors.
640
726
 
641
727
  ---
642
728
 
@@ -671,28 +757,56 @@ const urls = NamesTree.Urls(routeData);
671
757
  const urls = NamesTree(routeData, 'name', 'path', 'url');
672
758
  ```
673
759
 
674
- ### 2. Leverage Type Inference
760
+ ### 2. Use Short Leaf Values
761
+
762
+ Leaf node values are ignored — use `1` or any short value instead of empty strings for brevity.
763
+
764
+ ```typescript
765
+ // Verbose
766
+ const form1 = { name: '', email: '', password: '' };
767
+
768
+ // Concise - same result
769
+ const form2 = { name: 1, email: 1, password: 1 };
770
+
771
+ const tree = NamesTree.Names(form2);
772
+ console.log(tree.Name); // { name: 'name', email: 'email', password: 'password' }
773
+ ```
774
+
775
+ ### 3. Leverage Type Inference
675
776
 
676
- Let TypeScript infer types from your data structure for full type safety.
777
+ TypeScript automatically infers key names as literal types no `as const` needed for data structures.
677
778
 
678
779
  ```typescript
679
780
  const routes = {
680
- admin: { users: '', roles: '' }
681
- } as const; // Use 'as const' for literal types
781
+ admin: { users: 1, roles: 1 }
782
+ };
682
783
 
683
784
  const tree = NamesTree.Urls(routes);
684
785
 
685
786
  // TypeScript knows these properties exist
686
787
  tree.admin.users; // OK
687
788
  tree.admin.posts; // Error: Property 'posts' does not exist
789
+
790
+ // Kind accessors have precise literal types
791
+ tree.admin.users._url; // Type: '/admin/users'
688
792
  ```
689
793
 
690
- ### 3. Use String Coercion for Output
794
+ **Note:** Use `as const` for options when you need literal types:
795
+ ```typescript
796
+ // Options need 'as const' for precise type inference
797
+ const tree = NamesTree.Urls(data, { rootAlias: 'Home' } as const);
798
+ tree.Home; // Property 'Home' exists
799
+
800
+ const form = NamesTree.Names(data, { prefix: 'app-' } as const);
801
+ form.Name.user; // Type: 'app-user'
802
+ ```
803
+
804
+ ### 4. Use String Coercion for Output
691
805
 
692
806
  Trees automatically convert to strings via `toString()` method.
693
807
 
694
808
  ```typescript
695
- const tree = NamesTree.Names({ user: '' });
809
+ const tree = NamesTree.Names({ user: 1 });
696
810
 
697
811
  // Explicit string coercion
698
812
  console.log(`${tree.user}`); // 'user'
@@ -701,7 +815,7 @@ console.log(`${tree.user}`); // 'user'
701
815
  const url = `/api/${tree.user}`; // '/api/user'
702
816
  ```
703
817
 
704
- ### 4. Centralize Route Definitions
818
+ ### 5. Centralize Route Definitions
705
819
 
706
820
  Define routes once and derive all variations from a single source.
707
821
 
@@ -709,15 +823,15 @@ Define routes once and derive all variations from a single source.
709
823
  // routes.ts
710
824
  export const RouteStructure = {
711
825
  auth: {
712
- login: '',
713
- logout: '',
714
- register: ''
826
+ login: 1,
827
+ logout: 1,
828
+ register: 1
715
829
  },
716
830
  dashboard: {
717
- home: '',
718
- analytics: ''
831
+ home: 1,
832
+ analytics: 1
719
833
  }
720
- } as const;
834
+ };
721
835
 
722
836
  export const Routes = NamesTree.Urls(RouteStructure);
723
837
 
@@ -734,17 +848,17 @@ router.get(`${Routes.Url.auth.login}`, loginHandler);
734
848
  fetch(`${Routes.Path.dashboard.home}`);
735
849
  ```
736
850
 
737
- ### 5. Combine with Enums for Constants
851
+ ### 6. Combine with Enums for Constants
738
852
 
739
853
  Use trees for structured constants that need multiple representations.
740
854
 
741
855
  ```typescript
742
856
  const StatusStructure = {
743
- pending: '',
744
- active: '',
745
- completed: '',
746
- archived: ''
747
- } as const;
857
+ pending: 1,
858
+ active: 1,
859
+ completed: 1,
860
+ archived: 1
861
+ };
748
862
 
749
863
  const StatusTree = NamesTree.Names(StatusStructure);
750
864
 
@@ -768,17 +882,17 @@ import { NamesTree } from '@avstantso/utils-names-tree';
768
882
 
769
883
  const AppRoutes = NamesTree.Urls({
770
884
  public: {
771
- home: '',
772
- about: '',
773
- contact: ''
885
+ home: 1,
886
+ about: 1,
887
+ contact: 1
774
888
  },
775
889
  auth: {
776
- login: '',
777
- signup: ''
890
+ login: 1,
891
+ signup: 1
778
892
  },
779
893
  dashboard: {
780
- overview: '',
781
- settings: ''
894
+ overview: 1,
895
+ settings: 1
782
896
  }
783
897
  });
784
898
 
@@ -798,16 +912,16 @@ import { NamesTree } from '@avstantso/utils-names-tree';
798
912
  const i18nKeys = NamesTree.I18ns({
799
913
  common: {
800
914
  buttons: {
801
- save: '',
802
- cancel: '',
803
- delete: ''
915
+ save: 1,
916
+ cancel: 1,
917
+ delete: 1
804
918
  }
805
919
  },
806
920
  errors: {
807
921
  validation: {
808
- required: '',
809
- email: '',
810
- minLength: ''
922
+ required: 1,
923
+ email: 1,
924
+ minLength: 1
811
925
  }
812
926
  }
813
927
  });
@@ -823,11 +937,11 @@ t(`${i18nKeys.errors.validation.required}`); // 'errors.validation.required'
823
937
  import { NamesTree } from '@avstantso/utils-names-tree';
824
938
 
825
939
  const styles = NamesTree.Names({
826
- button: '',
827
- input: '',
828
- label: '',
829
- container: ''
830
- }, { prefix: 'app-' });
940
+ button: 1,
941
+ input: 1,
942
+ label: 1,
943
+ container: 1
944
+ }, { prefix: 'app-' } as const);
831
945
 
832
946
  // Use in JSX
833
947
  <button className={styles.Name.button}>Click Me</button>
@@ -844,13 +958,13 @@ import { NamesTree } from '@avstantso/utils-names-tree';
844
958
 
845
959
  const FormFields = NamesTree.Names({
846
960
  user: {
847
- firstName: '',
848
- lastName: '',
849
- email: '',
961
+ firstName: 1,
962
+ lastName: 1,
963
+ email: 1,
850
964
  address: {
851
- street: '',
852
- city: '',
853
- zipCode: ''
965
+ street: 1,
966
+ city: 1,
967
+ zipCode: 1
854
968
  }
855
969
  }
856
970
  });
@@ -861,6 +975,68 @@ const FormFields = NamesTree.Names({
861
975
  <input name={FormFields.Name.user.address.city} />
862
976
  ```
863
977
 
978
+ ### Environment Variables
979
+
980
+ ```typescript
981
+ import { NamesTree } from '@avstantso/utils-names-tree';
982
+
983
+ const envVars = NamesTree({
984
+ db: {
985
+ host: 1,
986
+ port: 1,
987
+ name: 1
988
+ },
989
+ api: {
990
+ key: 1,
991
+ secret: 1
992
+ }
993
+ }, 'envVar');
994
+
995
+ console.log(envVars.db.host._envVar); // 'DB_HOST'
996
+ console.log(envVars.api.key._envVar); // 'API_KEY'
997
+ ```
998
+
999
+ ### CLI Arguments
1000
+
1001
+ ```typescript
1002
+ import { NamesTree } from '@avstantso/utils-names-tree';
1003
+
1004
+ const cliArgs = NamesTree({
1005
+ verbose: 1,
1006
+ dry: { run: 1 },
1007
+ output: { file: 1 }
1008
+ }, 'longArg', 'shortArg');
1009
+
1010
+ console.log(cliArgs.verbose._longArg); // '--verbose'
1011
+ console.log(cliArgs.verbose._shortArg); // '-verbose'
1012
+ console.log(cliArgs.dry.run._longArg); // '--dry-run'
1013
+ ```
1014
+
1015
+ ### Route Parameters
1016
+
1017
+ ```typescript
1018
+ import { NamesTree } from '@avstantso/utils-names-tree';
1019
+
1020
+ const apiRoutes = NamesTree({
1021
+ users: {
1022
+ id: {
1023
+ posts: {
1024
+ postId: 1
1025
+ }
1026
+ }
1027
+ }
1028
+ }, 'url', 'params', 'args');
1029
+
1030
+ // Express-style route
1031
+ console.log(apiRoutes.users.id._params); // ':users/:id'
1032
+
1033
+ // OpenAPI-style route
1034
+ console.log(apiRoutes.users.id.posts.postId._args); // '{users}/{id}/{posts}/{postId}'
1035
+
1036
+ // Combined with url
1037
+ console.log(apiRoutes.users.id._url); // '/users/id'
1038
+ ```
1039
+
864
1040
  ---
865
1041
 
866
1042
  ## Requirements