Repository navigation
Expand file tree
/
Copy pathprotected-sub.js
More file actions
79 lines (64 loc) · 2.18 KB
/
Copy pathprotected-sub.js
File metadata and controls
79 lines (64 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
* Example sub-class with protected-level shared properties
* Author: Brian Katzung <briank@kappacs.com>
*/
import { Base, _GET, _SUB } from './protected-base.js';
export class Sub extends Base {
#_; // Sub's private access to shared protected properties
// Sub-class prototype for protected shared-state object
static __protected = Object.freeze(Object.setPrototypeOf({
logState () {
const [thys, _thys] = [this.__this, this];
if (_thys !== thys.#_) throw new Error('Unauthorized');
console.log('Sub #_', this);
super.logState();
},
get protoSub () { return true; }
}, super.__protected));
constructor () {
super();
// <-- Sub's this.#_ no longer throws
this[_GET](); // Obtain protected property access
// <-- Sub's this.#_ is now populated and available for use
const state = this.#_;
state.sub = true;
}
// Subscribe to #_ in every sub-class needing access
// protected properties
[_SUB] (subFn) {
const subToken = super[_SUB](subFn); // Must be first
return subFn(subToken, (p) => { this.#_ ||= p; }); // Set this.#_ once
}
method () { // Example consumer
const state = this.#_;
// Public props: this.prop
// Protected props: this.#_.prop (or state.prop)
// Private props: this.#prop
}
/*
* A pseudo-protected (publicly visible, but access-controlled) method.
* Callers must supply the callee's private #_ to authenticate.
* This can be called from any class within the same instance (#_
* is shared across all classes), or across instances when the callee is
* instanceof the caller's method class (in which case the caller has
* access to the callee's #_ and can therefore pass it).
*/
gatedMethod (state) {
if (state !== this.#_) throw new Error('Unauthorized method call');
// Caller is now confirmed to be in the class hierarchy for this instance
}
// Example of calling a pseudo-protected method on the same instance
callGatedMethod () {
this.gatedMethod(this.#_);
}
// Example of calling a pseudo-protected method across instances
callOtherGatedMethod (other) {
if (#_ in other) { // brand check
other.gatedMethod(other.#_);
} else {
// Incompatible
}
}
}
Object.freeze(Sub.prototype);
Object.freeze(Sub);