5htp 0.5.9 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/index.ts +30 -36
- package/compiler/common/babel/plugins/injection-dependances/index.ts +3 -1
- package/compiler/common/babel/plugins/services.ts +183 -101
- package/compiler/common/babel/routes/imports.ts +2 -2
- package/compiler/common/babel/routes/routes.ts +142 -47
- package/compiler/index.ts +156 -78
- package/package.json +1 -1
- package/paths.ts +1 -1
package/app/index.ts
CHANGED
|
@@ -20,6 +20,23 @@ import type { TEnvConfig } from '../../core/server/app/container/config';
|
|
|
20
20
|
|
|
21
21
|
export type TAppSide = 'server' | 'client'
|
|
22
22
|
|
|
23
|
+
type TServiceSetup = {
|
|
24
|
+
id: string,
|
|
25
|
+
name: string,
|
|
26
|
+
config: {},
|
|
27
|
+
subservices: TServiceSubservices,
|
|
28
|
+
type: 'service.setup'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type TServiceRef = {
|
|
32
|
+
refTo: string,
|
|
33
|
+
type: 'service.ref'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type TServiceSubservices = {
|
|
37
|
+
[key: string]: TServiceSetup | TServiceRef
|
|
38
|
+
}
|
|
39
|
+
|
|
23
40
|
/*----------------------------------
|
|
24
41
|
- SERVICE
|
|
25
42
|
----------------------------------*/
|
|
@@ -110,7 +127,7 @@ export class App {
|
|
|
110
127
|
|
|
111
128
|
public registered = {}
|
|
112
129
|
|
|
113
|
-
public use( referenceName: string ) {
|
|
130
|
+
public use( referenceName: string ): TServiceRef {
|
|
114
131
|
|
|
115
132
|
// We don't check because all service are not regstered when we register subservices
|
|
116
133
|
/*if (this.registered[referenceName] === undefined) {
|
|
@@ -119,37 +136,38 @@ export class App {
|
|
|
119
136
|
|
|
120
137
|
return {
|
|
121
138
|
refTo: referenceName,
|
|
139
|
+
type: 'service.ref'
|
|
122
140
|
}
|
|
123
141
|
}
|
|
124
142
|
|
|
125
143
|
public setup(...args: [
|
|
126
144
|
// { user: app.setup('Core/User') }
|
|
127
|
-
|
|
128
|
-
serviceConfig?:
|
|
129
|
-
serviceSubservices?: TServiceSubservices
|
|
145
|
+
servicePath: string,
|
|
146
|
+
serviceConfig?: {},
|
|
130
147
|
] | [
|
|
131
148
|
// app.setup('User', 'Core/User')
|
|
132
149
|
serviceName: string,
|
|
133
|
-
|
|
134
|
-
serviceConfig?:
|
|
135
|
-
|
|
136
|
-
]) {
|
|
150
|
+
servicePath: string,
|
|
151
|
+
serviceConfig?: {},
|
|
152
|
+
]): TServiceSetup {
|
|
137
153
|
|
|
138
154
|
// Registration to app root
|
|
139
155
|
if (typeof args[1] === 'string') {
|
|
140
156
|
|
|
141
|
-
const [name, id, config
|
|
157
|
+
const [name, id, config] = args;
|
|
142
158
|
|
|
143
|
-
const service = { id, name, config,
|
|
159
|
+
const service = { id, name, config, type: 'service.setup' } as TServiceSetup
|
|
144
160
|
|
|
145
161
|
this.registered[name] = service;
|
|
146
162
|
|
|
163
|
+
return service;
|
|
164
|
+
|
|
147
165
|
// Scoped to a parent service
|
|
148
166
|
} else {
|
|
149
167
|
|
|
150
|
-
const [id, config
|
|
168
|
+
const [id, config] = args;
|
|
151
169
|
|
|
152
|
-
const service = { id, config,
|
|
170
|
+
const service = { id, config, type: 'service.setup' } as TServiceSetup
|
|
153
171
|
|
|
154
172
|
return service;
|
|
155
173
|
}
|
|
@@ -157,9 +175,6 @@ export class App {
|
|
|
157
175
|
|
|
158
176
|
public async warmup() {
|
|
159
177
|
|
|
160
|
-
console.log("env", this.env);
|
|
161
|
-
|
|
162
|
-
|
|
163
178
|
// Require all config files in @/server/config
|
|
164
179
|
const configDir = path.resolve(cli.paths.appRoot, 'server', 'config');
|
|
165
180
|
const configFiles = fs.readdirSync(configDir);
|
|
@@ -167,27 +182,6 @@ export class App {
|
|
|
167
182
|
console.log("Loading config file:", configFile);
|
|
168
183
|
require( path.resolve(configDir, configFile) );
|
|
169
184
|
}
|
|
170
|
-
|
|
171
|
-
// Wait 2 seconds
|
|
172
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
173
|
-
|
|
174
|
-
// Load subservices
|
|
175
|
-
// for (const serviceName in this.registered) {
|
|
176
|
-
// const service = this.registered[serviceName];
|
|
177
|
-
|
|
178
|
-
// const subservices = {}
|
|
179
|
-
// if (service.subservices) {
|
|
180
|
-
// const list = service.subservices( this.registered );
|
|
181
|
-
// for (const subservice of list) {
|
|
182
|
-
|
|
183
|
-
// subservices[subservice.name] = list[];
|
|
184
|
-
|
|
185
|
-
// }
|
|
186
|
-
// }
|
|
187
|
-
// service.subservices = subservices;
|
|
188
|
-
// }
|
|
189
|
-
|
|
190
|
-
// console.log("SERVICES", this.registered);
|
|
191
185
|
}
|
|
192
186
|
}
|
|
193
187
|
|
|
@@ -23,6 +23,8 @@ module.exports = {
|
|
|
23
23
|
]
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
const routerMethods = ['get', 'post', 'put', 'delete', 'patch'];
|
|
27
|
+
|
|
26
28
|
/*----------------------------------
|
|
27
29
|
- PLUGIN
|
|
28
30
|
----------------------------------*/
|
|
@@ -133,7 +135,7 @@ function Plugin (babel) {
|
|
|
133
135
|
&&
|
|
134
136
|
i.node.callee.property.type === 'Identifier'
|
|
135
137
|
&&
|
|
136
|
-
|
|
138
|
+
routerMethods.includes(i.node.callee.property.name)
|
|
137
139
|
&&
|
|
138
140
|
i.node.arguments.length >= 2 // url + au moins 1 middleware
|
|
139
141
|
&&
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
// Npm
|
|
6
6
|
import * as types from '@babel/types'
|
|
7
|
-
import type { PluginObj } from '@babel/core';
|
|
7
|
+
import type { NodePath, PluginObj } from '@babel/core';
|
|
8
|
+
import generate from '@babel/generator';
|
|
8
9
|
|
|
9
10
|
// Core
|
|
10
11
|
import cli from '@cli';
|
|
@@ -24,12 +25,19 @@ type TOptions = {
|
|
|
24
25
|
* Extended source type: now includes "models"
|
|
25
26
|
* so we can differentiate how we rewrite references.
|
|
26
27
|
*/
|
|
27
|
-
type TImportSource = 'container' | '
|
|
28
|
+
type TImportSource = 'container' | 'services' | 'models' | 'request';
|
|
28
29
|
|
|
29
30
|
module.exports = (options: TOptions) => (
|
|
30
31
|
[Plugin, options]
|
|
31
32
|
)
|
|
32
33
|
|
|
34
|
+
type TImportedIndex = {
|
|
35
|
+
local: string,
|
|
36
|
+
imported: string, // The original “imported” name
|
|
37
|
+
references: NodePath<types.Node>[], // reference paths
|
|
38
|
+
source: TImportSource // container | application | models
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
/*----------------------------------
|
|
34
42
|
- PLUGIN
|
|
35
43
|
----------------------------------*/
|
|
@@ -54,8 +62,6 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
54
62
|
this.app.Models.client.MyModel.someCall();
|
|
55
63
|
|
|
56
64
|
Processed files:
|
|
57
|
-
@/server/config
|
|
58
|
-
@/server/routes
|
|
59
65
|
@/server/services
|
|
60
66
|
*/
|
|
61
67
|
|
|
@@ -68,42 +74,65 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
68
74
|
|
|
69
75
|
// Count how many total imports we transform
|
|
70
76
|
importedCount: number,
|
|
77
|
+
routeMethods: string[],
|
|
71
78
|
|
|
72
79
|
// For every local identifier, store info about how it should be rewritten
|
|
73
|
-
|
|
74
|
-
[localName: string]:
|
|
75
|
-
imported: string, // The original “imported” name
|
|
76
|
-
bindings: any, // reference paths
|
|
77
|
-
source: TImportSource // container | application | models
|
|
78
|
-
}
|
|
80
|
+
imported: {
|
|
81
|
+
[localName: string]: TImportedIndex
|
|
79
82
|
}
|
|
80
|
-
|
|
81
|
-
// Tally how many references per kind
|
|
82
|
-
bySource: { [s in TImportSource]: number }
|
|
83
83
|
}> = {
|
|
84
84
|
|
|
85
85
|
pre(state) {
|
|
86
86
|
this.filename = state.opts.filename as string;
|
|
87
|
-
this.processFile = (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
||
|
|
92
|
-
this.filename.startsWith(cli.paths.appRoot + '/server/services')
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
this.importedReferences = {};
|
|
96
|
-
this.bySource = {
|
|
97
|
-
container: 0,
|
|
98
|
-
application: 0,
|
|
99
|
-
models: 0
|
|
100
|
-
};
|
|
87
|
+
this.processFile = this.filename.startsWith(cli.paths.appRoot + '/server/services');
|
|
88
|
+
|
|
89
|
+
this.imported = {};
|
|
90
|
+
|
|
101
91
|
this.importedCount = 0;
|
|
102
92
|
this.debug = debug || false;
|
|
93
|
+
|
|
94
|
+
this.routeMethods = [];
|
|
103
95
|
},
|
|
104
96
|
|
|
105
97
|
visitor: {
|
|
106
98
|
|
|
99
|
+
// Detect decored methods before other plugins remove decorators
|
|
100
|
+
Program(path) {
|
|
101
|
+
|
|
102
|
+
if (!this.processFile) return;
|
|
103
|
+
|
|
104
|
+
// Traverse the AST within the Program node
|
|
105
|
+
path.traverse({
|
|
106
|
+
ClassMethod: (subPath) => {
|
|
107
|
+
const { node } = subPath;
|
|
108
|
+
if (!node.decorators || node.key.type !== 'Identifier') return;
|
|
109
|
+
|
|
110
|
+
for (const decorator of node.decorators) {
|
|
111
|
+
|
|
112
|
+
const isRoute = (
|
|
113
|
+
// Handles the case of @Route without parameters
|
|
114
|
+
(
|
|
115
|
+
t.isIdentifier(decorator.expression) && decorator.expression.name === 'Route'
|
|
116
|
+
)
|
|
117
|
+
||
|
|
118
|
+
// Handles the case of @Route() with parameters
|
|
119
|
+
(
|
|
120
|
+
t.isCallExpression(decorator.expression) &&
|
|
121
|
+
t.isIdentifier(decorator.expression.callee) &&
|
|
122
|
+
decorator.expression.callee.name === 'Route'
|
|
123
|
+
)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (!isRoute) continue;
|
|
127
|
+
|
|
128
|
+
const methodName = node.key.name;
|
|
129
|
+
this.routeMethods.push( methodName );
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
|
|
107
136
|
/**
|
|
108
137
|
* Detect import statements from '@app' or '@models'
|
|
109
138
|
*/
|
|
@@ -111,7 +140,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
111
140
|
if (!this.processFile) return;
|
|
112
141
|
|
|
113
142
|
const source = path.node.source.value;
|
|
114
|
-
if (source !== '@app' && source !== '@models') {
|
|
143
|
+
if (source !== '@app' && source !== '@models' && source !== '@request') {
|
|
115
144
|
return;
|
|
116
145
|
}
|
|
117
146
|
|
|
@@ -123,25 +152,32 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
123
152
|
this.importedCount++;
|
|
124
153
|
|
|
125
154
|
let importSource: TImportSource;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
155
|
+
switch (source) {
|
|
156
|
+
case '@app':
|
|
157
|
+
// Distinguish whether it's a container service or an application service
|
|
158
|
+
if (app.containerServices.includes(specifier.imported.name)) {
|
|
159
|
+
importSource = 'container';
|
|
160
|
+
} else {
|
|
161
|
+
importSource = 'services';
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
case '@request':
|
|
165
|
+
importSource = 'request';
|
|
166
|
+
break;
|
|
167
|
+
case '@models':
|
|
168
|
+
// source === '@models'
|
|
169
|
+
importSource = 'models';
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
throw new Error(`Unknown import source: ${source}`);
|
|
136
173
|
}
|
|
137
174
|
|
|
138
|
-
this.
|
|
175
|
+
this.imported[specifier.local.name] = {
|
|
176
|
+
local: specifier.local.name,
|
|
139
177
|
imported: specifier.imported.name,
|
|
140
|
-
|
|
178
|
+
references: path.scope.bindings[specifier.local.name].referencePaths,
|
|
141
179
|
source: importSource
|
|
142
180
|
};
|
|
143
|
-
|
|
144
|
-
this.bySource[importSource]++;
|
|
145
181
|
}
|
|
146
182
|
|
|
147
183
|
// Remove the original import line(s) and replace with any needed new import
|
|
@@ -151,7 +187,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
151
187
|
|
|
152
188
|
// If this line had container references, add a default import for container
|
|
153
189
|
// Example: import container from '<root>/server/app/container'
|
|
154
|
-
if (source === '@app'
|
|
190
|
+
if (source === '@app') {
|
|
155
191
|
replaceWith.push(
|
|
156
192
|
t.importDeclaration(
|
|
157
193
|
[t.importDefaultSpecifier(t.identifier('container'))],
|
|
@@ -167,78 +203,124 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
167
203
|
path.replaceWithMultiple(replaceWith);
|
|
168
204
|
},
|
|
169
205
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
*/
|
|
173
|
-
Identifier(path) {
|
|
174
|
-
if (!this.processFile || this.importedCount === 0) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
206
|
+
// This visitor fires for every class method.
|
|
207
|
+
ClassMethod(path) {
|
|
177
208
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (!ref || !ref.bindings) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
209
|
+
// Must be a server service
|
|
210
|
+
if (!this.processFile || path.replaced) return;
|
|
183
211
|
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
212
|
+
// Must have a method name
|
|
213
|
+
if (path.node.key.type !== 'Identifier') return;
|
|
214
|
+
|
|
215
|
+
// Init context
|
|
216
|
+
const methodName = path.node.key.name;
|
|
217
|
+
let params = path.node.params;
|
|
218
|
+
|
|
219
|
+
// Prefix references
|
|
220
|
+
path.traverse({ Identifier: (subPath) => {
|
|
221
|
+
|
|
222
|
+
const { node } = subPath;
|
|
223
|
+
const name = node.name;
|
|
224
|
+
const ref = this.imported[name];
|
|
225
|
+
if (!ref || !ref.references) {
|
|
226
|
+
return;
|
|
190
227
|
}
|
|
191
|
-
}
|
|
192
|
-
if (!foundBinding) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
228
|
|
|
196
|
-
|
|
197
|
-
|
|
229
|
+
// Find a specific binding that hasn't been replaced yet
|
|
230
|
+
const foundBinding = ref.references.find(binding => {
|
|
231
|
+
return subPath.getPathLocation() === binding.getPathLocation();
|
|
232
|
+
});
|
|
198
233
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
else if (ref.source === 'application') {
|
|
211
|
-
// this.app.[identifier]
|
|
212
|
-
// e.g. this.app.MyService
|
|
213
|
-
path.replaceWith(
|
|
214
|
-
t.memberExpression(
|
|
234
|
+
if (!foundBinding || foundBinding.replaced)
|
|
235
|
+
return;
|
|
236
|
+
|
|
237
|
+
// Mark as replaced to avoid loops
|
|
238
|
+
foundBinding.replaced = true;
|
|
239
|
+
|
|
240
|
+
// Based on the source, replace the identifier with the proper MemberExpression
|
|
241
|
+
if (ref.source === 'container') {
|
|
242
|
+
// container.[identifier]
|
|
243
|
+
// e.g. container.Environment
|
|
244
|
+
subPath.replaceWith(
|
|
215
245
|
t.memberExpression(
|
|
216
|
-
t.
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
246
|
+
t.identifier('container'),
|
|
247
|
+
subPath.node
|
|
248
|
+
)
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
else if (ref.source === 'services') {
|
|
252
|
+
// this.app.[identifier]
|
|
253
|
+
// e.g. this.app.MyService
|
|
254
|
+
subPath.replaceWith(
|
|
255
|
+
t.memberExpression(
|
|
256
|
+
t.memberExpression(
|
|
257
|
+
t.thisExpression(),
|
|
258
|
+
t.identifier('app')
|
|
259
|
+
),
|
|
260
|
+
subPath.node
|
|
261
|
+
)
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
else if (ref.source === 'models') {
|
|
265
|
+
// this.app.Models.client.[identifier]
|
|
266
|
+
// e.g. this.app.Models.client.MyModel
|
|
267
|
+
subPath.replaceWith(
|
|
228
268
|
t.memberExpression(
|
|
229
269
|
t.memberExpression(
|
|
230
270
|
t.memberExpression(
|
|
231
|
-
t.
|
|
232
|
-
|
|
271
|
+
t.memberExpression(
|
|
272
|
+
t.thisExpression(),
|
|
273
|
+
t.identifier('app')
|
|
274
|
+
),
|
|
275
|
+
t.identifier('Models')
|
|
233
276
|
),
|
|
234
|
-
t.identifier('
|
|
277
|
+
t.identifier('client')
|
|
235
278
|
),
|
|
236
|
-
|
|
237
|
-
)
|
|
238
|
-
|
|
279
|
+
subPath.node
|
|
280
|
+
)
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
else if (ref.source === 'request') {
|
|
284
|
+
// this.app.Models.client.[identifier]
|
|
285
|
+
// e.g. this.app.Models.client.MyModel
|
|
286
|
+
subPath.replaceWith(
|
|
287
|
+
t.memberExpression(
|
|
288
|
+
t.identifier('context'),
|
|
289
|
+
subPath.node
|
|
290
|
+
)
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
} });
|
|
295
|
+
|
|
296
|
+
if (
|
|
297
|
+
this.routeMethods.includes(methodName)
|
|
298
|
+
&&
|
|
299
|
+
path.node.params.length < 2
|
|
300
|
+
) {
|
|
301
|
+
|
|
302
|
+
// Expose router context variable via the second parameter
|
|
303
|
+
params = [
|
|
304
|
+
path.node.params[0] || t.objectPattern([]),
|
|
305
|
+
t.identifier('context'),
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
// Apply changes
|
|
309
|
+
path.replaceWith(
|
|
310
|
+
t.classMethod(
|
|
311
|
+
path.node.kind,
|
|
312
|
+
path.node.key,
|
|
313
|
+
params,
|
|
314
|
+
path.node.body,
|
|
315
|
+
false,
|
|
316
|
+
false,
|
|
317
|
+
false,
|
|
318
|
+
path.node.async
|
|
239
319
|
)
|
|
240
320
|
);
|
|
241
321
|
}
|
|
322
|
+
|
|
323
|
+
//console.log("ROUTE METHOD", this.filename, methodName, generate(path.node).code);
|
|
242
324
|
}
|
|
243
325
|
}
|
|
244
326
|
};
|
|
@@ -109,10 +109,10 @@ module.exports = (app: App, side: TAppSide, dev: boolean): ImportTransformer =>
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
console.log( generate(t.variableDeclaration("const", [t.variableDeclarator(
|
|
112
|
+
/*console.log( generate(t.variableDeclaration("const", [t.variableDeclarator(
|
|
113
113
|
t.identifier(request.imported.name),
|
|
114
114
|
t.objectExpression(pageLoaders)
|
|
115
|
-
)])).code )
|
|
115
|
+
)])).code );*/
|
|
116
116
|
|
|
117
117
|
return [
|
|
118
118
|
...imports,
|
|
@@ -42,19 +42,21 @@ module.exports = (options: TOptions) => (
|
|
|
42
42
|
const clientServices = ['Router'];
|
|
43
43
|
// Others will be called via app.<Service> (backend) or api.post(<path>, <params>) (frontend)
|
|
44
44
|
|
|
45
|
+
const routerMethods = ['get', 'post', 'put', 'delete', 'patch'];
|
|
46
|
+
|
|
45
47
|
/*----------------------------------
|
|
46
48
|
- PLUGIN
|
|
47
49
|
----------------------------------*/
|
|
48
50
|
function Plugin(babel, { app, side, debug }: TOptions) {
|
|
49
51
|
|
|
50
|
-
debug = true;
|
|
52
|
+
//debug = true;
|
|
51
53
|
|
|
52
54
|
const t = babel.types as typeof types;
|
|
53
55
|
|
|
54
56
|
/*
|
|
55
57
|
- Wrap route.get(...) with (app: Application) => { }
|
|
56
58
|
- Inject chunk ID into client route options
|
|
57
|
-
- Transform
|
|
59
|
+
- Transform api.fetch:
|
|
58
60
|
|
|
59
61
|
Input:
|
|
60
62
|
const { stats } = api.fetch({
|
|
@@ -83,7 +85,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
83
85
|
// Replace by: nothing
|
|
84
86
|
ImportDeclaration(path) {
|
|
85
87
|
|
|
86
|
-
const shouldTransformImports = this.file.process
|
|
88
|
+
const shouldTransformImports = this.file.process;
|
|
87
89
|
if (!shouldTransformImports)
|
|
88
90
|
return;
|
|
89
91
|
|
|
@@ -154,7 +156,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
154
156
|
&&
|
|
155
157
|
callee.property.type === 'Identifier'
|
|
156
158
|
&&
|
|
157
|
-
['page', 'error',
|
|
159
|
+
['page', 'error', ...routerMethods].includes(callee.property.name)
|
|
158
160
|
) {
|
|
159
161
|
|
|
160
162
|
// Should be at the root of the document
|
|
@@ -171,6 +173,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
// Adjust
|
|
176
|
+
// /client/pages/*
|
|
174
177
|
if (this.file.side === 'front') {
|
|
175
178
|
transformDataFetchers(path, this, routeDef);
|
|
176
179
|
}
|
|
@@ -181,12 +184,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
181
184
|
// Delete the route def since it will be replaced by a wrapper
|
|
182
185
|
path.replaceWithMultiple([]);
|
|
183
186
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
Events.Create( form.data ).then(res => toast.success(res.message))
|
|
187
|
-
=>
|
|
188
|
-
api.post( '/api/events/create', form.data ).then(res => toast.success(res.message))
|
|
189
|
-
*/
|
|
187
|
+
|
|
190
188
|
} else if (this.file.side === 'front') {
|
|
191
189
|
|
|
192
190
|
const isAService = (
|
|
@@ -197,14 +195,20 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
197
195
|
if(!isAService)
|
|
198
196
|
return;
|
|
199
197
|
|
|
200
|
-
|
|
198
|
+
/* [client] Backend Service calls: Transform to api.post( <method path>, <params> )
|
|
199
|
+
|
|
200
|
+
Events.Create( form.data ).then(res => toast.success(res.message))
|
|
201
|
+
=>
|
|
202
|
+
api.post( '/api/events/create', form.data ).then(res => toast.success(res.message))
|
|
203
|
+
*/
|
|
204
|
+
if (side === 'client' && !clientServices.includes(serviceName)) {
|
|
201
205
|
|
|
202
206
|
// Get complete call path
|
|
203
207
|
const apiPath = '/api/' + completePath.join('/');
|
|
204
208
|
|
|
205
209
|
// Replace by api.post( <method path>, <params> )
|
|
206
210
|
const apiPostArgs: types.CallExpression["arguments"] = [t.stringLiteral(apiPath)];
|
|
207
|
-
if (path.node.arguments.length
|
|
211
|
+
if (path.node.arguments.length >= 1)
|
|
208
212
|
apiPostArgs.push( path.node.arguments[0] );
|
|
209
213
|
|
|
210
214
|
path.replaceWith(
|
|
@@ -214,6 +218,13 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
214
218
|
), apiPostArgs
|
|
215
219
|
)
|
|
216
220
|
)
|
|
221
|
+
|
|
222
|
+
/* [server] Backend Service calls
|
|
223
|
+
|
|
224
|
+
Events.Create( form.data ).then(res => toast.success(res.message))
|
|
225
|
+
=>
|
|
226
|
+
app.Events.Create( form.data, context ).then(res => toast.success(res.message))
|
|
227
|
+
*/
|
|
217
228
|
} else {
|
|
218
229
|
|
|
219
230
|
// Rebuild member expression from completePath, adding a api prefix
|
|
@@ -231,7 +242,8 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
231
242
|
// Replace by app.<service>.<method>(...)
|
|
232
243
|
path.replaceWith(
|
|
233
244
|
t.callExpression(
|
|
234
|
-
newCallee,
|
|
245
|
+
newCallee,
|
|
246
|
+
[...path.node.arguments]
|
|
235
247
|
)
|
|
236
248
|
)
|
|
237
249
|
}
|
|
@@ -268,8 +280,8 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
268
280
|
relativeFileName = filename.substring( cli.paths.appRoot.length );
|
|
269
281
|
if (filename.startsWith( cli.paths.coreRoot ))
|
|
270
282
|
relativeFileName = filename.substring( cli.paths.coreRoot.length );
|
|
271
|
-
if (filename.startsWith('/node_modules/5htp-core/'))
|
|
272
|
-
relativeFileName = filename.substring( '/node_modules/5htp-core/'.length )
|
|
283
|
+
/*if (filename.startsWith('/node_modules/5htp-core/'))
|
|
284
|
+
relativeFileName = filename.substring( '/node_modules/5htp-core/'.length );*/
|
|
273
285
|
|
|
274
286
|
// The file isn't a route definition
|
|
275
287
|
if (relativeFileName === undefined) {
|
|
@@ -320,7 +332,39 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
320
332
|
}
|
|
321
333
|
*/
|
|
322
334
|
routeDef.dataFetchers.push(
|
|
323
|
-
...path.node.arguments[0].properties
|
|
335
|
+
...path.node.arguments[0].properties.map(p => {
|
|
336
|
+
|
|
337
|
+
// Server side: Pass request context as 2nd argument
|
|
338
|
+
// companies: Companies.create( <params>, context )
|
|
339
|
+
if (
|
|
340
|
+
side === 'server'
|
|
341
|
+
&&
|
|
342
|
+
p.type === 'ObjectProperty'
|
|
343
|
+
&&
|
|
344
|
+
p.key.type === 'Identifier'
|
|
345
|
+
&&
|
|
346
|
+
p.value.type === 'CallExpression'
|
|
347
|
+
&&
|
|
348
|
+
// TODO: reliable way to know if it's a service
|
|
349
|
+
!(
|
|
350
|
+
p.value.callee.type === 'MemberExpression'
|
|
351
|
+
&&
|
|
352
|
+
p.value.callee.object.type === 'Identifier'
|
|
353
|
+
&&
|
|
354
|
+
p.value.callee.object.name === 'api'
|
|
355
|
+
)
|
|
356
|
+
) {
|
|
357
|
+
|
|
358
|
+
// Pass request context as 2nd argument
|
|
359
|
+
p.value.arguments = p.value.arguments.length === 0
|
|
360
|
+
? [ t.objectExpression([]), t.identifier('context') ]
|
|
361
|
+
: [ p.value.arguments[0], t.identifier('context') ];
|
|
362
|
+
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return p;
|
|
366
|
+
|
|
367
|
+
})
|
|
324
368
|
);
|
|
325
369
|
|
|
326
370
|
/* Replace the:
|
|
@@ -357,7 +401,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
357
401
|
|
|
358
402
|
// Generate page chunk id
|
|
359
403
|
const { filepath, chunkId } = cli.paths.getPageChunk(app, filename);
|
|
360
|
-
debug && console.log(`[routes]`, filename
|
|
404
|
+
debug && console.log(`[routes]`, filename.replace(cli.paths.appRoot + '/client/pages', ''));
|
|
361
405
|
|
|
362
406
|
// Create new options to add in route.options
|
|
363
407
|
const newProperties = [
|
|
@@ -374,9 +418,19 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
374
418
|
// Add data fetchers
|
|
375
419
|
if (routeDef.dataFetchers.length !== 0) {
|
|
376
420
|
|
|
421
|
+
const rendererContext = t.cloneNode( renderer.params[0] );
|
|
422
|
+
// If not already present, add context to the 1st argument (a object spread)
|
|
423
|
+
if (!rendererContext.properties.some( p => p.key.name === 'context' ))
|
|
424
|
+
rendererContext.properties.push(
|
|
425
|
+
t.objectProperty(
|
|
426
|
+
t.identifier('context'),
|
|
427
|
+
t.identifier('context')
|
|
428
|
+
)
|
|
429
|
+
)
|
|
430
|
+
|
|
377
431
|
// (contollerParams) => { stats: api.get(...) }
|
|
378
432
|
const dataFetchersFunc = t.arrowFunctionExpression(
|
|
379
|
-
|
|
433
|
+
[rendererContext],
|
|
380
434
|
t.objectExpression(
|
|
381
435
|
routeDef.dataFetchers.map( df => t.cloneNode( df ))
|
|
382
436
|
)
|
|
@@ -467,7 +521,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
467
521
|
if (importedServicesList.length === 0)
|
|
468
522
|
return;
|
|
469
523
|
|
|
470
|
-
|
|
524
|
+
const definitions: types.BlockStatement["body"] = [];
|
|
471
525
|
if (file.side === 'front') {
|
|
472
526
|
|
|
473
527
|
// Limit to one route def per file
|
|
@@ -496,48 +550,89 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
496
550
|
|
|
497
551
|
// Force babel to create new fresh nodes
|
|
498
552
|
// If we directy use statementParent, it will not be included in the final compiler code
|
|
499
|
-
|
|
500
|
-
t.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
553
|
+
definitions.push(
|
|
554
|
+
t.returnStatement(
|
|
555
|
+
t.callExpression(
|
|
556
|
+
t.memberExpression(
|
|
557
|
+
t.identifier( callee.object.name ),
|
|
558
|
+
callee.property,
|
|
559
|
+
),
|
|
560
|
+
[routePath, ...routeArgs]
|
|
561
|
+
)
|
|
562
|
+
)
|
|
505
563
|
)
|
|
506
564
|
|
|
507
565
|
} else {
|
|
508
566
|
|
|
509
|
-
|
|
567
|
+
definitions.push(
|
|
510
568
|
// Without spread = react jxx need additionnal loader
|
|
511
569
|
...file.routeDefinitions.map( def =>
|
|
512
570
|
t.expressionStatement(def.definition)
|
|
513
571
|
),
|
|
514
|
-
|
|
572
|
+
)
|
|
515
573
|
}
|
|
516
574
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
575
|
+
/*
|
|
576
|
+
({ Router, app: { Events } }}) => {
|
|
577
|
+
...
|
|
578
|
+
}
|
|
579
|
+
*/
|
|
580
|
+
const appSpread: types.ObjectProperty[] = []
|
|
581
|
+
const servicesSpread: types.ObjectProperty[] = [
|
|
582
|
+
t.objectProperty(
|
|
583
|
+
t.identifier('app'),
|
|
584
|
+
t.identifier('app'),
|
|
585
|
+
),
|
|
586
|
+
t.objectProperty(
|
|
587
|
+
t.identifier('context'),
|
|
588
|
+
t.identifier('context'),
|
|
589
|
+
)
|
|
590
|
+
]
|
|
591
|
+
for (const [local, imported] of importedServicesList) {
|
|
592
|
+
if (imported === 'app')
|
|
593
|
+
appSpread.push(
|
|
594
|
+
t.objectProperty(
|
|
595
|
+
t.identifier(local),
|
|
596
|
+
t.identifier(local),
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
else
|
|
600
|
+
servicesSpread.push(
|
|
601
|
+
t.objectProperty(
|
|
602
|
+
t.identifier(local),
|
|
603
|
+
t.identifier(imported),
|
|
604
|
+
)
|
|
605
|
+
)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// export const __register = ({ Router, app }) => { ... }
|
|
609
|
+
const exportDeclaration = t.exportNamedDeclaration(
|
|
610
|
+
t.variableDeclaration('const', [
|
|
611
|
+
t.variableDeclarator(
|
|
612
|
+
t.identifier('__register'),
|
|
613
|
+
t.arrowFunctionExpression(
|
|
614
|
+
[
|
|
615
|
+
t.objectPattern(servicesSpread)
|
|
616
|
+
],
|
|
617
|
+
t.blockStatement([
|
|
618
|
+
// const { Events } = app;
|
|
619
|
+
t.variableDeclaration('const', [
|
|
620
|
+
t.variableDeclarator(
|
|
621
|
+
t.objectPattern(appSpread),
|
|
622
|
+
t.identifier('app')
|
|
528
623
|
)
|
|
529
|
-
)
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
624
|
+
]),
|
|
625
|
+
// Router.post(....)
|
|
626
|
+
...definitions,
|
|
627
|
+
])
|
|
628
|
+
)
|
|
533
629
|
)
|
|
534
|
-
)
|
|
535
|
-
|
|
536
|
-
);
|
|
630
|
+
])
|
|
631
|
+
);
|
|
537
632
|
|
|
538
633
|
|
|
539
|
-
(file.
|
|
540
|
-
&& console.log( file.path, generate(exportDeclaration).code );
|
|
634
|
+
// (file.path.includes('clients/prospect/search') && side === 'client')
|
|
635
|
+
// && console.log( file.path, generate(exportDeclaration).code );
|
|
541
636
|
|
|
542
637
|
return exportDeclaration;
|
|
543
638
|
}
|
package/compiler/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ import cli from '..';
|
|
|
17
17
|
import createServerConfig from './server';
|
|
18
18
|
import createClientConfig from './client';
|
|
19
19
|
import { TCompileMode } from './common';
|
|
20
|
+
import { routerServices } from './common/babel/plugins/services';
|
|
20
21
|
|
|
21
22
|
type TCompilerCallback = (compiler: webpack.Compiler) => void
|
|
22
23
|
|
|
@@ -25,7 +26,16 @@ type TServiceMetas = {
|
|
|
25
26
|
name: string,
|
|
26
27
|
parent: string,
|
|
27
28
|
dependences: string,
|
|
28
|
-
importationPath: string
|
|
29
|
+
importationPath: string,
|
|
30
|
+
priority: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type TRegisteredService = {
|
|
34
|
+
id?: string,
|
|
35
|
+
name: string,
|
|
36
|
+
className: string,
|
|
37
|
+
instanciation: (parentRef: string) => string,
|
|
38
|
+
priority: number,
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
/*----------------------------------
|
|
@@ -140,33 +150,40 @@ export default class Compiler {
|
|
|
140
150
|
|
|
141
151
|
|
|
142
152
|
// Index services
|
|
143
|
-
const searchDirs =
|
|
153
|
+
const searchDirs = [
|
|
144
154
|
// The less priority is the first
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
155
|
+
{
|
|
156
|
+
path: '@server/services/',
|
|
157
|
+
priority: -1,
|
|
158
|
+
root: path.join(cli.paths.core.root, 'server', 'services')
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
path: '@/server/services/',
|
|
162
|
+
priority: 0,
|
|
163
|
+
root: path.join(app.paths.root, 'server', 'services')
|
|
164
|
+
},
|
|
148
165
|
// Temp disabled because compile issue on vercel
|
|
149
166
|
//'': path.join(app.paths.root, 'node_modules'),
|
|
150
|
-
|
|
167
|
+
]
|
|
151
168
|
|
|
152
169
|
// Generate app class file
|
|
153
170
|
const servicesAvailable: {[id: string]: TServiceMetas} = {};
|
|
154
|
-
for (const
|
|
171
|
+
for (const searchDir of searchDirs) {
|
|
155
172
|
|
|
156
|
-
const
|
|
157
|
-
const services = this.findServices(searchDir);
|
|
173
|
+
const services = this.findServices(searchDir.root);
|
|
158
174
|
|
|
159
175
|
for (const serviceDir of services) {
|
|
160
176
|
const metasFile = path.join( serviceDir, 'service.json');
|
|
161
177
|
|
|
162
178
|
// The +1 is to remove the slash
|
|
163
|
-
const importationPath =
|
|
179
|
+
const importationPath = searchDir.path + serviceDir.substring( searchDir.root.length + 1 );
|
|
164
180
|
|
|
165
181
|
const serviceMetas = require(metasFile);
|
|
166
182
|
|
|
167
183
|
servicesAvailable[ serviceMetas.id ] = {
|
|
184
|
+
importationPath,
|
|
185
|
+
priority: searchDir.priority,
|
|
168
186
|
...serviceMetas,
|
|
169
|
-
importationPath
|
|
170
187
|
};
|
|
171
188
|
}
|
|
172
189
|
}
|
|
@@ -175,13 +192,13 @@ export default class Compiler {
|
|
|
175
192
|
const imported: string[] = []
|
|
176
193
|
const referencedNames: {[serviceId: string]: string} = {} // ID to Name
|
|
177
194
|
|
|
178
|
-
const refService = (serviceName: string, serviceConfig: any, level: number = 0) => {
|
|
195
|
+
const refService = (serviceName: string, serviceConfig: any, level: number = 0): TRegisteredService => {
|
|
179
196
|
|
|
180
197
|
if (serviceConfig.refTo !== undefined) {
|
|
181
198
|
const refTo = serviceConfig.refTo;
|
|
182
199
|
return {
|
|
183
200
|
name: serviceName,
|
|
184
|
-
|
|
201
|
+
instanciation: (parentRef: string) => `this.${refTo}`,
|
|
185
202
|
priority: 0
|
|
186
203
|
}
|
|
187
204
|
}
|
|
@@ -200,51 +217,51 @@ export default class Compiler {
|
|
|
200
217
|
if (serviceConfig.name !== undefined)
|
|
201
218
|
referencedNames[serviceConfig.id] = serviceConfig.name;
|
|
202
219
|
|
|
203
|
-
|
|
204
|
-
let subservices = '';
|
|
205
|
-
if (serviceConfig.subservices) {
|
|
220
|
+
const processConfig = (config: any, level: number = 0) => {
|
|
206
221
|
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
222
|
+
let propsStr = '';
|
|
223
|
+
for (const key in config) {
|
|
224
|
+
const value = config[key];
|
|
225
|
+
|
|
226
|
+
if (!value || typeof value !== 'object')
|
|
227
|
+
propsStr += `"${key}":${serialize(value, { space: 4 })},\n`;
|
|
228
|
+
|
|
229
|
+
// Reference to a service
|
|
230
|
+
else if (value.type === 'service.setup' || value.type === 'service.ref') // TODO: more reliable way to detect a service reference
|
|
231
|
+
propsStr += `${key}:`+ refService(key, value, level + 1).instanciation('instance') + ',\n'
|
|
232
|
+
|
|
233
|
+
// Recursion
|
|
234
|
+
else if (level <= 4 && !Array.isArray(value))
|
|
235
|
+
propsStr += `"${key}":` + processConfig(value, level + 1) + ',\n';
|
|
236
|
+
|
|
237
|
+
else
|
|
238
|
+
propsStr += `"${key}":${serialize(value, { space: 4 })},\n`;
|
|
211
239
|
|
|
212
|
-
|
|
213
|
-
const sortedSubservices = subservicesCode.sort((a, b) => a.priority - b.priority);
|
|
240
|
+
}
|
|
214
241
|
|
|
215
|
-
|
|
216
|
-
subservices = sortedSubservices.map(s => s.code).join('\n');
|
|
242
|
+
return `{ ${propsStr} }`;
|
|
217
243
|
}
|
|
244
|
+
const config = processConfig(serviceConfig.config || {});
|
|
218
245
|
|
|
219
246
|
// Generate the service instance
|
|
220
|
-
const instanciation =
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
};
|
|
235
|
-
else
|
|
236
|
-
return {
|
|
237
|
-
name: serviceName,
|
|
238
|
-
code: `${serviceName}: ${instanciation},`,
|
|
239
|
-
priority: serviceConfig.config?.priority || 0
|
|
240
|
-
};
|
|
247
|
+
const instanciation = (parentRef: string) =>
|
|
248
|
+
`new ${serviceMetas.name}(
|
|
249
|
+
${parentRef},
|
|
250
|
+
(instance: ${serviceMetas.name}) => (${config}),
|
|
251
|
+
this
|
|
252
|
+
)`
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
id: serviceConfig.id,
|
|
256
|
+
name: serviceName,
|
|
257
|
+
instanciation,
|
|
258
|
+
className: serviceMetas.name,
|
|
259
|
+
priority: serviceConfig.config?.priority || serviceMetas.priority || 0,
|
|
260
|
+
};
|
|
241
261
|
}
|
|
242
262
|
|
|
243
263
|
const servicesCode = Object.values(app.registered).map( s => refService(s.name, s, 0));
|
|
244
264
|
const sortedServices = servicesCode.sort((a, b) => a.priority - b.priority);
|
|
245
|
-
|
|
246
|
-
const services = sortedServices.map(s => s.code).join('\n');
|
|
247
|
-
const servicesNames = sortedServices.map(s => s.name);
|
|
248
265
|
|
|
249
266
|
// Define the app class identifier
|
|
250
267
|
const appClassIdentifier = app.identity.identifier;
|
|
@@ -255,43 +272,67 @@ export default class Compiler {
|
|
|
255
272
|
path.join( app.paths.client.generated, 'services.d.ts'),
|
|
256
273
|
`declare module "@app" {
|
|
257
274
|
|
|
258
|
-
import {
|
|
259
|
-
import
|
|
275
|
+
import { ${appClassIdentifier} as ${appClassIdentifier}Client } from "@/client";
|
|
276
|
+
import ${appClassIdentifier}Server from "@/server/.generated/app";
|
|
260
277
|
|
|
261
278
|
import { ApplicationProperties as ClientApplicationProperties } from "@client/app";
|
|
262
279
|
import { ApplicationProperties as ServerApplicationProperties } from "@server/app";
|
|
263
280
|
|
|
264
|
-
type ClientServices = Omit
|
|
265
|
-
type ServerServices = Omit
|
|
281
|
+
type ClientServices = Omit<${appClassIdentifier}Client, ClientApplicationProperties>;
|
|
282
|
+
type ServerServices = Omit<${appClassIdentifier}Server, ServerApplicationProperties | keyof ClientServices>;
|
|
266
283
|
|
|
267
284
|
type CombinedServices = ClientServices & ServerServices;
|
|
268
285
|
|
|
269
286
|
const appClass: CombinedServices;
|
|
270
287
|
export = appClass;
|
|
271
288
|
}
|
|
289
|
+
|
|
290
|
+
declare module '@models/types' {
|
|
291
|
+
export * from '@/var/prisma/index';
|
|
292
|
+
}
|
|
272
293
|
|
|
294
|
+
declare module '@request' {
|
|
295
|
+
|
|
296
|
+
}
|
|
273
297
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
declare module '@models' {
|
|
280
|
-
import { Prisma, PrismaClient } from '@/var/prisma/index';
|
|
281
|
-
|
|
282
|
-
type ModelNames = Prisma.ModelName;
|
|
283
|
-
|
|
284
|
-
type ModelDelegates = {
|
|
285
|
-
[K in ModelNames]: PrismaClient[Uncapitalize<K>];
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
const models: ModelDelegates;
|
|
289
|
-
|
|
290
|
-
export = models;
|
|
298
|
+
declare namespace preact.JSX {
|
|
299
|
+
interface HTMLAttributes {
|
|
300
|
+
src?: string;
|
|
301
|
+
}
|
|
291
302
|
}
|
|
292
|
-
|
|
303
|
+
`
|
|
293
304
|
);
|
|
294
305
|
|
|
306
|
+
fs.outputFileSync(
|
|
307
|
+
path.join( app.paths.client.generated, 'context.ts'),
|
|
308
|
+
`// TODO: move it into core (but how to make sure usecontext returns ${appClassIdentifier}'s context ?)
|
|
309
|
+
import React from 'react';
|
|
310
|
+
|
|
311
|
+
import type ${appClassIdentifier}Server from '@/server/.generated/app';
|
|
312
|
+
import type { TRouterContext as TServerRouterRequestContext } from '@server/services/router/response';
|
|
313
|
+
import type { TRouterContext as TClientRouterRequestContext } from '@client/services/router/response';
|
|
314
|
+
import type ${appClassIdentifier}Client from '.';
|
|
315
|
+
|
|
316
|
+
// TO Fix: TClientRouterRequestContext is unable to get the right type of ${appClassIdentifier}Client["router"]
|
|
317
|
+
// (it gets ClientApplication instead of ${appClassIdentifier}Client)
|
|
318
|
+
type ClientRequestContext = TClientRouterRequestContext<${appClassIdentifier}Client["Router"], ${appClassIdentifier}Client>;
|
|
319
|
+
type ServerRequestContext = TServerRouterRequestContext<${appClassIdentifier}Server["Router"]>
|
|
320
|
+
type UniversalServices = ClientRequestContext | ServerRequestContext
|
|
321
|
+
|
|
322
|
+
// Non-universla services are flagged as potentially undefined
|
|
323
|
+
export type ClientContext = (
|
|
324
|
+
UniversalServices
|
|
325
|
+
&
|
|
326
|
+
Partial<Omit<ClientRequestContext, keyof UniversalServices>>
|
|
327
|
+
&
|
|
328
|
+
{
|
|
329
|
+
Router: ${appClassIdentifier}Client["Router"],
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
export const ReactClientContext = React.createContext<ClientContext>({} as ClientContext);
|
|
334
|
+
export default (): ClientContext => React.useContext<ClientContext>(ReactClientContext);`);
|
|
335
|
+
|
|
295
336
|
fs.outputFileSync(
|
|
296
337
|
path.join( app.paths.server.generated, 'app.ts'),
|
|
297
338
|
`import { Application } from '@server/app/index';
|
|
@@ -300,15 +341,19 @@ ${imported.join('\n')}
|
|
|
300
341
|
|
|
301
342
|
export default class ${appClassIdentifier} extends Application {
|
|
302
343
|
|
|
303
|
-
|
|
304
|
-
${
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
protected
|
|
308
|
-
${
|
|
344
|
+
${sortedServices.map(service =>
|
|
345
|
+
`public ${service.name}!: ${service.className};`
|
|
346
|
+
).join('\n')}
|
|
347
|
+
|
|
348
|
+
protected registered = {
|
|
349
|
+
${sortedServices.map(service =>
|
|
350
|
+
`"${service.id}": {
|
|
351
|
+
name: "${service.name}",
|
|
352
|
+
priority: ${service.priority},
|
|
353
|
+
start: () => ${service.instanciation('this')}
|
|
354
|
+
}`
|
|
355
|
+
).join(',\n')}
|
|
309
356
|
} as const;
|
|
310
|
-
|
|
311
|
-
${services}
|
|
312
357
|
}
|
|
313
358
|
|
|
314
359
|
|
|
@@ -320,6 +365,29 @@ export default class ${appClassIdentifier} extends Application {
|
|
|
320
365
|
|
|
321
366
|
declare type ${appClassIdentifier} = import("@/server/.generated/app").default;
|
|
322
367
|
|
|
368
|
+
declare module '@cli/app' {
|
|
369
|
+
|
|
370
|
+
type App = {
|
|
371
|
+
|
|
372
|
+
env: TEnvConfig;
|
|
373
|
+
|
|
374
|
+
use: (referenceName: string) => TServiceRef;
|
|
375
|
+
|
|
376
|
+
setup: <TServiceName extends keyof ${appClassIdentifier}>(...args: [
|
|
377
|
+
// { user: app.setup('Core/User') }
|
|
378
|
+
servicePath: string,
|
|
379
|
+
serviceConfig?: {}
|
|
380
|
+
] | [
|
|
381
|
+
// app.setup('User', 'Core/User')
|
|
382
|
+
serviceName: TServiceName,
|
|
383
|
+
servicePath: string,
|
|
384
|
+
serviceConfig?: ${appClassIdentifier}[TServiceName]["config"]
|
|
385
|
+
]) => TServiceSetup;
|
|
386
|
+
}
|
|
387
|
+
const app: App;
|
|
388
|
+
export = app;
|
|
389
|
+
}
|
|
390
|
+
|
|
323
391
|
declare module "@app" {
|
|
324
392
|
|
|
325
393
|
import { ApplicationContainer } from '@server/app/container';
|
|
@@ -355,6 +423,12 @@ declare module '@server/app' {
|
|
|
355
423
|
|
|
356
424
|
export = foo;
|
|
357
425
|
}
|
|
426
|
+
|
|
427
|
+
declare module '@request' {
|
|
428
|
+
import type { TRouterContext } from '@server/services/router/response';
|
|
429
|
+
const routerContext: TRouterContext<CrossPath["Router"]>;
|
|
430
|
+
export = routerContext;
|
|
431
|
+
}
|
|
358
432
|
|
|
359
433
|
declare module '@models' {
|
|
360
434
|
import { Prisma, PrismaClient } from '@/var/prisma/index';
|
|
@@ -368,6 +442,10 @@ declare module '@models' {
|
|
|
368
442
|
const models: ModelDelegates;
|
|
369
443
|
|
|
370
444
|
export = models;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
declare module '@models/types' {
|
|
448
|
+
export * from '@/var/prisma/index';
|
|
371
449
|
}`
|
|
372
450
|
);
|
|
373
451
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp",
|
|
3
3
|
"description": "Convenient TypeScript framework designed for Performance and Productivity.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp.git",
|
|
7
7
|
"license": "MIT",
|
package/paths.ts
CHANGED
|
@@ -148,7 +148,7 @@ export default class Paths {
|
|
|
148
148
|
rootDir: this.core.cli
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
console.log('Applying Aliases ...', aliases.forModuleAlias());
|
|
151
|
+
//console.log('Applying Aliases ...', aliases.forModuleAlias());
|
|
152
152
|
moduleAlias.addAliases( aliases.forModuleAlias() );
|
|
153
153
|
|
|
154
154
|
}
|