class MyParentTokenClass extends Token {
init(amount, owner) {
const extended = this.constructor != MyParentTokenClass
if (!extended) throw new Error('This contract must be extended');
super.init(amount, owner);
// --- prevent redefining send() in child classes
// basic version (prevent overriding only one method like "send")
// const proto = Object.getPrototypeOf(this);
// if (proto.send !== MyParentTokenClass.prototype.send) {
// throw new Error(`Method 'send' cannot be overridden by class ${this.constructor.name}`);
// }
// advanced version, for ex to prevent overriding all methods
function getDeepPropertyNames(obj) {
const props = new Set(); // set to keep unique names
let current = obj;
while (current && current !== Object.prototype) {
// Get all string properties (including non-enumerable ones)
const ownProps = Object.getOwnPropertyNames(current);
ownProps.forEach(prop => props.add(prop));
// Move one level up the chain
current = Object.getPrototypeOf(current);
}
return Array.from(props);
}
const childProto = Object.getPrototypeOf(this);
const parentProto = Object.getPrototypeOf(childProto);
const childMethods = Object.getOwnPropertyNames(parentProto);
// console.log("childMethods:", childMethods);
const parentMethods = getDeepPropertyNames(MyParentTokenClass.prototype);
// console.log("parentMethods:", parentMethods)
let overriddenMethods = childMethods.filter(method =>
parentMethods.includes(method) && method !== 'constructor'
// && method !== 'init' // unsure if we want to allow overriding init() or not, might depend on case
);
console.log("overriddenMethods:", overriddenMethods);
if (overriddenMethods.includes('send')) {
throw new Error(
`Error: Subclass "${this.constructor.name}" is not allowed to override the critical methods: [${overriddenMethods}]. ` +
`These methods must remain as implemented in the base class.`
);
}
// console.log(`-- No forbidden overrides detected in "${this.constructor.name}". --\n`);
}
}