mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-11 10:46:28 -05:00
Decorators normative changes (#52582)
This commit is contained in:
@@ -704,7 +704,7 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
});
|
||||
});
|
||||
// Disabled pending the outcome of https://github.com/tc39/proposal-decorators/issues/494
|
||||
describe.skip(".access", () => {
|
||||
describe(".access", () => {
|
||||
describe("for: class", () => {
|
||||
it("is not set", () => {
|
||||
const { context } = exec`
|
||||
@@ -716,7 +716,7 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
});
|
||||
});
|
||||
describe("for: method", () => {
|
||||
it("is { get }", () => {
|
||||
it("is { has, get }", () => {
|
||||
const { context } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -725,10 +725,11 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
}
|
||||
`;
|
||||
assert.isObject(context.access);
|
||||
assert.hasAllKeys(context.access, ["get"]);
|
||||
assert.hasAllKeys(context.access, ["has", "get"]);
|
||||
assert.isFunction(context.access.has);
|
||||
assert.isFunction(context.access.get);
|
||||
});
|
||||
it("accesses value using 'this'", () => {
|
||||
it("test public element presence via .has", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -736,27 +737,56 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
static method() {}
|
||||
}
|
||||
`;
|
||||
assert.strictEqual(context.access.get.call(C), C.method);
|
||||
|
||||
const obj = { method() {} };
|
||||
assert.strictEqual(context.access.get.call(obj), obj.method);
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isTrue(context.access.has({ method() {} }));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("can access value for private name", () => {
|
||||
const { context, C } = exec`
|
||||
it("test private element presence via .has", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static #method() {}
|
||||
}
|
||||
export class D {
|
||||
static #method() {}
|
||||
}
|
||||
`;
|
||||
assert.isFunction(context.access.get.call(C));
|
||||
|
||||
const obj = { ["#method"]() {} };
|
||||
assert.throws(() => context.access.get.call(obj));
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isFalse(context.access.has(D));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("read public element of argument", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static method() {}
|
||||
}
|
||||
`;
|
||||
assert.strictEqual(context.access.get(C), C.method);
|
||||
const obj = { method() {} };
|
||||
assert.isTrue(context.access.has(obj));
|
||||
assert.strictEqual(context.access.get(obj), obj.method);
|
||||
});
|
||||
it("read private element of argument", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static #method() {}
|
||||
}
|
||||
export class D {
|
||||
static #method() {}
|
||||
}
|
||||
`;
|
||||
assert.isFunction(context.access.get(C));
|
||||
assert.throws(() => context.access.get(D));
|
||||
assert.throws(() => context.access.get({ ["#method"]() {} }));
|
||||
});
|
||||
});
|
||||
describe("for: getter", () => {
|
||||
it("is { get }", () => {
|
||||
it("is { has, get }", () => {
|
||||
const { context } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -765,10 +795,11 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
}
|
||||
`;
|
||||
assert.isObject(context.access);
|
||||
assert.hasAllKeys(context.access, ["get"]);
|
||||
assert.hasAllKeys(context.access, ["has", "get"]);
|
||||
assert.isFunction(context.access.has);
|
||||
assert.isFunction(context.access.get);
|
||||
});
|
||||
it("accesses value using 'this'", () => {
|
||||
it("test public element presence via .has", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -776,27 +807,56 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
static get x() { return 1; }
|
||||
}
|
||||
`;
|
||||
assert.strictEqual(context.access.get.call(C), 1);
|
||||
|
||||
const obj = { x: 2 };
|
||||
assert.strictEqual(context.access.get.call(obj), 2);
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isTrue(context.access.has({
|
||||
get x() { return 2; }
|
||||
}));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("can access value for private name", () => {
|
||||
it("test private element presence via .has", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static #method() {}
|
||||
}
|
||||
export class D {
|
||||
static #method() {}
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isFalse(context.access.has(D));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("read public element of argument", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static get x() { return 1; }
|
||||
}
|
||||
`;
|
||||
assert.strictEqual(context.access.get(C), 1);
|
||||
assert.strictEqual(context.access.get({ x: 2 }), 2);
|
||||
});
|
||||
it("read private element of argument", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static get #x() { return 1; }
|
||||
}
|
||||
export class D {
|
||||
static get #x() { return 1; }
|
||||
}
|
||||
`;
|
||||
assert.strictEqual(context.access.get.call(C), 1);
|
||||
|
||||
const obj = { "#x": 2 };
|
||||
assert.throws(() => context.access.get.call(obj));
|
||||
assert.strictEqual(context.access.get(C), 1);
|
||||
assert.throws(() => context.access.get(D));
|
||||
assert.throws(() => context.access.get({ "#x": 2 }));
|
||||
});
|
||||
});
|
||||
describe("for: setter", () => {
|
||||
it("is { set }", () => {
|
||||
it("is { has, set }", () => {
|
||||
const { context } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -805,10 +865,38 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
}
|
||||
`;
|
||||
assert.isObject(context.access);
|
||||
assert.hasAllKeys(context.access, ["set"]);
|
||||
assert.hasAllKeys(context.access, ["has", "set"]);
|
||||
assert.isFunction(context.access.has);
|
||||
assert.isFunction(context.access.set);
|
||||
});
|
||||
it("accesses value using 'this'", () => {
|
||||
it("test public element presence via .has", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static set x(v: number) { }
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isTrue(context.access.has({ x: 2 }));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("test private element presence via .has", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static set #x(v: number) { }
|
||||
}
|
||||
export class D {
|
||||
static set #x(v: number) { }
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isFalse(context.access.has(D));
|
||||
assert.isFalse(context.access.has({ "#x": 2 }));
|
||||
});
|
||||
it("write public element of argument", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -817,29 +905,31 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
static y: number;
|
||||
}
|
||||
`;
|
||||
context.access.set.call(C, 1);
|
||||
context.access.set(C, 1);
|
||||
assert.strictEqual(C.y, 1);
|
||||
|
||||
const obj = { x: 2 };
|
||||
context.access.set.call(obj, 3);
|
||||
context.access.set(obj, 3);
|
||||
assert.strictEqual(obj.x, 3);
|
||||
});
|
||||
it("can access value for private name", () => {
|
||||
const { context, C } = exec`
|
||||
it("write private element of argument", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static set #x(v: number) {}
|
||||
}
|
||||
export class D {
|
||||
static set #x(v: number) {}
|
||||
}
|
||||
`;
|
||||
context.access.set.call(C, 1);
|
||||
|
||||
const obj = { "#x": 2 };
|
||||
assert.throws(() => context.access.set.call(obj, 3));
|
||||
context.access.set(C, 1);
|
||||
assert.throws(() => context.access.set(D, 3));
|
||||
assert.throws(() => context.access.set({ "#x": 2 }, 3));
|
||||
});
|
||||
});
|
||||
describe("for: field", () => {
|
||||
it("is { get, set }", () => {
|
||||
it("is { has, get, set }", () => {
|
||||
const { context } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -848,11 +938,39 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
}
|
||||
`;
|
||||
assert.isObject(context.access);
|
||||
assert.hasAllKeys(context.access, ["get", "set"]);
|
||||
assert.hasAllKeys(context.access, ["has", "get", "set"]);
|
||||
assert.isFunction(context.access.has);
|
||||
assert.isFunction(context.access.get);
|
||||
assert.isFunction(context.access.set);
|
||||
});
|
||||
it("accesses value using 'this'", () => {
|
||||
it("test public element presence via .has", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static x: number = 1;
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isTrue(context.access.has({ x: 2 }));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("test private element presence via .has", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static #x: number = 1;
|
||||
}
|
||||
export class D {
|
||||
static #x: number = 1;
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isFalse(context.access.has(D));
|
||||
assert.isFalse(context.access.has({ "#x": 2 }));
|
||||
});
|
||||
it("read/write public element of argument", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -861,36 +979,41 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
}
|
||||
`;
|
||||
|
||||
assert.strictEqual(context.access.get.call(C), 1);
|
||||
context.access.set.call(C, 2);
|
||||
assert.strictEqual(context.access.get(C), 1);
|
||||
context.access.set(C, 2);
|
||||
assert.strictEqual(C.x, 2);
|
||||
|
||||
const obj = { x: 2 };
|
||||
assert.strictEqual(context.access.get.call(obj), 2);
|
||||
context.access.set.call(obj, 3);
|
||||
assert.strictEqual(context.access.get(obj), 2);
|
||||
context.access.set(obj, 3);
|
||||
assert.strictEqual(obj.x, 3);
|
||||
});
|
||||
it("can access value for private name", () => {
|
||||
const { context, C } = exec`
|
||||
it("read/write private element of argument", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static #x: number = 1;
|
||||
static getX() { return this.#x; }
|
||||
}
|
||||
export class D {
|
||||
static #x: number = 1;
|
||||
}
|
||||
`;
|
||||
|
||||
assert.strictEqual(context.access.get.call(C), 1);
|
||||
context.access.set.call(C, 2);
|
||||
assert.strictEqual(context.access.get(C), 1);
|
||||
context.access.set(C, 2);
|
||||
assert.strictEqual(C.getX(), 2);
|
||||
|
||||
const obj = { "#x": 2 };
|
||||
assert.throws(() => context.access.get.call(obj));
|
||||
assert.throws(() => context.access.set.call(obj, 3));
|
||||
assert.throws(() => context.access.get(D));
|
||||
assert.throws(() => context.access.set(D, 3));
|
||||
|
||||
assert.throws(() => context.access.get({ "#x": 2 }));
|
||||
assert.throws(() => context.access.set({ "#x": 2 }, 3));
|
||||
});
|
||||
});
|
||||
describe("for: auto-accessor", () => {
|
||||
it("is { get, set }", () => {
|
||||
it("is { has, get, set }", () => {
|
||||
const { context } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -898,11 +1021,39 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
static accessor x: number;
|
||||
}
|
||||
`;
|
||||
assert.hasAllKeys(context.access, ["get", "set"]);
|
||||
assert.hasAllKeys(context.access, ["has", "get", "set"]);
|
||||
assert.isFunction(context.access.has);
|
||||
assert.isFunction(context.access.get);
|
||||
assert.isFunction(context.access.set);
|
||||
});
|
||||
it("accesses value using 'this'", () => {
|
||||
it("test public element presence via .has", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static accessor x: number = 1;
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isTrue(context.access.has({ x: 2 }));
|
||||
assert.isFalse(context.access.has({ }));
|
||||
});
|
||||
it("test private element presence via .has", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static accessor #x: number = 1;
|
||||
}
|
||||
export class D {
|
||||
static accessor #x: number = 1;
|
||||
}
|
||||
`;
|
||||
assert.isTrue(context.access.has(C));
|
||||
assert.isFalse(context.access.has(D));
|
||||
assert.isFalse(context.access.has({ "#x": 2 }));
|
||||
});
|
||||
it("read/write public element of argument", () => {
|
||||
const { context, C } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@@ -911,32 +1062,37 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
}
|
||||
`;
|
||||
|
||||
assert.strictEqual(context.access.get.call(C), 1);
|
||||
context.access.set.call(C, 2);
|
||||
assert.strictEqual(context.access.get(C), 1);
|
||||
context.access.set(C, 2);
|
||||
assert.strictEqual(C.x, 2);
|
||||
|
||||
const obj = { x: 2 };
|
||||
assert.strictEqual(context.access.get.call(obj), 2);
|
||||
context.access.set.call(obj, 3);
|
||||
assert.strictEqual(context.access.get(obj), 2);
|
||||
context.access.set(obj, 3);
|
||||
assert.strictEqual(obj.x, 3);
|
||||
});
|
||||
it("can access value for private name", () => {
|
||||
const { context, C } = exec`
|
||||
it("read/write private element of argument", () => {
|
||||
const { context, C, D } = exec`
|
||||
export let context;
|
||||
export class C {
|
||||
@((t, c) => { context = c; })
|
||||
static accessor #x: number = 1;
|
||||
static getX() { return this.#x; }
|
||||
}
|
||||
export class D {
|
||||
static accessor #x: number = 1;
|
||||
}
|
||||
`;
|
||||
|
||||
assert.strictEqual(context.access.get.call(C), 1);
|
||||
context.access.set.call(C, 2);
|
||||
assert.strictEqual(context.access.get(C), 1);
|
||||
context.access.set(C, 2);
|
||||
assert.strictEqual(C.getX(), 2);
|
||||
|
||||
const obj = { "#x": 2 };
|
||||
assert.throws(() => context.access.get.call(obj));
|
||||
assert.throws(() => context.access.set.call(obj, 3));
|
||||
assert.throws(() => context.access.get(D));
|
||||
assert.throws(() => context.access.set(D, 3));
|
||||
|
||||
assert.throws(() => context.access.get({ "#x": 2 }));
|
||||
assert.throws(() => context.access.set({ "#x": 2 }, 3));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2223,13 +2379,12 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
});
|
||||
|
||||
// see https://github.com/tc39/proposal-decorators#access-and-metadata-sidechanneling
|
||||
// Disabled, pending the outcome of https://github.com/tc39/proposal-decorators/issues/494
|
||||
it.skip(`dependency injection (${targetName})`, () => {
|
||||
it(`dependency injection (${targetName})`, () => {
|
||||
const { result } = exec`
|
||||
const INJECTIONS = new WeakMap<object, { injectionKey: string, set: (this: any, value: any) => void }[]>();
|
||||
const INJECTIONS = new WeakMap<object, { injectionKey: string, set: (object: any, value: any) => void }[]>();
|
||||
|
||||
function createInjections() {
|
||||
const injections: { injectionKey: string, set: (this: any, value: any) => void }[] = [];
|
||||
const injections: { injectionKey: string, set: (object: any, value: any) => void }[] = [];
|
||||
|
||||
function injectable<T extends new (...args: any) => any>(Class: T, context: ClassDecoratorContext<T>) {
|
||||
INJECTIONS.set(Class, injections);
|
||||
@@ -2259,7 +2414,7 @@ describe("unittests:: evaluation:: esDecorators", () => {
|
||||
let instance = new Class();
|
||||
|
||||
for (const { injectionKey, set } of INJECTIONS.get(Class) || []) {
|
||||
set.call(instance, this.lookup(injectionKey));
|
||||
set(instance, this.lookup(injectionKey));
|
||||
}
|
||||
|
||||
return instance;
|
||||
|
||||
Reference in New Issue
Block a user