UNPKG

3.65 kBJavaScriptView Raw
1const debug = require('debug')('feathers:application');
2const { stripSlashes } = require('@feathersjs/commons');
3
4const Uberproto = require('uberproto');
5const events = require('./events');
6const hooks = require('./hooks');
7const version = require('./version');
8
9const Proto = Uberproto.extend({
10 create: null
11});
12
13const application = {
14 init () {
15 Object.assign(this, {
16 version,
17 methods: [
18 'find', 'get', 'create', 'update', 'patch', 'remove'
19 ],
20 mixins: [],
21 services: {},
22 providers: [],
23 _setup: false,
24 settings: {}
25 });
26
27 this.configure(hooks());
28 this.configure(events());
29 },
30
31 get (name) {
32 return this.settings[name];
33 },
34
35 set (name, value) {
36 this.settings[name] = value;
37 return this;
38 },
39
40 disable (name) {
41 this.settings[name] = false;
42 return this;
43 },
44
45 disabled (name) {
46 return !this.settings[name];
47 },
48
49 enable (name) {
50 this.settings[name] = true;
51 return this;
52 },
53
54 enabled (name) {
55 return !!this.settings[name];
56 },
57
58 configure (fn) {
59 fn.call(this, this);
60
61 return this;
62 },
63
64 service (path, service) {
65 if (typeof service !== 'undefined') {
66 throw new Error('Registering a new service with `app.service(path, service)` is no longer supported. Use `app.use(path, service)` instead.');
67 }
68
69 const location = stripSlashes(path) || '/';
70 const current = this.services[location];
71
72 if (typeof current === 'undefined' && typeof this.defaultService === 'function') {
73 return this.use(location, this.defaultService(location))
74 .service(location);
75 }
76
77 return current;
78 },
79
80 use (path, service, options = {}) {
81 if (typeof path !== 'string') {
82 throw new Error(`'${path}' is not a valid service path.`);
83 }
84
85 const location = stripSlashes(path) || '/';
86 const isSubApp = typeof service.service === 'function' && service.services;
87 const isService = this.methods.concat('setup').some(name => typeof service[name] === 'function');
88
89 if (isSubApp) {
90 const subApp = service;
91
92 Object.keys(subApp.services).forEach(subPath =>
93 this.use(`${location}/${subPath}`, subApp.service(subPath))
94 );
95
96 return this;
97 }
98
99 if (!isService) {
100 throw new Error(`Invalid service object passed for path \`${location}\``);
101 }
102
103 // If the service is already Uberproto'd use it directly
104 const protoService = Proto.isPrototypeOf(service) ? service : Proto.extend(service);
105
106 debug(`Registering new service at \`${location}\``);
107
108 // Add all the mixins
109 this.mixins.forEach(fn => fn.call(this, protoService, location, options));
110
111 if (typeof protoService._setup === 'function') {
112 protoService._setup(this, location);
113 }
114
115 // Run the provider functions to register the service
116 this.providers.forEach(provider =>
117 provider.call(this, protoService, location, options)
118 );
119
120 // If we ran setup already, set this service up explicitly
121 if (this._isSetup && typeof protoService.setup === 'function') {
122 debug(`Setting up service for \`${location}\``);
123 protoService.setup(this, location);
124 }
125
126 this.services[location] = protoService;
127
128 return this;
129 },
130
131 setup () {
132 // Setup each service (pass the app so that they can look up other services etc.)
133 Object.keys(this.services).forEach(path => {
134 const service = this.services[path];
135
136 debug(`Setting up service for \`${path}\``);
137
138 if (typeof service.setup === 'function') {
139 service.setup(this, path);
140 }
141 });
142
143 this._isSetup = true;
144
145 return this;
146 }
147};
148
149module.exports = application;