posthtml-component 1.0.0-beta.8 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "posthtml-component",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0",
4
4
  "description": "PostHTML Components Blade-like with slots, attributes as props and custom tag",
5
5
  "license": "MIT",
6
6
  "repository": "thewebartisan7/posthtml-components",
@@ -13,7 +13,7 @@
13
13
  "version": "conventional-changelog -i changelog.md -s -r 0 && git add changelog.md",
14
14
  "test": "c8 ava",
15
15
  "pretest": "clinton && xo",
16
- "build-examples": "node ./examples"
16
+ "build": "node ./docs-src"
17
17
  },
18
18
  "keywords": [
19
19
  "posthtml",
package/readme.md CHANGED
@@ -17,10 +17,10 @@ npm i -D posthtml-component
17
17
  ## Introduction
18
18
 
19
19
  This PostHTML plugin provides an HTML-friendly syntax for write components in your templates.
20
- If you are familiar with Blade, you will find similar syntax as this plugin was inspired by it.
20
+ If you are familiar with Blade, React, Vue or similar, you will find familiar syntax as this plugin is inspired by them.
21
21
  See below a basic example, as code is worth a thousand words.
22
22
 
23
- > This plugin is still in early stage of development and the current API may change.
23
+ **See also the first [PostHTML Bootstrap UI](https://github.com/thewebartisan7/posthtml-bootstrap-ui) using this plugin and check also the [starter template here](https://github.com/thewebartisan7/posthtml-bootstrap-ui-starter).**
24
24
 
25
25
  ## Basic example
26
26
 
@@ -69,13 +69,11 @@ Result:
69
69
  </html>
70
70
  ```
71
71
 
72
- You may ask yourself many questions about this basic examples, and you will find most if not all answers in this readme. In case is missing something, feel free to ask via discussions.
72
+ You may notice that the `src/button.html` component has a `type` and `class` attribute, and when we use the component in `src/index.html` we pass `type` and `class` attribute.
73
+ The result is that `type` is override, and `class` is merged.
73
74
 
74
- But I want to explain a few things now.
75
-
76
- First you may notice that our `src/button.html` component has a `type` and `class` attribute, and when we use the component in `src/index.html` we add type and class attribute. The result is that `type` is override, and `class` is merged.
77
-
78
- By default `class` and `style` attributes are merged, while all others attribute are override. You can also override class and style attribute by prepending `override:` to the class attribute. Example:
75
+ By default `class` and `style` attributes are merged, while all others attribute are override.
76
+ You can also override `class` and `style` attributes by prepending `override:` to the class attribute. Example:
79
77
 
80
78
  ```html
81
79
  <x-button override:class="btn-custom">Submit</x-button>
@@ -84,41 +82,50 @@ By default `class` and `style` attributes are merged, while all others attribute
84
82
  <button type="button" class="btn-custom">Submit</button>
85
83
  ```
86
84
 
87
- All attributes you pass to the component will be added to the first root element of your component, and only if they are not defined as `props` via `<script props>`. More details on this later.
88
-
89
- Second you may notice a `<yield>` tag.
85
+ All attributes you pass to the component will be added to the first node of your component or to the node with an attribute names `attributes`,
86
+ and only if they are not defined as `props` via `<script props>` or if they are not in the following file
87
+ [valid-attributes.js](https://github.com/thewebartisan7/posthtml-components/blob/main/src/valid-attributes.js).
88
+ You can also manage valid attributes via options.
89
+ More details on this in [Attributes](#attributes) section.
90
90
 
91
- This is where your content will be injected.
91
+ The `<yield>` tag is where your content will be injected.
92
+ In next section you can find all available options and then examples for each feature.
92
93
 
93
- In next section you can find all available options and then more examples.
94
-
95
- See also the `examples` folder. You can run `npm run build-examples` to compile them.
94
+ See also the `docs-src` folder where you can find more examples.
95
+ You can run `npm run build` to compile them.
96
96
 
97
97
  ## Options
98
98
 
99
- | Option | Default | Description |
100
- |:----------------------:|:----------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------|
101
- | **root** | `'./'` | String value as root path for components lookup. |
102
- | **folders** | `['']` | Array of additional multi folders path from `options.root` or any defined namespaces root, fallback or custom. |
103
- | **tagPrefix** | `x-` | String for tag prefix. The plugin will use RegExp with this string. |
104
- | **tag** | `false` | String or boolean value for component tag. Use this with `options.attribute`. Boolean only false. |
105
- | **attribute** | `src` | String value for component attribute for set path. |
106
- | **namespaces** | `[]` | Array of namespace's root path, fallback path and custom path for override. |
107
- | **namespaceSeparator** | `::` | String value for namespace separator to be used with tag name. Example `<x-namespace::button>` |
108
- | **fileExtension** | `html` | String value for file extension of the components used for retrieve x-tag file. |
109
- | **yield** | `yield` | String value for `<yield>` tag name. Where main content of component is injected. |
110
- | **slot** | `slot` | String value for `<slot>` tag name. Used with RegExp by appending `:` (example `<slot:slot-name>`). |
111
- | **fill** | `fill` | String value for `<fill>` tag name. Used with RegExp by appending `:` (example `<fill:slot-name>`). |
112
- | **slotSeparator** | `:` | String value used for separate `<slot>` and `<fill>` tag from their names. |
113
- | **push** | `push` | String value for `<push>` tag name. |
114
- | **stack** | `stack` | String value for `<stack>` tag name. |
115
- | **localsAttr** | `props` | String value used in `<script props>` parsed by the plugin to retrieve locals in the components. |
116
- | **expressions** | `{}` | Object to configure `posthtml-expressions`. You can pre-set locals or customize the delimiters for example. |
117
- | **plugins** | `[]` | PostHTML plugins to apply for every parsed components. |
118
- | **matcher** | `[{tag: options.tagPrefix}]` | Array of object used to match the tags. |
119
- | **attrsParserRules** | `{}` | Additional rules for attributes parser plugin. |
120
- | **strict** | `true` | Boolean value for enable or disable throw an exception. |
121
- | **mergeCustomizer** | `function` | Function callback passed to lodash `mergeWith` for attribute `locals` and `merge:attribute`. By default it's used to concat array. |
99
+ | Option | Default | Description |
100
+ |:------------------------:|:---------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------|
101
+ | **root** | `'./'` | String value as root path for components lookup. |
102
+ | **folders** | `['']` | Array of additional multi folders path from `options.root` or any defined namespaces root, fallback or custom. |
103
+ | **tagPrefix** | `x-` | String for tag prefix. The plugin will use RegExp with this string. |
104
+ | **tag** | `false` | String or boolean value for component tag. Use this with `options.attribute`. Boolean only false. |
105
+ | **attribute** | `src` | String value for component attribute for set path. |
106
+ | **namespaces** | `[]` | Array of namespace's root path, fallback path and custom path for override. |
107
+ | **namespaceSeparator** | `::` | String value for namespace separator to be used with tag name. Example `<x-namespace::button>` |
108
+ | **fileExtension** | `html` | String value for file extension of the components used for retrieve x-tag file. |
109
+ | **yield** | `yield` | String value for `<yield>` tag name. Where main content of component is injected. |
110
+ | **slot** | `slot` | String value for `<slot>` tag name. Used with RegExp by appending `:` (example `<slot:slot-name>`). |
111
+ | **fill** | `fill` | String value for `<fill>` tag name. Used with RegExp by appending `:` (example `<fill:slot-name>`). |
112
+ | **slotSeparator** | `:` | String value used for separate `<slot>` and `<fill>` tag from their names. |
113
+ | **push** | `push` | String value for `<push>` tag name. |
114
+ | **stack** | `stack` | String value for `<stack>` tag name. |
115
+ | **propsScriptAttribute** | `props` | String value used as attribute in `<script props>` parsed by the plugin to retrieve props of the component. |
116
+ | **propsContext** | `props` | String value used as object name inside the script to process process before passed to the component. |
117
+ | **propsAttribute** | `props` | String value for props attribute to define props as JSON. |
118
+ | **propsSlot** | `props` | String value used to retrieve the props passed to slot via `$slots.slotName.props`. |
119
+ | **expressions** | `{}` | Object to configure `posthtml-expressions`. You can pre-set locals or customize the delimiters for example. |
120
+ | **plugins** | `[]` | PostHTML plugins to apply for every parsed components. |
121
+ | **matcher** | `[{tag: options.tagPrefix}]` | Array of object used to match the tags. |
122
+ | **attrsParserRules** | `{}` | Additional rules for attributes parser plugin. |
123
+ | **strict** | `true` | Boolean value for enable or disable throw an exception. |
124
+ | **mergeCustomizer** | `function` | Function callback passed to lodash `mergeWith` for merge `options.expressions.locals` and props passed via attribute `props`. |
125
+ | **utilities** | `{merge: _.mergeWith, template: _.template}` | Object of utilities methods to be passed to `<script props>`. By default lodash `mergeWith` and `template`. |
126
+ | **elementAttributes** | `{}` | An object with tag name and a function modifier of valid-attributes.js. |
127
+ | **safelistAttributes** | `['data-*']` | An array of attributes name to be added to default valid attributes. |
128
+ | **blacklistAttributes** | `[]` | An array of attributes name to be removed from default valid attributes. |
122
129
 
123
130
  ## Features
124
131
 
@@ -213,7 +220,7 @@ Please see below example to understand better.
213
220
 
214
221
  You have full control where to place your components. Once you set the base root path of your components, you can then set multiple folders.
215
222
  For example let's suppose your main root is `./src` and then you have several folders where you have your components, for example `./src/components` and `./src/layouts`.
216
- You can setup the plugin like below:
223
+ You can set up the plugin like below:
217
224
 
218
225
  ```js
219
226
  // index.js
@@ -229,7 +236,7 @@ require('posthtml')(require('posthtml-components')(options))
229
236
 
230
237
  ### Namespaces
231
238
 
232
- With namespaces you can define a top level root path to your components like shown in below example.
239
+ With namespaces, you can define a top level root path to your components like shown in below example.
233
240
  It can be useful for handle custom theme, where you define a specific top level root, with fallback root when component it's not found,
234
241
  and a custom root for override, something like a child theme.
235
242
 
@@ -346,7 +353,7 @@ Result:
346
353
  </div>
347
354
  ```
348
355
 
349
- By default the content is replaced, but you can also prepend or append the content, or keep the default content by not filling the slot.
356
+ By default, the content is replaced, but you can also prepend or append the content, or keep the default content by not filling the slot.
350
357
 
351
358
  Add some default content in the component:
352
359
 
@@ -486,7 +493,7 @@ Example.
486
493
  </push>
487
494
  ```
488
495
 
489
- By default the content is pushed in the stack in the given order.
496
+ By default, the content is pushed in the stack in the given order.
490
497
  If you would like to prepend content onto the beginning of a stack, you should use the `prepend` attribute:
491
498
 
492
499
  ```html
@@ -505,7 +512,7 @@ If you would like to prepend content onto the beginning of a stack, you should u
505
512
 
506
513
  ### Props
507
514
 
508
- Behind the `props` there is powerful [posthtml-expressions](https://github.com/posthtml/posthtml-expressions) plugin, with feature to pass `props` (locals) via attributes, define default via `<script props>`, merge with default and use `<script props>` as computed.
515
+ Behind the `props` there is powerful [posthtml-expressions](https://github.com/posthtml/posthtml-expressions) plugin, with feature to pass `props` (locals) via attributes and manipulate them via `<script props>`.
509
516
 
510
517
  Let's see how it works with a few examples starting with a basic one.
511
518
 
@@ -515,7 +522,7 @@ Create the component:
515
522
  <!-- src/my-component.html -->
516
523
  <script props>
517
524
  module.exports = {
518
- prop: 'Default prop value'
525
+ prop: props.prop || 'Default prop value'
519
526
  }
520
527
  </script>
521
528
  <div>
@@ -553,11 +560,7 @@ The output will be:
553
560
  </div>
554
561
  ```
555
562
 
556
- If you don't add the props in `<script props>` inside your component, all props will be added as attributes to the first node of your component or to the node with attribute `attributes`.
557
- More details on this in the next section.
558
-
559
- So by default `<script props>` act as default value, like the `@props` you define with Laravel Blade.
560
- You can change this behaviour by prepending `computed` or `merge` to the attribute name like shown below.
563
+ In the `<script props>` you have access to passed props via object `props`, and you can add any logic you need inside it.
561
564
 
562
565
  Create the component:
563
566
 
@@ -565,9 +568,9 @@ Create the component:
565
568
  <!-- src/modal.html -->
566
569
  <script props>
567
570
  module.exports = {
568
- title: 'Default title', // This will be the default value
569
- size: locals.size ? `modal-${locals.size}` : '', // This will be a computed value, so it's always used
570
- items: ['first', 'second'] // This will be merged
571
+ title: props.title || 'Default title',
572
+ size: props.size ? `modal-${props.size}` : '',
573
+ items: Array.isArray(props.items) ? props.items.concat(['first', 'second']) : ['first', 'second']
571
574
  }
572
575
  </script>
573
576
  <div class="modal {{ size }}">
@@ -583,7 +586,7 @@ Create the component:
583
586
  Use:
584
587
 
585
588
  ```html
586
- <x-modal computed:size="xl" title="My modal title" merge:items='["third", "fourth"]' class="modal-custom"></x-modal>
589
+ <x-modal size="xl" title="My modal title" items='["third", "fourth"]' class="modal-custom"></x-modal>
587
590
  ```
588
591
 
589
592
  The output will be:
@@ -602,19 +605,89 @@ The output will be:
602
605
  </div>
603
606
  ```
604
607
 
605
- So the prop `size` is not override since we prepend `computed:` to the attribute, while the prop `title` is override.
606
- And the prop `items` is merged and not override.
607
- You can also notice how the `class` attribute is merged with `class` attribute of the first node. Let's see in next section more about this.
608
+ You can also notice how the `class` attribute is merged with `class` attribute of the first node. In the next section you will know more about this.
609
+
610
+ You can change how attributes are merged with global props defined via options by passing a callback function used by lodash method [mergeWith](https://lodash.com/docs/4.17.15#mergeWith).
611
+
612
+ By default, all props are scoped to the component, and are not available to nested components. You can however change this accordingly to your need.
613
+ Let's see below example.
614
+
615
+ Create a component:
616
+
617
+ ```html
618
+ <!-- src/child.html -->
619
+ <script props>
620
+ module.exports = {
621
+ prop: props.prop || 'Default prop value'
622
+ }
623
+ </script>
624
+ <div>
625
+ Prop in child: {{ prop }}
626
+ </div>
627
+ ```
628
+
629
+ Create another component that use the first one:
630
+
631
+
632
+ ```html
633
+ <!-- src/parent.html -->
634
+ <script props>
635
+ module.exports = {
636
+ prop: props.prop || 'Default prop value'
637
+ }
638
+ </script>
639
+ <div>
640
+ Prop in parent: {{ prop }}
641
+ <x-child></x-child>
642
+ </div>
643
+ ```
644
+
645
+ Use:
646
+
647
+ ```html
648
+ <x-parent prop="My prop"></x-parent>
649
+ ```
650
+
651
+ The output will be:
652
+
653
+ ```html
654
+ <div>
655
+ Prop in parent: My prop
656
+ <div>
657
+ Prop in child: Default prop value
658
+ </div>
659
+ </div>
660
+ ```
661
+
662
+ As you can see `prop` in `x-child` component are default value and not the one set via `x-parent`. Prepend `aware:` to the attribute name to pass the props to nested components.
663
+
664
+
665
+ ```html
666
+ <x-parent aware:prop="My prop"></x-parent>
667
+ ```
668
+
669
+ The output now will be:
608
670
 
609
- You can change how attributes are merged by passing via options a callback function used by lodash method [mergeWith](https://lodash.com/docs/4.17.15#mergeWith).
610
- By default, it's used to concat array.
671
+ ```html
672
+ <div>
673
+ Prop in parent: My prop
674
+ <div>
675
+ Prop in child: My prop
676
+ </div>
677
+ </div>
678
+ ```
611
679
 
612
680
  ### Attributes
613
681
 
614
- Your can pass any attributes to your components and this will be added to the first node of your component, or to the node with an attribute named `attributes`.
682
+ You can pass any attributes to your components and this will be added to the first node of your component,
683
+ or to the node with an attribute named `attributes`. If you are familiar with VueJS this is the same as so called
684
+ [fallthrough attribute](https://vuejs.org/guide/components/attrs.html), or with Laravel Blade is
685
+ [component-attributes](https://laravel.com/docs/10.x/blade#component-attributes).
686
+
615
687
  By default `class` and `style` are merged with existing `class` and `style` attribute.
616
688
  All others attributes are override by default.
617
- Only attribute not defined as `props` will be used.
689
+ Only attributes defined in [valid-attributes.js](https://github.com/thewebartisan7/posthtml-components/blob/main/src/valid-attributes.js)
690
+ or not defined as `props` in the `<script props>`.
618
691
 
619
692
  As already seen in basic example:
620
693
 
@@ -622,7 +695,7 @@ As already seen in basic example:
622
695
  <!-- src/button.html -->
623
696
  <script props>
624
697
  module.exports = {
625
- label: 'A button'
698
+ label: props.label || 'A button'
626
699
  }
627
700
  </script>
628
701
  <button type="button" class="btn">
@@ -646,8 +719,6 @@ Result:
646
719
 
647
720
  As you may notice the `label` attribute is not added as attribute, since it's defined as a `props`.
648
721
 
649
- If you are familiar with Laravel Blade, this is also how Blade handle this.
650
-
651
722
  As said early, `class` and `style` are merged by default, if you want to override them, just prepend `override:` to the attribute name:
652
723
 
653
724
  ```html
@@ -662,7 +733,7 @@ Result:
662
733
  <button type="submit" class="btn-custom">My button</button>
663
734
  ```
664
735
 
665
- If you want to use another node for add such attributes, then you can add the attribute `attributes` like shown below.
736
+ If you want to use another node and not the first one, then you can add the attribute `attributes` like shown below.
666
737
 
667
738
  ```html
668
739
  <!-- src/my-component.html -->
@@ -693,10 +764,57 @@ Result:
693
764
 
694
765
  You can add custom rules how attributes are parsed, as behind the scene it's used [posthtml-attrs-parser](https://github.com/posthtml/posthtml-attrs-parser) plugin.
695
766
 
767
+ ### Advanced attributes configurations
768
+
769
+ If default configurations for valid attributes are not right for you, then you can configure them as explained below.
770
+
771
+ ```js
772
+ // index.js
773
+ const { readFileSync, writeFileSync } = require('fs')
774
+
775
+ const posthtml = require('posthtml')
776
+ const components = require('posthtml-components')
777
+
778
+ const options = {
779
+ root: './src',
780
+
781
+ // Add attributes to specific tag or override defaults
782
+ elementAttributes: {
783
+ DIV: (defaultAttributes) => {
784
+ /* Add new one */
785
+ defaultAttributes.push('custom-attribute-name');
786
+
787
+ return defaultAttributes;
788
+ },
789
+ DIV: (defaultAttributes) => {
790
+ /* Override all */
791
+ defaultAttributes = ['custom-attribute-name', 'another-one'];
792
+
793
+ return defaultAttributes;
794
+ },
795
+ },
796
+
797
+ // Add attributes to all tags, use '*' as wildcard for attribute name that starts with
798
+ safelistAttributes: [
799
+ 'custom-attribute-name',
800
+ 'attribute-name-start-with-*'
801
+ ],
802
+
803
+ // Remove attributes from all tags that support it
804
+ blacklistAttributes: [
805
+ 'role'
806
+ ]
807
+ }
808
+
809
+ posthtml(components(options))
810
+ .process(readFileSync('src/index.html', 'utf8'))
811
+ .then((result) => writeFileSync('dist/index.html', result.html, 'utf8'))
812
+ ```
813
+
696
814
  ## Examples
697
815
 
698
- You can work with `<slot>` and `<fill>` or you can create component for each "block" of your component, and you can also support both of them.
699
- You can find an example of this inside `examples/components/modal`. Below is a short explanation about the both approach.
816
+ You can work with `<slot>` and `<fill>` or you can create component for each block of your component, and you can also support both of them.
817
+ You can find an example of this inside `docs-src/components/modal`. Below is a short explanation about the both approach.
700
818
 
701
819
  ### Using slots
702
820
 
@@ -855,7 +973,7 @@ You can also combine both way, and then use them with slots or with small compon
855
973
  </x-modal.body>
856
974
  </if>
857
975
  <if condition="$slots.footer?.filled">
858
- <x-modal.footer close="{{ $slots.footer?.locals.close }}">
976
+ <x-modal.footer close="{{ $slots.footer?.props.close }}">
859
977
  <slot:footer></slot:footer>
860
978
  </x-modal.footer>
861
979
  </if>
@@ -871,53 +989,9 @@ via `$slots` which has all the `props` passed via slot, and as well check if slo
871
989
 
872
990
  ## Migration
873
991
 
874
- If you are migrating from `posthtml-extend` and/or `posthtml-modules` then you can continue to keep them until you migrate all of your components.
875
- For continue to use current code with this plugin without changing it, see below examples. Any more updates on this will be added in this issue:
992
+ If you are migrating from `posthtml-extend` and/or `posthtml-modules` please to follow updates here:
876
993
  [posthtml-components/issues/16](https://github.com/thewebartisan7/posthtml-components/issues/16).
877
994
 
878
- ### PostHTML Include
879
-
880
- PostHTML Include plugin can work when passed via `options.plugins` like below example:
881
-
882
- ```js
883
- require("posthtml-component")({
884
- root: "./src",
885
- folders: ["components", "layouts"],
886
- plugins: [
887
- require("posthtml-include")({
888
- encoding: "utf8",
889
- root: "./src"
890
- }),
891
- ]
892
- })
893
- ```
894
-
895
- ### PostHTML Modules
896
-
897
- At the moment doesn't work when nested inside PostHTML Components plugin since it use `tree.match` and even trying with something like PostHTML Include is doing here https://github.com/posthtml/posthtml-include/blob/master/lib/index.js#L16 doesn't work. But a workaround is to use PostHTML Components custom tag and attributes like below:
898
-
899
- ```js
900
- require("posthtml-component")({
901
- root: "./src",
902
- folders: ["components", "layouts"],
903
- tag: 'module',
904
- attribute: 'href',
905
- yield: 'content',
906
- plugins: [
907
- require("posthtml-include")({
908
- encoding: "utf8",
909
- root: "./src/www/posthtml-templates/"
910
- }),
911
- ]
912
- })
913
- ```
914
-
915
- NOTE: If you change `<yield>` tag to `<content>` to support your existing code, then you need to use it always. Maybe you can just replace all `<content>` with `<yield>` and it should works fine.
916
-
917
- ### PostHTML Extends
918
-
919
- Not yet tested.
920
-
921
995
  ## Contributing
922
996
 
923
997
  See [PostHTML Guidelines](https://github.com/posthtml/posthtml/tree/master/docs) and [contribution guide](CONTRIBUTING.md).
package/src/find-path.js CHANGED
@@ -44,7 +44,7 @@ function searchInFolders(tag, fileNameFromTag, options) {
44
44
  const componentPath = search(options.root, options.folders, fileNameFromTag, options.fileExtension);
45
45
 
46
46
  if (!componentPath) {
47
- throw new Error(`[components] For the tag ${tag} was not found any template in defined root path ${options.folders.join(', ')}`);
47
+ throw new Error(`[components] <${tag}> could not find ${fileNameFromTag} in the defined root paths (${options.folders.join(', ')})`);
48
48
  }
49
49
 
50
50
  return componentPath;
@@ -63,7 +63,7 @@ function searchInNamespaces(tag, [namespace, fileNameFromTag], options) {
63
63
  const namespaceOption = options.namespaces.find(n => n.name === namespace.replace(options.tagPrefix, ''));
64
64
 
65
65
  if (!namespaceOption) {
66
- throw new Error(`[components] Unknown component namespace ${namespace}.`);
66
+ throw new Error(`[components] Unknown component namespace: ${namespace}.`);
67
67
  }
68
68
 
69
69
  let componentPath;
@@ -84,7 +84,7 @@ function searchInNamespaces(tag, [namespace, fileNameFromTag], options) {
84
84
  }
85
85
 
86
86
  if (!componentPath && options.strict) {
87
- throw new Error(`[components] For the tag ${tag} was not found any template in the defined namespace's base path ${namespaceOption.root}.`);
87
+ throw new Error(`[components] <${tag}> could not find ${fileNameFromTag} in the defined namespace base path ${namespaceOption.root}`);
88
88
  }
89
89
 
90
90
  return componentPath;