assign-gingerly 0.0.16 → 0.0.17

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
@@ -2206,6 +2206,17 @@ console.log(query);
2206
2206
  const elements = document.querySelectorAll(query);
2207
2207
  ```
2208
2208
 
2209
+ **Without selectors (matches any element):**
2210
+
2211
+ ```TypeScript
2212
+ const query = buildCSSQuery(config, '');
2213
+ console.log(query);
2214
+ // '[my-component], [enh-my-component], [my-component-theme], [enh-my-component-theme]'
2215
+
2216
+ // Matches any element with these attributes
2217
+ const elements = document.querySelectorAll(query);
2218
+ ```
2219
+
2209
2220
  ### How It Works
2210
2221
 
2211
2222
  `buildCSSQuery` creates a cross-product of:
@@ -2289,11 +2300,25 @@ buildCSSQuery(config, 'div');
2289
2300
 
2290
2301
  ### Edge Cases
2291
2302
 
2292
- **Empty inputs return empty string:**
2303
+ **Empty selectors return attribute-only selectors:**
2304
+ ```TypeScript
2305
+ const config = {
2306
+ spawn: MyClass,
2307
+ withAttrs: {
2308
+ base: 'my-attr',
2309
+ theme: '${base}-theme'
2310
+ }
2311
+ };
2312
+
2313
+ buildCSSQuery(config, '');
2314
+ // '[my-attr], [enh-my-attr], [my-attr-theme], [enh-my-attr-theme]'
2315
+ // Matches any element with these attributes
2316
+ ```
2317
+
2318
+ **Empty withAttrs returns empty string:**
2293
2319
  ```TypeScript
2294
2320
  buildCSSQuery({ spawn: MyClass }, 'div'); // '' (no withAttrs)
2295
2321
  buildCSSQuery({ spawn: MyClass, withAttrs: {} }, 'div'); // '' (empty withAttrs)
2296
- buildCSSQuery({ spawn: MyClass, withAttrs: { base: 'x' } }, ''); // '' (empty selectors)
2297
2322
  ```
2298
2323
 
2299
2324
  **Deduplication:**
@@ -2312,14 +2337,15 @@ buildCSSQuery(config, ' div , span , p ');
2312
2337
 
2313
2338
  1. **Mount Observer Integration**: Find elements that need enhancement
2314
2339
  ```TypeScript
2315
- const query = buildCSSQuery(enhancementConfig, '*');
2340
+ // Match any element with the attributes
2341
+ const query = buildCSSQuery(enhancementConfig, '');
2316
2342
  const observer = new MutationObserver(() => {
2317
2343
  const elements = document.querySelectorAll(query);
2318
2344
  elements.forEach(el => enhance(el));
2319
2345
  });
2320
2346
  ```
2321
2347
 
2322
- 2. **Batch Enhancement**: Enhance all matching elements at once
2348
+ 2. **Specific Element Types**: Enhance only certain element types
2323
2349
  ```TypeScript
2324
2350
  const query = buildCSSQuery(config, 'template, script');
2325
2351
  document.querySelectorAll(query).forEach(el => {
@@ -2345,10 +2371,13 @@ function buildCSSQuery(
2345
2371
  **Parameters:**
2346
2372
  - `config`: Enhancement configuration with `withAttrs` property
2347
2373
  - `selectors`: Comma-separated CSS selectors (e.g., `'div, span'`)
2374
+ - If empty string or whitespace only, returns attribute selectors without element prefix
2375
+ - This matches any element with the specified attributes
2348
2376
 
2349
2377
  **Returns:**
2350
2378
  - CSS query string with cross-product of selectors and attributes
2351
- - Empty string if `withAttrs` is missing or empty
2379
+ - If selectors is empty: returns attribute-only selectors (e.g., `'[attr], [enh-attr]'`)
2380
+ - If withAttrs is missing or empty: returns empty string
2352
2381
 
2353
2382
  **Throws:**
2354
2383
  - Error if template variables have circular references
package/buildCSSQuery.js CHANGED
@@ -65,6 +65,7 @@ function extractAttributeNames(withAttrs) {
65
65
  *
66
66
  * @param config - Enhancement configuration with withAttrs
67
67
  * @param selectors - Comma-separated CSS selectors to match (e.g., 'template, script')
68
+ * If empty, returns just the attribute selectors without element prefix
68
69
  * @returns CSS query string with cross-product of selectors and attributes
69
70
  *
70
71
  * @example
@@ -76,36 +77,47 @@ function extractAttributeNames(withAttrs) {
76
77
  * }
77
78
  * };
78
79
  *
80
+ * // With selectors
79
81
  * buildCSSQuery(config, 'div, span');
80
82
  * // Returns: 'div[my-attr], span[my-attr], div[enh-my-attr], span[enh-my-attr],
81
83
  * // div[my-attr-theme], span[my-attr-theme], div[enh-my-attr-theme], span[enh-my-attr-theme]'
84
+ *
85
+ * // Without selectors (matches any element)
86
+ * buildCSSQuery(config, '');
87
+ * // Returns: '[my-attr], [enh-my-attr], [my-attr-theme], [enh-my-attr-theme]'
82
88
  */
83
89
  export function buildCSSQuery(config, selectors) {
84
90
  // Validate inputs
85
- if (!config.withAttrs || !selectors) {
86
- return '';
87
- }
88
- // Parse and normalize selectors
89
- const selectorList = selectors
90
- .split(',')
91
- .map(s => s.trim())
92
- .filter(s => s.length > 0);
93
- if (selectorList.length === 0) {
91
+ if (!config.withAttrs) {
94
92
  return '';
95
93
  }
96
- // Extract and resolve attribute names
94
+ // Extract and resolve attribute names first
97
95
  const attrNames = extractAttributeNames(config.withAttrs);
98
96
  if (attrNames.length === 0) {
99
97
  return '';
100
98
  }
101
- // Build cross-product of selectors × attributes × prefixes
99
+ // Parse and normalize selectors
100
+ const selectorList = selectors
101
+ ? selectors.split(',').map(s => s.trim()).filter(s => s.length > 0)
102
+ : [];
103
+ // Build queries
102
104
  const queries = [];
103
- for (const selector of selectorList) {
105
+ if (selectorList.length === 0) {
106
+ // No selectors provided - return just attribute selectors
104
107
  for (const attrName of attrNames) {
105
- // Unprefixed version
106
- queries.push(`${selector}[${attrName}]`);
107
- // enh- prefixed version
108
- queries.push(`${selector}[enh-${attrName}]`);
108
+ queries.push(`[${attrName}]`);
109
+ queries.push(`[enh-${attrName}]`);
110
+ }
111
+ }
112
+ else {
113
+ // Build cross-product of selectors × attributes × prefixes
114
+ for (const selector of selectorList) {
115
+ for (const attrName of attrNames) {
116
+ // Unprefixed version
117
+ queries.push(`${selector}[${attrName}]`);
118
+ // enh- prefixed version
119
+ queries.push(`${selector}[enh-${attrName}]`);
120
+ }
109
121
  }
110
122
  }
111
123
  // Deduplicate and join
package/buildCSSQuery.ts CHANGED
@@ -83,6 +83,7 @@ function extractAttributeNames(withAttrs: AttrPatterns<any>): string[] {
83
83
  *
84
84
  * @param config - Enhancement configuration with withAttrs
85
85
  * @param selectors - Comma-separated CSS selectors to match (e.g., 'template, script')
86
+ * If empty, returns just the attribute selectors without element prefix
86
87
  * @returns CSS query string with cross-product of selectors and attributes
87
88
  *
88
89
  * @example
@@ -94,45 +95,54 @@ function extractAttributeNames(withAttrs: AttrPatterns<any>): string[] {
94
95
  * }
95
96
  * };
96
97
  *
98
+ * // With selectors
97
99
  * buildCSSQuery(config, 'div, span');
98
100
  * // Returns: 'div[my-attr], span[my-attr], div[enh-my-attr], span[enh-my-attr],
99
101
  * // div[my-attr-theme], span[my-attr-theme], div[enh-my-attr-theme], span[enh-my-attr-theme]'
102
+ *
103
+ * // Without selectors (matches any element)
104
+ * buildCSSQuery(config, '');
105
+ * // Returns: '[my-attr], [enh-my-attr], [my-attr-theme], [enh-my-attr-theme]'
100
106
  */
101
107
  export function buildCSSQuery(
102
108
  config: EnhancementConfig,
103
109
  selectors: string
104
110
  ): string {
105
111
  // Validate inputs
106
- if (!config.withAttrs || !selectors) {
112
+ if (!config.withAttrs) {
107
113
  return '';
108
114
  }
109
115
 
110
- // Parse and normalize selectors
111
- const selectorList = selectors
112
- .split(',')
113
- .map(s => s.trim())
114
- .filter(s => s.length > 0);
115
-
116
- if (selectorList.length === 0) {
117
- return '';
118
- }
119
-
120
- // Extract and resolve attribute names
116
+ // Extract and resolve attribute names first
121
117
  const attrNames = extractAttributeNames(config.withAttrs);
122
118
 
123
119
  if (attrNames.length === 0) {
124
120
  return '';
125
121
  }
126
122
 
127
- // Build cross-product of selectors × attributes × prefixes
123
+ // Parse and normalize selectors
124
+ const selectorList = selectors
125
+ ? selectors.split(',').map(s => s.trim()).filter(s => s.length > 0)
126
+ : [];
127
+
128
+ // Build queries
128
129
  const queries: string[] = [];
129
130
 
130
- for (const selector of selectorList) {
131
+ if (selectorList.length === 0) {
132
+ // No selectors provided - return just attribute selectors
131
133
  for (const attrName of attrNames) {
132
- // Unprefixed version
133
- queries.push(`${selector}[${attrName}]`);
134
- // enh- prefixed version
135
- queries.push(`${selector}[enh-${attrName}]`);
134
+ queries.push(`[${attrName}]`);
135
+ queries.push(`[enh-${attrName}]`);
136
+ }
137
+ } else {
138
+ // Build cross-product of selectors × attributes × prefixes
139
+ for (const selector of selectorList) {
140
+ for (const attrName of attrNames) {
141
+ // Unprefixed version
142
+ queries.push(`${selector}[${attrName}]`);
143
+ // enh- prefixed version
144
+ queries.push(`${selector}[enh-${attrName}]`);
145
+ }
136
146
  }
137
147
  }
138
148
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assign-gingerly",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
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": {