Skip to content

Commit ddf8821

Browse files
committed
feat(core): Remove Uberproto (#2178)
BREAKING CHANGE: Services no longer extend Uberproto objects and `service.mixin()` is no longer available.
1 parent 6d18065 commit ddf8821

13 files changed

Lines changed: 143 additions & 280 deletions

File tree

package-lock.json

Lines changed: 82 additions & 198 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/adapter-tests/src/methods.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ export default (test: any, app: any, _errors: any, serviceName: string, idProp:
539539
let throwing: any;
540540

541541
before(() => {
542-
throwing = app.service(serviceName).extend({
542+
throwing = Object.assign(Object.create(app.service(serviceName)), {
543543
get store () {
544544
return app.service(serviceName).store;
545545
},

packages/express/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@
5454
"@types/express": "^4.17.9",
5555
"debug": "^4.3.1",
5656
"express": "^4.17.1",
57-
"lodash": "^4.17.20",
58-
"uberproto": "^2.0.6"
57+
"lodash": "^4.17.20"
5958
},
6059
"devDependencies": {
6160
"@feathersjs/authentication": "^5.0.0-pre.1",

packages/express/src/index.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// @ts-ignore
2-
import Proto from 'uberproto';
31
import express, { Express, static as _static, json, raw, text, urlencoded, query } from 'express';
42
import Debug from 'debug';
53
import {
@@ -55,9 +53,10 @@ export default function feathersExpress<T = any> (feathersApp?: FeathersApplicat
5553
throw new Error(`@feathersjs/express requires an instance of a Feathers application version 3.x or later (got ${feathersApp.version || 'unknown'})`);
5654
}
5755

56+
const { use, listen } = expressApp as any;
5857
// An Uberproto mixin that provides the extended functionality
5958
const mixin: any = {
60-
use (location: string) {
59+
use (location: string, ...rest: any[]) {
6160
let service: any;
6261
const middleware = Array.from(arguments).slice(1)
6362
.reduce(function (middleware, arg) {
@@ -81,7 +80,7 @@ export default function feathersExpress<T = any> (feathersApp?: FeathersApplicat
8180
// Check for service (any object with at least one service method)
8281
if (hasMethod(['handle', 'set']) || !hasMethod(this.methods.concat('setup'))) {
8382
debug('Passing app.use call to Express app');
84-
return this._super.apply(this, arguments);
83+
return use.call(this, location, ...rest);
8584
}
8685

8786
debug('Registering service with middleware', middleware);
@@ -91,8 +90,8 @@ export default function feathersExpress<T = any> (feathersApp?: FeathersApplicat
9190
return this;
9291
},
9392

94-
listen () {
95-
const server = this._super.apply(this, arguments);
93+
listen (...args: any[]) {
94+
const server = listen.call(this, ...args);
9695

9796
this.setup(server);
9897
debug('Feathers application listening');
@@ -112,7 +111,7 @@ export default function feathersExpress<T = any> (feathersApp?: FeathersApplicat
112111
}
113112
});
114113

115-
return Proto.mixin(mixin, expressApp);
114+
return Object.assign(expressApp, mixin);
116115
}
117116

118117
if (typeof module !== 'undefined') {

packages/express/src/rest/index.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,10 @@ const HTTP_METHOD = Symbol('@feathersjs/express/rest/HTTP_METHOD');
99

1010
export function httpMethod (verb: any, uris?: any) {
1111
return (method: any) => {
12-
Object.defineProperty(method, HTTP_METHOD, {
13-
enumerable: false,
14-
configurable: true,
15-
writable: false,
16-
value: (Array.isArray(uris) ? uris : [uris])
17-
.reduce(
18-
(result, uri) => ([...result, { verb, uri }]),
19-
method[HTTP_METHOD] || []
20-
)
21-
});
12+
method[HTTP_METHOD] = (Array.isArray(uris) ? uris : [uris]).reduce(
13+
(result, uri) => ([...result, { verb, uri }]),
14+
method[HTTP_METHOD] || []
15+
);
2216

2317
return method;
2418
};

packages/feathers/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
"version": "npm run write-version",
4848
"publish": "npm run reset-version",
4949
"compile": "shx rm -rf lib/ && tsc",
50-
"test": "npm run compile && mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts"
50+
"test": "npm run compile && npm run mocha",
51+
"mocha": "mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts"
5152
},
5253
"engines": {
5354
"node": ">= 12"
@@ -59,8 +60,7 @@
5960
"@feathersjs/commons": "^5.0.0-pre.1",
6061
"@feathersjs/hooks": "^0.6.1",
6162
"debug": "^4.3.1",
62-
"events": "^3.2.0",
63-
"uberproto": "^2.0.6"
63+
"events": "^3.2.0"
6464
},
6565
"devDependencies": {
6666
"@types/mocha": "^8.2.0",

packages/feathers/src/application.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import Debug from 'debug';
22
import { stripSlashes } from '@feathersjs/commons';
33

4-
// @ts-ignore
5-
import Uberproto from 'uberproto';
64
import events from './events';
75
import hooks from './hooks';
86
import version from './version';
97
import { BaseApplication, Service } from './declarations';
108

119
const debug = Debug('feathers:application');
1210

13-
const Proto = Uberproto.extend({
14-
create: null
15-
});
16-
1711
interface AppExtensions {
1812
_isSetup: boolean;
1913
init (): void;
@@ -106,8 +100,9 @@ export default {
106100
throw new Error(`Invalid service object passed for path \`${location}\``);
107101
}
108102

109-
// If the service is already Uberproto'd use it directly
110-
const protoService = Proto.isPrototypeOf(service) ? service : Proto.extend(service);
103+
// Use existing service or create a new object with prototype pointing to original
104+
const isFeathersService = typeof service.hooks === 'function' && (service as any)._serviceEvents;
105+
const protoService = isFeathersService ? service : Object.create(service);
111106

112107
debug(`Registering new service at \`${location}\``);
113108

packages/feathers/src/events.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// @ts-ignore
2-
import Proto from 'uberproto';
31
import { EventEmitter } from 'events';
42
import { HookContext, Service, Application } from './declarations';
53

@@ -32,9 +30,9 @@ export function eventMixin (this: Application, service: Service<any>) {
3230
const isEmitter = typeof service.on === 'function' &&
3331
typeof service.emit === 'function';
3432

35-
// If not, mix it in (the service is always an Uberproto object that has a .mixin)
36-
if (typeof service.mixin === 'function' && !isEmitter) {
37-
service.mixin(EventEmitter.prototype);
33+
// If not, add EventEmitter functionality
34+
if (!isEmitter) {
35+
Object.assign(service, EventEmitter.prototype);
3836
}
3937

4038
// Define non-enumerable properties of
@@ -81,7 +79,7 @@ export default function () {
8179
app.hooks({ finally: eventHook() });
8280

8381
// Make the app an event emitter
84-
Proto.mixin(EventEmitter.prototype, app);
82+
Object.assign(app, EventEmitter.prototype);
8583

8684
app.mixins.push(eventMixin);
8785
};

packages/feathers/src/hooks/index.ts

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,25 +89,29 @@ function withHooks (app: Application, service: Service<any>, methods: string[])
8989
hooksDecorator(service, hookMap);
9090
}
9191

92-
function mixinMethod (this: any) {
93-
const service = this;
94-
const args = Array.from(arguments);
95-
96-
const returnHook = args[args.length - 1] === true || args[args.length - 1] instanceof HookContext
97-
? args.pop() : false;
98-
99-
const hookContext = returnHook instanceof HookContext ? returnHook : this._super.createContext();
100-
101-
return this._super.call(service, ...args, hookContext)
102-
.then(() => returnHook ? hookContext : hookContext.result)
103-
// Handle errors
104-
.catch(() => {
105-
if (typeof hookContext.error !== 'undefined' && typeof hookContext.result === 'undefined') {
106-
return Promise.reject(returnHook ? hookContext : hookContext.error);
107-
} else {
108-
return returnHook ? hookContext : hookContext.result;
109-
}
110-
});
92+
const mixinMethod = (_super: any) => {
93+
const result = function (this: any) {
94+
const service = this;
95+
const args = Array.from(arguments);
96+
97+
const returnHook = args[args.length - 1] === true || args[args.length - 1] instanceof HookContext
98+
? args.pop() : false;
99+
100+
const hookContext = returnHook instanceof HookContext ? returnHook : _super.createContext();
101+
102+
return _super.call(service, ...args, hookContext)
103+
.then(() => returnHook ? hookContext : hookContext.result)
104+
// Handle errors
105+
.catch(() => {
106+
if (typeof hookContext.error !== 'undefined' && typeof hookContext.result === 'undefined') {
107+
return Promise.reject(returnHook ? hookContext : hookContext.error);
108+
} else {
109+
return returnHook ? hookContext : hookContext.result;
110+
}
111+
});
112+
};
113+
114+
return Object.assign(result, _super);
111115
}
112116

113117
// A service mixin that adds `service.hooks()` method and functionality
@@ -116,7 +120,7 @@ const hookMixin = exports.hookMixin = function hookMixin (service: any) {
116120
return;
117121
}
118122

119-
service.methods = Object.getOwnPropertyNames(service)
123+
service.methods = Object.getOwnPropertyNames(Object.getPrototypeOf(service))
120124
.filter(key => typeof service[key] === 'function' && service[key][ACTIVATE_HOOKS])
121125
.reduce((result, methodName) => {
122126
result[methodName] = service[methodName][ACTIVATE_HOOKS];
@@ -143,15 +147,15 @@ const hookMixin = exports.hookMixin = function hookMixin (service: any) {
143147
return mixin;
144148
}
145149

146-
mixin[method] = mixinMethod;
150+
mixin[method] = mixinMethod(service[method]);
147151

148152
return mixin;
149153
}, {} as any);
150154

151155
// Add .hooks method and properties to the service
152156
enableHooks(service, methodNames, app.hookTypes);
153157

154-
service.mixin(mixin);
158+
Object.assign(service, mixin);
155159
};
156160

157161
export default function () {

packages/feathers/src/index.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
1-
// @ts-ignore
2-
import Proto from 'uberproto';
31
import Application from './application';
42
import version from './version';
53
import { Application as ApplicationType } from './declarations'
64

7-
const baseObject = Object.create(null);
8-
95
export default function feathers<ServiceTypes = {}> (): ApplicationType<ServiceTypes> {
10-
const app = Object.create(baseObject);
11-
12-
// Mix in the base application
13-
Proto.mixin(Application, app);
6+
const app = Object.assign({}, Application);
147

158
app.init();
169

17-
return app;
10+
return app as any as ApplicationType<ServiceTypes>;
1811
}
1912

2013
export { version };

0 commit comments

Comments
 (0)