Skip to content

Commit a0f3855

Browse files
authored
Merge pull request #199 from github/marky-mark
Introduce extension API
2 parents 03b1191 + 4d53986 commit a0f3855

File tree

4 files changed

+25
-20
lines changed

4 files changed

+25
-20
lines changed

src/attr.ts

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {CustomElement} from './custom-element.js'
2+
import {meta} from './core.js'
23

3-
const attrs = new WeakMap<Record<PropertyKey, unknown>, string[]>()
4+
const attrKey = 'attr'
45
type attrValue = string | number | boolean
56

67
/**
@@ -11,8 +12,7 @@ type attrValue = string | number | boolean
1112
* Number or Boolean. This matches the behavior of `initializeAttrs`.
1213
*/
1314
export function attr<K extends string>(proto: Record<K, attrValue>, key: K): void {
14-
if (!attrs.has(proto)) attrs.set(proto, [])
15-
attrs.get(proto)!.push(key)
15+
meta(proto, attrKey).add(key)
1616
}
1717

1818
/**
@@ -38,7 +38,7 @@ const initialized = new WeakSet<Element>()
3838
export function initializeAttrs(instance: HTMLElement, names?: Iterable<string>): void {
3939
if (initialized.has(instance)) return
4040
initialized.add(instance)
41-
if (!names) names = getAttrNames(Object.getPrototypeOf(instance))
41+
if (!names) names = meta(Object.getPrototypeOf(instance), attrKey)
4242
for (const key of names) {
4343
const value = (<Record<PropertyKey, unknown>>(<unknown>instance))[key]
4444
const name = attrToAttributeName(key)
@@ -79,19 +79,6 @@ export function initializeAttrs(instance: HTMLElement, names?: Iterable<string>)
7979
}
8080
}
8181

82-
function getAttrNames(classObjectProto: Record<PropertyKey, unknown>): Set<string> {
83-
const names: Set<string> = new Set()
84-
let proto: Record<PropertyKey, unknown> | typeof HTMLElement = classObjectProto
85-
86-
while (proto && proto !== HTMLElement) {
87-
const attrNames = attrs.get(<Record<PropertyKey, unknown>>proto) || []
88-
for (const name of attrNames) names.add(name)
89-
proto = Object.getPrototypeOf(proto)
90-
}
91-
92-
return names
93-
}
94-
9582
function attrToAttributeName(name: string): string {
9683
return `data-${name.replace(/([A-Z]($|[a-z]))/g, '-$1')}`.replace(/--/g, '-').toLowerCase()
9784
}
@@ -101,8 +88,7 @@ export function defineObservedAttributes(classObject: CustomElement): void {
10188
Object.defineProperty(classObject, 'observedAttributes', {
10289
configurable: true,
10390
get() {
104-
const attrMap = getAttrNames(classObject.prototype)
105-
return [...attrMap].map(attrToAttributeName).concat(observed)
91+
return [...meta(classObject.prototype, attrKey)].map(attrToAttributeName).concat(observed)
10692
},
10793
set(attributes: string[]) {
10894
observed = attributes

src/core.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {defineObservedAttributes, initializeAttrs} from './attr.js'
55
import type {CustomElement} from './custom-element.js'
66

77
const instances = new WeakSet<Element>()
8+
const symbol = Symbol.for('catalyst')
89

910
export function initializeInstance(instance: HTMLElement, connect?: (this: HTMLElement) => void): void {
1011
instance.toggleAttribute('data-catalyst', true)
@@ -38,3 +39,18 @@ export function initializeClass(classObject: CustomElement): void {
3839
export function initialized(el: Element): boolean {
3940
return instances.has(el)
4041
}
42+
43+
export function meta(proto: Record<PropertyKey, unknown>, name: string): Set<string> {
44+
if (!Object.prototype.hasOwnProperty.call(proto, symbol)) {
45+
const parent = proto[symbol] as Map<string, Set<string>> | undefined
46+
const map = (proto[symbol] = new Map<string, Set<string>>())
47+
if (parent) {
48+
for (const [key, value] of parent) {
49+
map.set(key, new Set(value))
50+
}
51+
}
52+
}
53+
const map = proto[symbol] as Map<string, Set<string>>
54+
if (!map.has(name)) map.set(name, new Set<string>())
55+
return map.get(name)!
56+
}

src/target.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {findTarget, findTargets} from './findtarget.js'
2+
import {meta} from './core.js'
23

34
/**
45
* Target is a decorator which - when assigned to a property field on the
@@ -8,6 +9,7 @@ import {findTarget, findTargets} from './findtarget.js'
89
* `findTarget(this, 'foo')`.
910
*/
1011
export function target<K extends string>(proto: Record<K, unknown>, key: K): void {
12+
meta(proto, 'target').add(key)
1113
Object.defineProperty(proto, key, {
1214
configurable: true,
1315
get() {
@@ -24,6 +26,7 @@ export function target<K extends string>(proto: Record<K, unknown>, key: K): voi
2426
* `findTargets(this, 'foo')`.
2527
*/
2628
export function targets<K extends string>(proto: Record<K, unknown>, key: K): void {
29+
meta(proto, 'targets').add(key)
2730
Object.defineProperty(proto, key, {
2831
configurable: true,
2932
get() {

test/attr.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ describe('attr', () => {
183183
expect(instance).to.have.property('foo', '')
184184
expect(instance).to.have.property('bar', 'hello')
185185
expect(instance).to.have.property('baz', 'world')
186-
expect(instance.getAttributeNames()).to.eql(['data-baz', 'data-foo', 'data-bar'])
186+
expect(instance.getAttributeNames()).to.eql(['data-foo', 'data-bar', 'data-baz'])
187187
expect(instance.getAttribute('data-foo')).to.equal('')
188188
expect(instance.getAttribute('data-bar')).to.equal('hello')
189189
expect(instance.getAttribute('data-baz')).to.equal('world')

0 commit comments

Comments
 (0)