feat(53461): Implement decorator metadata proposal (#54657)

This commit is contained in:
Oleksandr T
2023-06-23 17:55:22 +03:00
committed by GitHub
parent f7e4f809ac
commit bc91920cc6
276 changed files with 2926 additions and 973 deletions

View File

@@ -37,6 +37,7 @@ import "./unittests/evaluation/awaiter";
import "./unittests/evaluation/destructuring";
import "./unittests/evaluation/externalModules";
import "./unittests/evaluation/esDecorators";
import "./unittests/evaluation/esDecoratorsMetadata";
import "./unittests/evaluation/forAwaitOf";
import "./unittests/evaluation/forOf";
import "./unittests/evaluation/generator";

View File

@@ -0,0 +1,141 @@
import * as evaluator from "../../_namespaces/evaluator";
import * as ts from "../../_namespaces/ts";
import { ScriptTarget } from "../../_namespaces/ts";
describe("unittests:: evaluation:: esDecoratorsMetadata", () => {
const nodeVersion = new ts.Version(process.versions.node);
const supportsClassStaticBlock = nodeVersion.major >= 16;
const targets = [
// NOTE: Class static blocks weren't supported in Node v14
...(supportsClassStaticBlock ? [ScriptTarget.ES2022] : []),
ScriptTarget.ES2021,
ScriptTarget.ES2015,
];
for (const target of targets) {
const targetName = ts.Debug.formatEnum(target, (ts as any).ScriptTarget);
const options: ts.CompilerOptions = { target };
const exec = (array: TemplateStringsArray) => evaluator.evaluateTypeScript(array[0], options);
describe("examples", () => {
// see https://github.com/tc39/proposal-decorator-metadata
it(`@meta (${targetName})`, () => {
const { output } = exec`
export const output: unknown[] = [];
function meta(key: string, value: string) {
return (_, context) => {
context.metadata[key] = value;
};
}
@meta('a', 'x')
class C {
@meta('b', 'y')
m() { }
}
output.push(C[Symbol.metadata].a);
output.push(C[Symbol.metadata].b);
`;
assert.deepEqual(output, ["x", "y"]);
});
// see https://github.com/tc39/proposal-decorator-metadata#inheritance
it(`inheritance (${targetName})`, () => {
const { output } = exec`
export const output: unknown[] = [];
function meta(key: string, value: string) {
return (_, context) => {
context.metadata[key] = value;
};
}
@meta('a', 'x')
class C {
@meta('b', 'y')
m() {}
}
output.push(C[Symbol.metadata].a);
output.push(C[Symbol.metadata].b);
class D extends C {
@meta('b', 'z')
m() {}
}
output.push(D[Symbol.metadata].a);
output.push(D[Symbol.metadata].b);
`;
assert.deepEqual(output, [
"x",
"y",
"x",
"z",
]);
});
// see https://github.com/tc39/proposal-decorator-metadata#inheritance
it(`inheritance append(${targetName})`, () => {
const { output } = exec`
export const output: unknown[] = [];
function appendMeta(key: string, value: string) {
return (_, context) => {
const existing = context.metadata[key] ?? [];
context.metadata[key] = [...existing, value];
};
}
@appendMeta('a', 'x')
class C { }
@appendMeta('a', 'z')
class D extends C { }
output.push(C[Symbol.metadata].a);
output.push(D[Symbol.metadata].a);
`;
assert.deepEqual(output, [
["x"],
["x", "z"],
]);
});
// see https://github.com/tc39/proposal-decorator-metadata#private-metadata
it(`private metadata (${targetName})`, () => {
const { output } = exec`
export const output: unknown[] = [];
const PRIVATE_METADATA = new WeakMap();
function meta(key: string, value: string) {
return (_, context) => {
let metadata = PRIVATE_METADATA.get(context.metadata);
if (!metadata) {
metadata = {};
PRIVATE_METADATA.set(context.metadata, metadata);
}
metadata[key] = value;
};
}
@meta('a', 'x')
class C {
@meta('b', 'y')
m() { }
}
output.push(PRIVATE_METADATA.get(C[Symbol.metadata]).a);
output.push(PRIVATE_METADATA.get(C[Symbol.metadata]).b);
`;
assert.deepEqual(output, [
"x",
"y",
]);
});
});
}
});