Skip to content

Commit

Permalink
WIP 13
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Sep 27, 2020
1 parent 308bf8c commit 2c3e5e4
Show file tree
Hide file tree
Showing 3 changed files with 297 additions and 6 deletions.
12 changes: 8 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ const buildPlugin = new Plugin(

// If class has no prototype methods remaining, remove it from prototype chain
const nextProto = Object.getPrototypeOf(proto);
if (previousProto && hasNoProperties(proto)) {
Object.setPrototypeOf(previousProto, nextProto);
if (previousProto && hasNoPropertiesExceptConstructor(proto)) {
Object.setPrototypeOf(previousProto.constructor, nextProto.constructor);
Object.setPrototypeOf(previousProto, nextProto);
} else {
previousProto = proto;
}
Expand Down Expand Up @@ -232,6 +232,10 @@ module.exports = buildPlugin;

// Utility functions

function hasNoProperties(obj) {
return Object.getOwnPropertyNames(obj).length === 0 && Object.getOwnPropertySymbols(obj).length === 0;
function hasNoPropertiesExceptConstructor(obj) {
if (Object.getOwnPropertySymbols(obj).length !== 0) return false;

const keys = Object.getOwnPropertyNames(obj);
if (keys.length === 0) return true;
return keys.length === 1 && keys[0] === 'constructor';
}
290 changes: 288 additions & 2 deletions test/build.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ const {modules, buildAndRun} = require('./support/build.js');

// Tests

let Route, buildPlugin;
let Route, buildPlugin, fsPlugin;
beforeEach(() => {
({Route, buildPlugin} = modules);
({Route, buildPlugin, fsPlugin} = modules);
});

describe('Builds', () => {
Expand Down Expand Up @@ -119,6 +119,94 @@ describe('Builds', () => {
});
});

describe('app route has empty classes deleted', () => {
it('where empty class is top', async () => {
const BuildRoute = Route.extend(buildPlugin),
FsRoute = Route.extend(fsPlugin),
{PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends BuildRoute {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

root = new ExtendedRoute();
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, FsRoute, BuildRoute}
}));

const proto = Object.getPrototypeOf(app);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});

it('where empty class is bottom', async () => {
const {PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends Route {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

const BuildRoute = ExtendedRoute.extend(buildPlugin),
FsRoute = ExtendedRoute.extend(fsPlugin);

root = new BuildRoute();
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, BuildRoute, FsRoute}
}));

const proto = Object.getPrototypeOf(app);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});

it('where empty class is middle', async () => {
const FsRoute = Route.extend(fsPlugin),
{PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends FsRoute {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

const BuildRoute = ExtendedRoute.extend(buildPlugin);

root = new BuildRoute();
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, BuildRoute, FsRoute}
}));

const proto = Object.getPrototypeOf(app);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});
});

it('[PRE_BUILD] method is run on route', async () => {
const {PRE_BUILD} = buildPlugin;
const preBuild = spy(() => {});
Expand Down Expand Up @@ -322,6 +410,204 @@ describe('multiple routes', () => {
});
});

describe('empty classes deleted from', () => {
describe('child route', () => {
it('where empty class is top', async () => {
const BuildRoute = Route.extend(buildPlugin),
FsRoute = Route.extend(fsPlugin),
{PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends BuildRoute {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

root = new ExtendedRoute();
const child = new ExtendedRoute({name: 'child'});
root.attachChild(child);
// const childOfChild = new ExtendedRoute({name: 'childOfChild'});
// child.attachChild(childOfChild);
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, FsRoute, BuildRoute}
}));

const proto = Object.getPrototypeOf(app.children[0]);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});

it('where empty class is bottom', async () => {
const {PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends Route {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

const BuildRoute = ExtendedRoute.extend(buildPlugin),
FsRoute = ExtendedRoute.extend(fsPlugin);

root = new BuildRoute();
const child = new BuildRoute({name: 'child'});
root.attachChild(child);
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, BuildRoute, FsRoute}
}));

const proto = Object.getPrototypeOf(app.children[0]);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});

it('where empty class is middle', async () => {
const FsRoute = Route.extend(fsPlugin),
{PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends FsRoute {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

const BuildRoute = ExtendedRoute.extend(buildPlugin);

root = new BuildRoute();
const child = new BuildRoute({name: 'child'});
root.attachChild(child);
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, BuildRoute, FsRoute}
}));

const proto = Object.getPrototypeOf(app.children[0]);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});
});

describe('nested child route', () => {
it('where empty class is top', async () => {
const BuildRoute = Route.extend(buildPlugin),
FsRoute = Route.extend(fsPlugin),
{PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends BuildRoute {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

root = new ExtendedRoute();
const child = new ExtendedRoute({name: 'child'});
root.attachChild(child);
const childOfChild = new ExtendedRoute({name: 'childOfChild'});
child.attachChild(childOfChild);
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, FsRoute, BuildRoute}
}));

const proto = Object.getPrototypeOf(app.children[0].children[0]);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});

it('where empty class is bottom', async () => {
const {PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends Route {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

const BuildRoute = ExtendedRoute.extend(buildPlugin),
FsRoute = ExtendedRoute.extend(fsPlugin);

root = new BuildRoute();
const child = new BuildRoute({name: 'child'});
root.attachChild(child);
const childOfChild = new BuildRoute({name: 'childOfChild'});
child.attachChild(childOfChild);
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, BuildRoute, FsRoute}
}));

const proto = Object.getPrototypeOf(app.children[0].children[0]);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});

it('where empty class is middle', async () => {
const FsRoute = Route.extend(fsPlugin),
{PRE_BUILD, deleteRouteProperties} = buildPlugin;
class ExtendedRoute extends FsRoute {
_otherMethod() {} // eslint-disable-line class-methods-use-this

[PRE_BUILD]() {
deleteRouteProperties(this, ['_otherMethod']);
}
}

const BuildRoute = ExtendedRoute.extend(buildPlugin);

root = new BuildRoute();
const child = new BuildRoute({name: 'child'});
root.attachChild(child);
const childOfChild = new BuildRoute({name: 'childOfChild'});
child.attachChild(childOfChild);
await root.init();

const {app, classes} = await buildAndRun(root, _app => ({
app: _app,
classes: {Route, BuildRoute, FsRoute}
}));

const proto = Object.getPrototypeOf(app.children[0].children[0]);
expect(proto).toBe(classes.BuildRoute.prototype);
const proto2 = Object.getPrototypeOf(proto);
expect(proto2).toBe(classes.FsRoute.prototype);
const proto3 = Object.getPrototypeOf(proto2);
expect(proto3).toBe(classes.Route.prototype);
});
});
});

describe('[PRE_BUILD] method is run on', () => {
it('child route', async () => {
const {PRE_BUILD} = buildPlugin;
Expand Down
1 change: 1 addition & 0 deletions test/support/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ beforeEach(() => {
jest.isolateModules(() => {
modules.Route = require('@overlook/route');
modules.buildPlugin = require('@overlook/plugin-build');
modules.fsPlugin = require('@overlook/plugin-fs');
modules.startPlugin = require('@overlook/plugin-start');
});
});
Expand Down

0 comments on commit 2c3e5e4

Please sign in to comment.