assign-gingerly 0.0.43 → 0.0.44
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 +1 -0
- package/assignFeatures.js +80 -0
- package/assignFeatures.ts +108 -0
- package/index.js +1 -1
- package/index.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4790,6 +4790,7 @@ await customElements.assignFeatures(MyElement, { feature: { spawn: SyncFeature }
|
|
|
4790
4790
|
| [truth-sourcer](https://www.npmjs.com/package/truth-sourcer) | Attribute/property binding and truth-sourcing for custom elements | [GitHub](https://github.com/bahrus/truth-sourcer) |
|
|
4791
4791
|
| [be-reflective](https://www.npmjs.com/package/be-reflective) | CSS custom state reflection from computed styles | [GitHub](https://github.com/bahrus/be-reflective) |
|
|
4792
4792
|
| [face-up](https://www.npmjs.com/package/face-up) | Form Associated Custom Element behavior via ElementInternals | [GitHub](https://github.com/bahrus/face-up) |
|
|
4793
|
+
| [roundabout](https://www.npmjs.com/package/roundabout) | Reactive view-model binding with template rendering and computed property orchestration | [GitHub](https://github.com/bahrus/roundabout#using-roundaboutfeature-with-assignfeatures) |
|
|
4793
4794
|
| [time-ticker](https://www.npmjs.com/package/time-ticker) | Web component that fires events periodically (example of a feature-based component with no code in the class) | [GitHub](https://github.com/bahrus/time-ticker) |
|
|
4794
4795
|
|
|
4795
4796
|
</details>
|
package/assignFeatures.js
CHANGED
|
@@ -479,6 +479,86 @@ export function captureFeatureInitVals(instance) {
|
|
|
479
479
|
}
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* Global store for inter-feature suggestions.
|
|
484
|
+
* Structure: Map<targetSymbol, Map<targetClass, Array<FeatureInfoSuggestion>>>
|
|
485
|
+
* Scoped per target class to prevent leaking between different custom elements.
|
|
486
|
+
*/
|
|
487
|
+
const featureInfoSuggestions = new Map();
|
|
488
|
+
/**
|
|
489
|
+
* Suggest configuration to another feature during registration.
|
|
490
|
+
*
|
|
491
|
+
* Call this in a feature's `static onAssigned` to provide config fragments
|
|
492
|
+
* (withAttrs, customData) that another feature should merge into its own config.
|
|
493
|
+
*
|
|
494
|
+
* The target feature is identified by a Symbol (stable across versions and mocks).
|
|
495
|
+
* Suggestions are scoped per target class to prevent leaking between different
|
|
496
|
+
* custom elements that use the same features.
|
|
497
|
+
*
|
|
498
|
+
* @param fromFeatureCtr - The feature class making the suggestion (for tracing)
|
|
499
|
+
* @param toFeatureSymbol - Symbol identifying the target feature
|
|
500
|
+
* @param featureInfo - Config fragments to suggest (withAttrs, customData)
|
|
501
|
+
* @param targetClass - The custom element class being configured
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* import { suggestFeatureInfo } from 'assign-gingerly/assignFeatures.js';
|
|
505
|
+
* import { ROUNDABOUT_FEATURE } from 'roundabout/symbols.js';
|
|
506
|
+
*
|
|
507
|
+
* class FaceUp {
|
|
508
|
+
* static onAssigned(ctr, featureConfig) {
|
|
509
|
+
* suggestFeatureInfo(FaceUp, ROUNDABOUT_FEATURE, {
|
|
510
|
+
* customData: { formBindings: { value: 'value' } }
|
|
511
|
+
* }, ctr);
|
|
512
|
+
* }
|
|
513
|
+
* }
|
|
514
|
+
*/
|
|
515
|
+
export function suggestFeatureInfo(fromFeatureCtr, toFeatureSymbol, featureInfo, targetClass) {
|
|
516
|
+
let symbolMap = featureInfoSuggestions.get(toFeatureSymbol);
|
|
517
|
+
if (!symbolMap) {
|
|
518
|
+
symbolMap = new Map();
|
|
519
|
+
featureInfoSuggestions.set(toFeatureSymbol, symbolMap);
|
|
520
|
+
}
|
|
521
|
+
let suggestions = symbolMap.get(targetClass);
|
|
522
|
+
if (!suggestions) {
|
|
523
|
+
suggestions = [];
|
|
524
|
+
symbolMap.set(targetClass, suggestions);
|
|
525
|
+
}
|
|
526
|
+
suggestions.push({
|
|
527
|
+
from: fromFeatureCtr,
|
|
528
|
+
...featureInfo
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Retrieve suggestions made to a feature by other features.
|
|
533
|
+
*
|
|
534
|
+
* Call this in a feature's `static onAssigned` to read config fragments
|
|
535
|
+
* suggested by other features that were processed earlier.
|
|
536
|
+
*
|
|
537
|
+
* @param toFeatureSymbol - Symbol identifying this feature (the target)
|
|
538
|
+
* @param targetClass - The custom element class being configured
|
|
539
|
+
* @returns Array of suggestions (empty if none)
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* import { getFeatureInfoSuggestions } from 'assign-gingerly/assignFeatures.js';
|
|
543
|
+
* import { ROUNDABOUT_FEATURE } from './symbols.js';
|
|
544
|
+
*
|
|
545
|
+
* class RoundaboutFeature {
|
|
546
|
+
* static onAssigned(ctr, featureConfig) {
|
|
547
|
+
* const suggestions = getFeatureInfoSuggestions(ROUNDABOUT_FEATURE, ctr);
|
|
548
|
+
* for (const suggestion of suggestions) {
|
|
549
|
+
* if (suggestion.customData) {
|
|
550
|
+
* featureConfig.customData = { ...featureConfig.customData, ...suggestion.customData };
|
|
551
|
+
* }
|
|
552
|
+
* }
|
|
553
|
+
* }
|
|
554
|
+
* }
|
|
555
|
+
*/
|
|
556
|
+
export function getFeatureInfoSuggestions(toFeatureSymbol, targetClass) {
|
|
557
|
+
const symbolMap = featureInfoSuggestions.get(toFeatureSymbol);
|
|
558
|
+
if (!symbolMap)
|
|
559
|
+
return [];
|
|
560
|
+
return symbolMap.get(targetClass) || [];
|
|
561
|
+
}
|
|
482
562
|
// =============================================================================
|
|
483
563
|
// PropertyBag — base class for nested feature containers
|
|
484
564
|
// =============================================================================
|
package/assignFeatures.ts
CHANGED
|
@@ -731,6 +731,114 @@ export function captureFeatureInitVals(instance: any): void {
|
|
|
731
731
|
}
|
|
732
732
|
}
|
|
733
733
|
|
|
734
|
+
// =============================================================================
|
|
735
|
+
// Inter-feature communication: suggestFeatureInfo / getFeatureInfoSuggestions
|
|
736
|
+
// =============================================================================
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* A suggestion from one feature to another, containing config fragments to merge.
|
|
740
|
+
*/
|
|
741
|
+
export interface FeatureInfoSuggestion {
|
|
742
|
+
/** The feature class that made the suggestion (for debugging/tracing) */
|
|
743
|
+
from: Function;
|
|
744
|
+
/** Attribute patterns to merge into the target feature's withAttrs */
|
|
745
|
+
withAttrs?: any;
|
|
746
|
+
/** Custom data to merge into the target feature's customData */
|
|
747
|
+
customData?: any;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Global store for inter-feature suggestions.
|
|
752
|
+
* Structure: Map<targetSymbol, Map<targetClass, Array<FeatureInfoSuggestion>>>
|
|
753
|
+
* Scoped per target class to prevent leaking between different custom elements.
|
|
754
|
+
*/
|
|
755
|
+
const featureInfoSuggestions = new Map<symbol, Map<Function, FeatureInfoSuggestion[]>>();
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Suggest configuration to another feature during registration.
|
|
759
|
+
*
|
|
760
|
+
* Call this in a feature's `static onAssigned` to provide config fragments
|
|
761
|
+
* (withAttrs, customData) that another feature should merge into its own config.
|
|
762
|
+
*
|
|
763
|
+
* The target feature is identified by a Symbol (stable across versions and mocks).
|
|
764
|
+
* Suggestions are scoped per target class to prevent leaking between different
|
|
765
|
+
* custom elements that use the same features.
|
|
766
|
+
*
|
|
767
|
+
* @param fromFeatureCtr - The feature class making the suggestion (for tracing)
|
|
768
|
+
* @param toFeatureSymbol - Symbol identifying the target feature
|
|
769
|
+
* @param featureInfo - Config fragments to suggest (withAttrs, customData)
|
|
770
|
+
* @param targetClass - The custom element class being configured
|
|
771
|
+
*
|
|
772
|
+
* @example
|
|
773
|
+
* import { suggestFeatureInfo } from 'assign-gingerly/assignFeatures.js';
|
|
774
|
+
* import { ROUNDABOUT_FEATURE } from 'roundabout/symbols.js';
|
|
775
|
+
*
|
|
776
|
+
* class FaceUp {
|
|
777
|
+
* static onAssigned(ctr, featureConfig) {
|
|
778
|
+
* suggestFeatureInfo(FaceUp, ROUNDABOUT_FEATURE, {
|
|
779
|
+
* customData: { formBindings: { value: 'value' } }
|
|
780
|
+
* }, ctr);
|
|
781
|
+
* }
|
|
782
|
+
* }
|
|
783
|
+
*/
|
|
784
|
+
export function suggestFeatureInfo(
|
|
785
|
+
fromFeatureCtr: Function,
|
|
786
|
+
toFeatureSymbol: symbol,
|
|
787
|
+
featureInfo: { withAttrs?: any; customData?: any },
|
|
788
|
+
targetClass: Function
|
|
789
|
+
): void {
|
|
790
|
+
let symbolMap = featureInfoSuggestions.get(toFeatureSymbol);
|
|
791
|
+
if (!symbolMap) {
|
|
792
|
+
symbolMap = new Map();
|
|
793
|
+
featureInfoSuggestions.set(toFeatureSymbol, symbolMap);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
let suggestions = symbolMap.get(targetClass);
|
|
797
|
+
if (!suggestions) {
|
|
798
|
+
suggestions = [];
|
|
799
|
+
symbolMap.set(targetClass, suggestions);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
suggestions.push({
|
|
803
|
+
from: fromFeatureCtr,
|
|
804
|
+
...featureInfo
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Retrieve suggestions made to a feature by other features.
|
|
810
|
+
*
|
|
811
|
+
* Call this in a feature's `static onAssigned` to read config fragments
|
|
812
|
+
* suggested by other features that were processed earlier.
|
|
813
|
+
*
|
|
814
|
+
* @param toFeatureSymbol - Symbol identifying this feature (the target)
|
|
815
|
+
* @param targetClass - The custom element class being configured
|
|
816
|
+
* @returns Array of suggestions (empty if none)
|
|
817
|
+
*
|
|
818
|
+
* @example
|
|
819
|
+
* import { getFeatureInfoSuggestions } from 'assign-gingerly/assignFeatures.js';
|
|
820
|
+
* import { ROUNDABOUT_FEATURE } from './symbols.js';
|
|
821
|
+
*
|
|
822
|
+
* class RoundaboutFeature {
|
|
823
|
+
* static onAssigned(ctr, featureConfig) {
|
|
824
|
+
* const suggestions = getFeatureInfoSuggestions(ROUNDABOUT_FEATURE, ctr);
|
|
825
|
+
* for (const suggestion of suggestions) {
|
|
826
|
+
* if (suggestion.customData) {
|
|
827
|
+
* featureConfig.customData = { ...featureConfig.customData, ...suggestion.customData };
|
|
828
|
+
* }
|
|
829
|
+
* }
|
|
830
|
+
* }
|
|
831
|
+
* }
|
|
832
|
+
*/
|
|
833
|
+
export function getFeatureInfoSuggestions(
|
|
834
|
+
toFeatureSymbol: symbol,
|
|
835
|
+
targetClass: Function
|
|
836
|
+
): FeatureInfoSuggestion[] {
|
|
837
|
+
const symbolMap = featureInfoSuggestions.get(toFeatureSymbol);
|
|
838
|
+
if (!symbolMap) return [];
|
|
839
|
+
return symbolMap.get(targetClass) || [];
|
|
840
|
+
}
|
|
841
|
+
|
|
734
842
|
// =============================================================================
|
|
735
843
|
// PropertyBag — base class for nested feature containers
|
|
736
844
|
// =============================================================================
|
package/index.js
CHANGED
|
@@ -9,6 +9,6 @@ export { resolveTemplate } from './resolveTemplate.js';
|
|
|
9
9
|
export { getHost } from './getHost.js';
|
|
10
10
|
export { resolveValues, resolveValue } from './resolveValues.js';
|
|
11
11
|
export { assignFrom } from './assignFrom.js';
|
|
12
|
-
export { assignFeatures, FeaturesRegistry, captureFeatureInitVals, PropertyBag } from './assignFeatures.js';
|
|
12
|
+
export { assignFeatures, FeaturesRegistry, captureFeatureInitVals, PropertyBag, suggestFeatureInfo, getFeatureInfoSuggestions } from './assignFeatures.js';
|
|
13
13
|
export { installForwarding } from './installForwarding.js';
|
|
14
14
|
import './object-extension.js';
|
package/index.ts
CHANGED
|
@@ -9,6 +9,6 @@ export {resolveTemplate} from './resolveTemplate.js';
|
|
|
9
9
|
export {getHost} from './getHost.js';
|
|
10
10
|
export {resolveValues, resolveValue} from './resolveValues.js';
|
|
11
11
|
export {assignFrom} from './assignFrom.js';
|
|
12
|
-
export {assignFeatures, FeaturesRegistry, captureFeatureInitVals, PropertyBag} from './assignFeatures.js';
|
|
12
|
+
export {assignFeatures, FeaturesRegistry, captureFeatureInitVals, PropertyBag, suggestFeatureInfo, getFeatureInfoSuggestions} from './assignFeatures.js';
|
|
13
13
|
export {installForwarding} from './installForwarding.js';
|
|
14
14
|
import './object-extension.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assign-gingerly",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.44",
|
|
4
4
|
"description": "This package provides a utility function for carefully merging one object into another.",
|
|
5
5
|
"homepage": "https://github.com/bahrus/assign-gingerly#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@playwright/test": "1.60.0",
|
|
91
91
|
"spa-ssi": "0.0.27",
|
|
92
|
-
"@types/node": "25.
|
|
92
|
+
"@types/node": "25.8.0",
|
|
93
93
|
"typescript": "6.0.3"
|
|
94
94
|
}
|
|
95
95
|
}
|