2023-03
Refresher: Why metadata?
JSON.stringify
output, or WASM or native platform interop)GET
or POST
, or belonging to a specific url path, or what request body transforms to use)Legacy decorators used to receive the class definition as the first argument. Decorators could use the class as a key in a WeakMap to expose metadata.
const MY_META = new WeakMap();
class Metadata {
public = {};
own;
}
function addMeta(value) {
return function(Class, name, desc) {
let metadata = MY_META.get(Class);
if (!metadata) {
metadata = new Metadata();
MY_META.set(Class, metadata);
}
if (name) {
metadata.public[name] = value;
} else {
metadata.own = value;
}
}
}
@addMeta('class')
class C {
@addMeta('pub') x;
}
const metadata = MY_META.get(C);
metadata.own;
// 'class'
metadata.public.x;
// 'pub'
Champion's preferred approach. Decorator context receives an additional `metadata` property, which is a POJO.
function meta(key, value) {
return (_, context) => {
context.metadata[key] = value;
};
}
@meta('a' 'x')
class C {
@meta('b', 'y')
m() {}
}
C[Symbol.metadata].a; // 'x'
C[Symbol.metadata].b; // 'y'
class D extends C {
@meta('b', 'z')
m() {}
}
D[Symbol.metadata].a; // 'x'
D[Symbol.metadata].b; // 'z'
Decorators receive an object on `context` that can be used as a WeakMap key for metadata
const METADATA = new WeakMap();
function meta(key, value) {
return (_, context) => {
let metadata = METADATA.get(context.metadataKey);
if (!metadata) {
metadata = {};
METADATA.set(context.metadataKey, metadata);
}
metadata[key] = value;
};
}
@meta('a' 'x')
class C {
@meta('b', 'y')
m() {}
}
METADATA.get(C[Symbol.metadata]).a; // 'x'
METADATA.get(C[Symbol.metadata]).b; // 'y'
class D extends C {
@meta('b', 'z')
m() {}
}
METADATA.get(D[Symbol.metadata].parent).a; // `x`
METADATA.get(D[Symbol.metadata]).b; // 'z'
function meta(key, value) {
return (_, context) => {
context.setMetadata(key, value);
};
}
@meta(Symbol.for('a'), 'x')
class C {
@meta(Symbol.for('b'), 'y')
m() {}
}
C[Symbol.metadata][Symbol.for('a')]; // 'x'
C[Symbol.metadata][Symbol.for('b')]; // 'y'
class D extends C {
@meta(Symbol.for('b'), 'z')
m() {}
}
D[Symbol.metadata][Symbol.for('a')]; // 'x'
D[Symbol.metadata][Symbol.for('b')]; // 'z'