There's been some concern about the trust involved in decorating
private class elements. Decorating a private field or method is
specified to give access to the private name which is declared.
Although this notion of privacy may be defensible in theory, we
take a couple additional precautions to ensure that it's private
in practice:
- #134: PrivateName is a defensive class, which is deeply frozen and
does not permit monkey patching.
- #133: Class decorators get "restricted" PrivateName instances,
which cannot be used to read or write private class elements.
Previously, the idea was that class decorators would be trusted,
enabling class decorators to be used to deliberately grant access to
private fields and methods to things outside of the class. For
example, a @testable decorator could expose all private class elements
to a testing framework.
The new idea is, class decorators are less trusted, and can only see
that private class elements are present, insert or delete them, but
not read or write them. This increases the level of privacy in
practice (e.g., if a decorator is used for wrapping purposes and not
expected to be able to trusted reading private fields), but removes
certain use cases.
This patch enables class decorators to add and remove private elements,
which may be considered to have integrity implications with respect
to usages of private class elements as a "brand". The trust level of
class decorators is intermediate: they are trusted with these branding
rights, but not with the ability to actually read and write everything.
In a follow-on proposal, we could permit class decorators to get
un-restricted private names through a `@trusted: decorator` syntax;
we could also decide to "relax" the restriction on all class
decorators.
The logic here could be used to implement "restricted" private fields
as proposed in #24 (comment)
with the following implementation:
```js
function restricted(privateName) {
let restrictedName;
function classDecorator({[{key}]}) {
restrictedName = key;
}
function elementDecorator(descriptor) {
return {...descriptor, key: privateName};
}
@classDecorator class X {
@elementDecorator x;
}
return restrictedName;
}
```