assign-gingerly 0.0.29 → 0.0.31
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 +44 -20
- package/object-extension.js +68 -0
- package/object-extension.ts +78 -0
- package/package.json +75 -75
- package/parseWithAttrs.js +3 -3
- package/parseWithAttrs.ts +3 -3
- package/playwright.config.ts +1 -1
- package/types/assign-gingerly/types.d.ts +1 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# assign-gingerly and assign-tentatively
|
|
2
2
|
|
|
3
3
|
[](https://github.com/bahrus/assign-gingerly/actions/workflows/CI.yml)
|
|
4
4
|
[](http://badge.fury.io/js/assign-gingerly)
|
|
@@ -1460,19 +1460,19 @@ element.remove();
|
|
|
1460
1460
|
|
|
1461
1461
|
// Case 1: Temporarily removed, will be re-added
|
|
1462
1462
|
setTimeout(() => document.body.append(element), 1000);
|
|
1463
|
-
//
|
|
1463
|
+
// ? Don't dispose - enhancement should persist
|
|
1464
1464
|
|
|
1465
1465
|
// Case 2: Moved to another location
|
|
1466
1466
|
otherContainer.append(element);
|
|
1467
|
-
//
|
|
1467
|
+
// ? Don't dispose - enhancement should persist
|
|
1468
1468
|
|
|
1469
1469
|
// Case 3: Cached for reuse
|
|
1470
1470
|
elementCache.set('myElement', element);
|
|
1471
|
-
//
|
|
1471
|
+
// ? Don't dispose - enhancement should persist
|
|
1472
1472
|
|
|
1473
1473
|
// Case 4: Truly done, ready for GC
|
|
1474
1474
|
element = null;
|
|
1475
|
-
//
|
|
1475
|
+
// ? Should dispose, but no way to detect this automatically
|
|
1476
1476
|
```
|
|
1477
1477
|
|
|
1478
1478
|
**Practical disposal strategies:**
|
|
@@ -1566,10 +1566,10 @@ class MyEnhancement {
|
|
|
1566
1566
|
```
|
|
1567
1567
|
|
|
1568
1568
|
**Summary:**
|
|
1569
|
-
-
|
|
1570
|
-
-
|
|
1571
|
-
-
|
|
1572
|
-
-
|
|
1569
|
+
- ? Storage mechanism prevents memory leaks via WeakMap
|
|
1570
|
+
- ?? Enhancement internals need manual cleanup via dispose()
|
|
1571
|
+
- ? No automatic way to detect when disposal should happen
|
|
1572
|
+
- ?? Choose disposal strategy based on your application's lifecycle
|
|
1573
1573
|
|
|
1574
1574
|
### Waiting for Async Initialization with `enh.whenResolved(regItem)`
|
|
1575
1575
|
|
|
@@ -1976,7 +1976,7 @@ console.log(instance.value); // 'test123' (parsed from attribute)
|
|
|
1976
1976
|
|
|
1977
1977
|
</details>
|
|
1978
1978
|
|
|
1979
|
-
> !
|
|
1979
|
+
> [!NOTE]
|
|
1980
1980
|
> `withAttrs` works with or without `enhKey`. When there's no `enhKey`, the parsed attributes are passed directly to the constructor. When there is an `enhKey`, they're merged with any pre-existing values on the enh container.
|
|
1981
1981
|
|
|
1982
1982
|
### The `enh-` Prefix for Attribute Isolation
|
|
@@ -2150,7 +2150,7 @@ The `base` attribute must contain either a dash (`-`) or a non-ASCII character t
|
|
|
2150
2150
|
```TypeScript
|
|
2151
2151
|
// Valid base attributes
|
|
2152
2152
|
const enhConfig1 = { base: 'data-config' }; // Has dash
|
|
2153
|
-
const enhConfig2 = { base: '
|
|
2153
|
+
const enhConfig2 = { base: '??-theme' }); // Has non-ASCII (and dash)
|
|
2154
2154
|
|
|
2155
2155
|
// Invalid - throws error
|
|
2156
2156
|
const enhConig3 = { base: 'config' }; // No dash or non-ASCII
|
|
@@ -2198,6 +2198,33 @@ const result = parseWithAttrs(element, {
|
|
|
2198
2198
|
// Result: { name: 'Alice', age: '30' }
|
|
2199
2199
|
```
|
|
2200
2200
|
|
|
2201
|
+
**Deep Nesting:**
|
|
2202
|
+
|
|
2203
|
+
Template variables can reference other template variables to any depth, creating hierarchical attribute naming patterns:
|
|
2204
|
+
|
|
2205
|
+
```TypeScript
|
|
2206
|
+
// HTML: <div data-app-user-profile-name="Alice" data-app-user-profile-email="alice@example.com"></div>
|
|
2207
|
+
|
|
2208
|
+
const result = parseWithAttrs(element, {
|
|
2209
|
+
base: 'data-',
|
|
2210
|
+
app: '${base}app',
|
|
2211
|
+
user: '${app}-user',
|
|
2212
|
+
profile: '${user}-profile',
|
|
2213
|
+
name: '${profile}-name',
|
|
2214
|
+
email: '${profile}-email'
|
|
2215
|
+
});
|
|
2216
|
+
// Result: { name: 'Alice', email: 'alice@example.com' }
|
|
2217
|
+
|
|
2218
|
+
// The resolution chain: base ? app ? user ? profile ? name/email
|
|
2219
|
+
// Resolves to: data-app-user-profile-name and data-app-user-profile-email
|
|
2220
|
+
```
|
|
2221
|
+
|
|
2222
|
+
**Benefits of hierarchical variables:**
|
|
2223
|
+
- Build complex attribute names from simple parts
|
|
2224
|
+
- Maintain consistency across related attributes
|
|
2225
|
+
- Easy to refactor by changing a single variable
|
|
2226
|
+
- Self-documenting attribute structure
|
|
2227
|
+
|
|
2201
2228
|
Template variables are resolved recursively and cached for performance. Circular references are detected and throw an error.
|
|
2202
2229
|
|
|
2203
2230
|
### Type Parsing with instanceOf
|
|
@@ -2376,12 +2403,12 @@ registerCommonParsers(globalParserRegistry);
|
|
|
2376
2403
|
|
|
2377
2404
|
**Benefits of Named Parsers:**
|
|
2378
2405
|
|
|
2379
|
-
-
|
|
2380
|
-
-
|
|
2381
|
-
-
|
|
2382
|
-
-
|
|
2383
|
-
-
|
|
2384
|
-
-
|
|
2406
|
+
- ? **JSON serializable** - Configs can be stored/transmitted as JSON
|
|
2407
|
+
- ? **Reusable** - Define once, use everywhere
|
|
2408
|
+
- ? **Maintainable** - Update parser logic in one place
|
|
2409
|
+
- ? **Testable** - Test parsers independently
|
|
2410
|
+
- ? **Discoverable** - `globalParserRegistry.getNames()` lists all available parsers
|
|
2411
|
+
- ? **Backward compatible** - Inline functions still work
|
|
2385
2412
|
|
|
2386
2413
|
**Mixing Inline and Named Parsers:**
|
|
2387
2414
|
|
|
@@ -3408,6 +3435,3 @@ ItemScope Managers follow these design principles:
|
|
|
3408
3435
|
|
|
3409
3436
|
This design ensures backward compatibility while providing powerful new capabilities for managing DOM fragments.
|
|
3410
3437
|
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
package/object-extension.js
CHANGED
|
@@ -284,6 +284,74 @@ if (typeof Element !== 'undefined') {
|
|
|
284
284
|
enumerable: true,
|
|
285
285
|
configurable: true,
|
|
286
286
|
});
|
|
287
|
+
/**
|
|
288
|
+
* Adds 'set' property to Element prototype for symbol-based dependency injection
|
|
289
|
+
* Returns a proxy that intercepts symbol property assignments
|
|
290
|
+
*/
|
|
291
|
+
Object.defineProperty(Element.prototype, 'set', {
|
|
292
|
+
get: function () {
|
|
293
|
+
const element = this;
|
|
294
|
+
return new Proxy({}, {
|
|
295
|
+
set: (_, prop, value) => {
|
|
296
|
+
if (typeof prop === 'symbol') {
|
|
297
|
+
// Get the registry from customElementRegistry (scoped or global)
|
|
298
|
+
const registry = element.customElementRegistry?.enhancementRegistry
|
|
299
|
+
?? (typeof customElements !== 'undefined' ? customElements.enhancementRegistry : undefined);
|
|
300
|
+
if (registry) {
|
|
301
|
+
const registryItem = registry.findBySymbol(prop);
|
|
302
|
+
if (registryItem) {
|
|
303
|
+
const instanceMap = getInstanceMap();
|
|
304
|
+
const instances = instanceMap.getOrInsertComputed(element, () => new Map());
|
|
305
|
+
let instance = instances.get(registryItem);
|
|
306
|
+
if (!instance) {
|
|
307
|
+
const SpawnClass = registryItem.spawn;
|
|
308
|
+
// Check canSpawn if it exists
|
|
309
|
+
if (typeof SpawnClass.canSpawn === 'function') {
|
|
310
|
+
const ctx = { config: registryItem };
|
|
311
|
+
if (!SpawnClass.canSpawn(element, ctx)) {
|
|
312
|
+
// canSpawn returned false, skip spawning
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// If target is an Element and registryItem has enhKey, pass element to constructor
|
|
317
|
+
if (registryItem.enhKey) {
|
|
318
|
+
const ctx = { config: registryItem };
|
|
319
|
+
const initVals = element.enh?.[registryItem.enhKey] &&
|
|
320
|
+
!(element.enh[registryItem.enhKey] instanceof SpawnClass)
|
|
321
|
+
? element.enh[registryItem.enhKey]
|
|
322
|
+
: undefined;
|
|
323
|
+
instance = new SpawnClass(element, ctx, initVals);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const ctx = { config: registryItem };
|
|
327
|
+
instance = new SpawnClass(element, ctx);
|
|
328
|
+
}
|
|
329
|
+
instances.set(registryItem, instance);
|
|
330
|
+
// If registryItem has enhKey, store on enh
|
|
331
|
+
if (registryItem.enhKey) {
|
|
332
|
+
if (!element.enh) {
|
|
333
|
+
// This shouldn't happen since enh is a getter, but be safe
|
|
334
|
+
element.enh = {};
|
|
335
|
+
}
|
|
336
|
+
element.enh[registryItem.enhKey] = instance;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (registryItem.symlinks) {
|
|
340
|
+
const mappedKey = registryItem.symlinks[prop];
|
|
341
|
+
if (mappedKey && instance && typeof instance === 'object') {
|
|
342
|
+
instance[mappedKey] = value;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return true;
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
},
|
|
352
|
+
enumerable: false,
|
|
353
|
+
configurable: true,
|
|
354
|
+
});
|
|
287
355
|
}
|
|
288
356
|
/**
|
|
289
357
|
* Adds assignGingerly method to all objects via the Object prototype
|
package/object-extension.ts
CHANGED
|
@@ -404,6 +404,84 @@ if (typeof Element !== 'undefined') {
|
|
|
404
404
|
enumerable: true,
|
|
405
405
|
configurable: true,
|
|
406
406
|
});
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Adds 'set' property to Element prototype for symbol-based dependency injection
|
|
410
|
+
* Returns a proxy that intercepts symbol property assignments
|
|
411
|
+
*/
|
|
412
|
+
Object.defineProperty(Element.prototype, 'set', {
|
|
413
|
+
get: function (this: Element) {
|
|
414
|
+
const element = this;
|
|
415
|
+
return new Proxy(
|
|
416
|
+
{},
|
|
417
|
+
{
|
|
418
|
+
set: (_: any, prop: string | symbol, value: any) => {
|
|
419
|
+
if (typeof prop === 'symbol') {
|
|
420
|
+
// Get the registry from customElementRegistry (scoped or global)
|
|
421
|
+
const registry = (element as any).customElementRegistry?.enhancementRegistry
|
|
422
|
+
?? (typeof customElements !== 'undefined' ? customElements.enhancementRegistry : undefined);
|
|
423
|
+
|
|
424
|
+
if (registry) {
|
|
425
|
+
const registryItem = registry.findBySymbol(prop);
|
|
426
|
+
if (registryItem) {
|
|
427
|
+
const instanceMap = getInstanceMap();
|
|
428
|
+
const instances = instanceMap.getOrInsertComputed(element, () => new Map());
|
|
429
|
+
let instance = instances.get(registryItem);
|
|
430
|
+
|
|
431
|
+
if (!instance) {
|
|
432
|
+
const SpawnClass = registryItem.spawn;
|
|
433
|
+
|
|
434
|
+
// Check canSpawn if it exists
|
|
435
|
+
if (typeof SpawnClass.canSpawn === 'function') {
|
|
436
|
+
const ctx = { config: registryItem };
|
|
437
|
+
if (!SpawnClass.canSpawn(element, ctx)) {
|
|
438
|
+
// canSpawn returned false, skip spawning
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// If target is an Element and registryItem has enhKey, pass element to constructor
|
|
444
|
+
if (registryItem.enhKey) {
|
|
445
|
+
const ctx = { config: registryItem };
|
|
446
|
+
const initVals = (element as any).enh?.[registryItem.enhKey] &&
|
|
447
|
+
!((element as any).enh[registryItem.enhKey] instanceof SpawnClass)
|
|
448
|
+
? (element as any).enh[registryItem.enhKey]
|
|
449
|
+
: undefined;
|
|
450
|
+
instance = new SpawnClass(element, ctx, initVals);
|
|
451
|
+
} else {
|
|
452
|
+
const ctx = { config: registryItem };
|
|
453
|
+
instance = new SpawnClass(element, ctx);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
instances.set(registryItem, instance);
|
|
457
|
+
|
|
458
|
+
// If registryItem has enhKey, store on enh
|
|
459
|
+
if (registryItem.enhKey) {
|
|
460
|
+
if (!(element as any).enh) {
|
|
461
|
+
// This shouldn't happen since enh is a getter, but be safe
|
|
462
|
+
(element as any).enh = {};
|
|
463
|
+
}
|
|
464
|
+
(element as any).enh[registryItem.enhKey] = instance;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if(registryItem.symlinks){
|
|
469
|
+
const mappedKey = registryItem.symlinks[prop];
|
|
470
|
+
if (mappedKey && instance && typeof instance === 'object') {
|
|
471
|
+
(instance as any)[mappedKey] = value;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return true;
|
|
478
|
+
},
|
|
479
|
+
}
|
|
480
|
+
);
|
|
481
|
+
},
|
|
482
|
+
enumerable: false,
|
|
483
|
+
configurable: true,
|
|
484
|
+
});
|
|
407
485
|
}
|
|
408
486
|
|
|
409
487
|
/**
|
package/package.json
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "assign-gingerly",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "This package provides a utility function for carefully merging one object into another.",
|
|
5
|
-
"homepage": "https://github.com/bahrus/assign-gingerly#readme",
|
|
6
|
-
"bugs": {
|
|
7
|
-
"url": "https://github.com/bahrus/assign-gingerly/issues"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/bahrus/assign-gingerly.git"
|
|
12
|
-
},
|
|
13
|
-
"license": "MIT",
|
|
14
|
-
"author": "Bruce B. Anderson <andeson.bruce.b@gmail.com>",
|
|
15
|
-
"type": "module",
|
|
16
|
-
"types": "types/assign-gingerly/types.d.ts",
|
|
17
|
-
"files": [
|
|
18
|
-
"*.js",
|
|
19
|
-
"*.ts",
|
|
20
|
-
"README.md",
|
|
21
|
-
"LICENSE",
|
|
22
|
-
"types/assign-gingerly/types.d.ts"
|
|
23
|
-
],
|
|
24
|
-
"exports": {
|
|
25
|
-
".": {
|
|
26
|
-
"default": "./index.js",
|
|
27
|
-
"types": "./index.ts"
|
|
28
|
-
},
|
|
29
|
-
"./assignGingerly.js": {
|
|
30
|
-
"default": "./assignGingerly.js",
|
|
31
|
-
"types": "./assignGingerly.ts"
|
|
32
|
-
},
|
|
33
|
-
"./assignTentatively.js": {
|
|
34
|
-
"default": "./assignTentatively.js",
|
|
35
|
-
"types": "./assignTentatively.ts"
|
|
36
|
-
},
|
|
37
|
-
"./waitForEvent.js": {
|
|
38
|
-
"default": "./waitForEvent.js"
|
|
39
|
-
},
|
|
40
|
-
"./parserRegistry.js": {
|
|
41
|
-
"default": "./parserRegistry.js"
|
|
42
|
-
},
|
|
43
|
-
"./parseWithAttrs.js": {
|
|
44
|
-
"default": "./parseWithAttrs.js",
|
|
45
|
-
"types": "./parseWithAttrs.ts"
|
|
46
|
-
},
|
|
47
|
-
"./buildCSSQuery.js": {
|
|
48
|
-
"default": "./buildCSSQuery.js",
|
|
49
|
-
"types": "./buildCSSQuery.ts"
|
|
50
|
-
},
|
|
51
|
-
"./resolveTemplate.js": {
|
|
52
|
-
"default": "./resolveTemplate.js",
|
|
53
|
-
"types": "./resolveTemplate.ts"
|
|
54
|
-
},
|
|
55
|
-
"./getHost.js": {
|
|
56
|
-
"default": "./getHost.js",
|
|
57
|
-
"types": "./getHost.ts"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"main": "index.js",
|
|
61
|
-
"module": "index.js",
|
|
62
|
-
"scripts": {
|
|
63
|
-
"serve": "node ./node_modules/spa-ssi/serve.js",
|
|
64
|
-
"test": "playwright test",
|
|
65
|
-
"update": "ncu -u && npm install",
|
|
66
|
-
"safari": "npx playwright wk http://localhost:8000",
|
|
67
|
-
"chrome": "npx playwright cr http://localhost:8000"
|
|
68
|
-
},
|
|
69
|
-
"devDependencies": {
|
|
70
|
-
"@playwright/test": "1.59.1",
|
|
71
|
-
"spa-ssi": "0.0.27",
|
|
72
|
-
"@types/node": "25.
|
|
73
|
-
"typescript": "6.0.
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "assign-gingerly",
|
|
3
|
+
"version": "0.0.31",
|
|
4
|
+
"description": "This package provides a utility function for carefully merging one object into another.",
|
|
5
|
+
"homepage": "https://github.com/bahrus/assign-gingerly#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/bahrus/assign-gingerly/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/bahrus/assign-gingerly.git"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Bruce B. Anderson <andeson.bruce.b@gmail.com>",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"types": "types/assign-gingerly/types.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"*.js",
|
|
19
|
+
"*.ts",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"types/assign-gingerly/types.d.ts"
|
|
23
|
+
],
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"default": "./index.js",
|
|
27
|
+
"types": "./index.ts"
|
|
28
|
+
},
|
|
29
|
+
"./assignGingerly.js": {
|
|
30
|
+
"default": "./assignGingerly.js",
|
|
31
|
+
"types": "./assignGingerly.ts"
|
|
32
|
+
},
|
|
33
|
+
"./assignTentatively.js": {
|
|
34
|
+
"default": "./assignTentatively.js",
|
|
35
|
+
"types": "./assignTentatively.ts"
|
|
36
|
+
},
|
|
37
|
+
"./waitForEvent.js": {
|
|
38
|
+
"default": "./waitForEvent.js"
|
|
39
|
+
},
|
|
40
|
+
"./parserRegistry.js": {
|
|
41
|
+
"default": "./parserRegistry.js"
|
|
42
|
+
},
|
|
43
|
+
"./parseWithAttrs.js": {
|
|
44
|
+
"default": "./parseWithAttrs.js",
|
|
45
|
+
"types": "./parseWithAttrs.ts"
|
|
46
|
+
},
|
|
47
|
+
"./buildCSSQuery.js": {
|
|
48
|
+
"default": "./buildCSSQuery.js",
|
|
49
|
+
"types": "./buildCSSQuery.ts"
|
|
50
|
+
},
|
|
51
|
+
"./resolveTemplate.js": {
|
|
52
|
+
"default": "./resolveTemplate.js",
|
|
53
|
+
"types": "./resolveTemplate.ts"
|
|
54
|
+
},
|
|
55
|
+
"./getHost.js": {
|
|
56
|
+
"default": "./getHost.js",
|
|
57
|
+
"types": "./getHost.ts"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"main": "index.js",
|
|
61
|
+
"module": "index.js",
|
|
62
|
+
"scripts": {
|
|
63
|
+
"serve": "node ./node_modules/spa-ssi/serve.js",
|
|
64
|
+
"test": "playwright test",
|
|
65
|
+
"update": "ncu -u && npm install",
|
|
66
|
+
"safari": "npx playwright wk http://localhost:8000",
|
|
67
|
+
"chrome": "npx playwright cr http://localhost:8000"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@playwright/test": "1.59.1",
|
|
71
|
+
"spa-ssi": "0.0.27",
|
|
72
|
+
"@types/node": "25.6.0",
|
|
73
|
+
"typescript": "6.0.3"
|
|
74
|
+
}
|
|
75
|
+
}
|
package/parseWithAttrs.js
CHANGED
|
@@ -147,7 +147,8 @@ function hasDashOrNonASCII(str) {
|
|
|
147
147
|
* @returns The attribute value or null
|
|
148
148
|
*/
|
|
149
149
|
function getAttributeValue(element, attrName, allowUnprefixed) {
|
|
150
|
-
const
|
|
150
|
+
const { localName } = element;
|
|
151
|
+
const isCustomElement = localName.includes('-');
|
|
151
152
|
const isSVGElement = typeof SVGElement !== 'undefined' && element instanceof SVGElement;
|
|
152
153
|
// For custom elements and SVG - strict enh- requirement
|
|
153
154
|
if (isCustomElement || isSVGElement) {
|
|
@@ -157,8 +158,7 @@ function getAttributeValue(element, attrName, allowUnprefixed) {
|
|
|
157
158
|
// Only fallback if tag name matches the allowUnprefixed pattern
|
|
158
159
|
if (allowUnprefixed) {
|
|
159
160
|
const pattern = typeof allowUnprefixed === 'string' ? new RegExp(allowUnprefixed) : allowUnprefixed;
|
|
160
|
-
|
|
161
|
-
if (pattern.test(tagName)) {
|
|
161
|
+
if (pattern.test(localName)) {
|
|
162
162
|
return element.getAttribute(attrName);
|
|
163
163
|
}
|
|
164
164
|
}
|
package/parseWithAttrs.ts
CHANGED
|
@@ -186,7 +186,8 @@ function getAttributeValue(
|
|
|
186
186
|
attrName: string,
|
|
187
187
|
allowUnprefixed?: string | RegExp
|
|
188
188
|
): string | null {
|
|
189
|
-
const
|
|
189
|
+
const { localName } = element;
|
|
190
|
+
const isCustomElement = localName.includes('-');
|
|
190
191
|
const isSVGElement = typeof SVGElement !== 'undefined' && element instanceof SVGElement;
|
|
191
192
|
|
|
192
193
|
// For custom elements and SVG - strict enh- requirement
|
|
@@ -197,8 +198,7 @@ function getAttributeValue(
|
|
|
197
198
|
// Only fallback if tag name matches the allowUnprefixed pattern
|
|
198
199
|
if (allowUnprefixed) {
|
|
199
200
|
const pattern = typeof allowUnprefixed === 'string' ? new RegExp(allowUnprefixed) : allowUnprefixed;
|
|
200
|
-
|
|
201
|
-
if (pattern.test(tagName)) {
|
|
201
|
+
if (pattern.test(localName)) {
|
|
202
202
|
return element.getAttribute(attrName);
|
|
203
203
|
}
|
|
204
204
|
}
|
package/playwright.config.ts
CHANGED
|
@@ -20,7 +20,7 @@ export default defineConfig({
|
|
|
20
20
|
/* Opt out of parallel tests on CI. */
|
|
21
21
|
workers: process.env.CI ? 1 : undefined,
|
|
22
22
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
23
|
-
reporter: [ ['html', { open: 'never' }] ],
|
|
23
|
+
reporter: [ ['html', { open: 'never' }] ],
|
|
24
24
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
25
25
|
use: {
|
|
26
26
|
/* Base URL to use in actions like `await page.goto('/')`. */
|