diff --git a/lib/function_inheritance.js b/lib/function_inheritance.js index bb49c1f..cddf736 100644 --- a/lib/function_inheritance.js +++ b/lib/function_inheritance.js @@ -527,12 +527,46 @@ const defClassMethodForProto = function defClassMethodForProto(fnc) { return defClassMethod(fnc, 'this.prototype'); }; +/** + * Make sure the namespace is configured if it's available + * + * @author Jelle De Loecker + * @since 0.9.3 + * @version 0.9.3 + * + * @param {Function} new_constructor + * @param {Function} parent_constructor + * @param {string} namespace + */ +const ensureNamespace = function ensureNamespace(new_constructor, parent_constructor, namespace) { + + if (!new_constructor) { + return namespace; + } + + if (new_constructor.namespace) { + return namespace; + } + + if (!namespace && typeof parent_constructor == 'function') { + namespace = parent_constructor.namespace; + } + + if (!namespace) { + namespace = ''; + } + + Blast.defineValue(new_constructor, 'namespace', namespace == '@' ? '' : namespace); + + return namespace; +}; + /** * Make one class inherit from the other * * @author Jelle De Loecker * @since 0.1.3 - * @version 0.8.18 + * @version 0.9.3 * * @param {string|Function|Array} _parent Parent class to inherit from * @param {string} _namespace Namespace to store class in @@ -602,18 +636,7 @@ Blast.defineStatic('Function', function inherits(_parent, _namespace, _newConstr } // Set the namespace on the constructor if it's given - if (!newConstructor.namespace) { - - if (!namespace && typeof parentConstructor == 'function') { - namespace = parentConstructor.namespace; - } - - if (!namespace) { - namespace = ''; - } - - Blast.defineValue(newConstructor, 'namespace', namespace == '@' ? '' : namespace); - } + namespace = ensureNamespace(newConstructor, parentConstructor, namespace); if (_do_constitutors == null) { _do_constitutors = true; @@ -783,8 +806,8 @@ Blast.defineStatic('Function', function inherits(_parent, _namespace, _newConstr temp = Fn.create(new_constructor_name, temp); temp.staticChain = newConstructor.staticChain; temp.super = newConstructor.super; - Blast.defineValue(temp, 'namespace', namespace); newConstructor = temp; + ensureNamespace(newConstructor, parentConstructor, namespace); } } @@ -814,9 +837,18 @@ Blast.defineStatic('Function', function inherits(_parent, _namespace, _newConstr replacement_class = class extends parentConstructor {}; } + // Make sure all static properties become "uninherited" + replacement_class.children = null; + replacement_class.staticChain = null; + replacement_class.super = null; + replacement_class.namespace = null; + replacement_class.postInheritors = null; + replacement_class.constitutors = null; + Object.defineProperty(replacement_class, 'name', {value: new_constructor_name}); fallback_constructor = newConstructor; newConstructor = replacement_class; + ensureNamespace(newConstructor, parentConstructor, namespace); } } diff --git a/test/function_inheritance.js b/test/function_inheritance.js index d19f978..2c6c5d2 100644 --- a/test/function_inheritance.js +++ b/test/function_inheritance.js @@ -234,6 +234,8 @@ describe('Inheritance', function() { this.did_test++; } } + + assert.strictEqual(Kak.children, undefined, 'A vanilla ES6 class should not have a static `children` property'); let kak = new Kak(); assert.strictEqual(kak.seen_kak, true); @@ -241,10 +243,21 @@ describe('Inheritance', function() { const Unkaked = Function.inherits(Kak, function Unkaked() { this.seen_unkaked = true; }); + + let counter = 0; + + Unkaked.postInherit(function test() { + this.counter = ++counter; + }); + + assert.strictEqual(Kak.children.length, 1, 'After inheriting, the parent should have a `children` property'); + assert.notStrictEqual(Kak.children, Unkaked.children, 'The parent & child class are sharing the same `children` property!'); + assert.strictEqual(Unkaked.counter, 1); let unkaked = new Unkaked(); assert.strictEqual(unkaked.seen_unkaked, true); assert.strictEqual(unkaked.seen_kak, true); + assert.strictEqual(Unkaked.children?.length, undefined); const DeeperUnkaked = Function.inherits(Unkaked, function DeeperUnkaked() { DeeperUnkaked.super.call(this); @@ -255,6 +268,8 @@ describe('Inheritance', function() { assert.strictEqual(deeper.seen_unkaked, true); assert.strictEqual(deeper.seen_kak, true); assert.strictEqual(deeper.is_deep, true); + assert.strictEqual(Unkaked.children?.length, 1); + assert.strictEqual(DeeperUnkaked.counter, 2); class DeepKak extends Kak { constructor() { @@ -272,6 +287,17 @@ describe('Inheritance', function() { assert.strictEqual(unkaked_child_by_name.seen_unkaked, true); assert.strictEqual(unkaked_child_by_name.seen_kak, true); assert.strictEqual(unkaked_child_by_name.is_deep, true); + assert.strictEqual(UnkakedChildByName.counter, 3); + + const NestedUnkaked = Function.inherits('Unkaked', 'Nested.Unkaked', 'NestedUnkaked'); + assert.strictEqual(NestedUnkaked.namespace, 'Nested.Unkaked'); + assert.strictEqual(DeeperUnkaked.counter, 2); + assert.strictEqual(UnkakedChildByName.counter, 3); + assert.strictEqual(NestedUnkaked.counter, 4); + + const DeepNested = Function.inherits('Nested.Unkaked.NestedUnkaked', 'DeepNested'); + assert.strictEqual(Blast.Classes.Nested.Unkaked.DeepNested, DeepNested); + assert.strictEqual(DeepNested.counter, 5); }); });