5htp 0.6.3-2 → 0.6.3-4
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/compiler/common/babel/routes/routes.ts +303 -6
- package/compiler/index.ts +7 -10
- package/package.json +1 -1
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// Npm
|
|
6
6
|
import * as types from '@babel/types'
|
|
7
7
|
import type { PluginObj, NodePath } from '@babel/core';
|
|
8
|
-
import generate from '@babel/generator';
|
|
9
8
|
|
|
10
9
|
// Core
|
|
11
10
|
import cli from '@cli';
|
|
@@ -206,7 +205,7 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
206
205
|
|
|
207
206
|
Events.Create( form.data ).then(res => toast.success(res.message))
|
|
208
207
|
=>
|
|
209
|
-
api.post( '/api/events/create', form.data ).then(res => toast.success(res.message))
|
|
208
|
+
api.post( '/api/events/create', form.data ).then(res => toast.success(res.message)).catch(app.handleError)
|
|
210
209
|
*/
|
|
211
210
|
if (side === 'client' && !clientServices.includes(serviceName)) {
|
|
212
211
|
|
|
@@ -227,6 +226,8 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
227
226
|
), apiPostArgs
|
|
228
227
|
)
|
|
229
228
|
)
|
|
229
|
+
|
|
230
|
+
ensureBackendServicePromiseCatch(path);
|
|
230
231
|
|
|
231
232
|
/* [server] Backend Service calls
|
|
232
233
|
|
|
@@ -275,11 +276,254 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
|
|
279
|
+
function ensureBackendServicePromiseCatch(path: NodePath<types.CallExpression>) {
|
|
280
|
+
|
|
281
|
+
const chainRoot = getPromiseChainRoot(path);
|
|
282
|
+
|
|
283
|
+
// Only append if we are in a promise chain (e.g. .then(...))
|
|
284
|
+
if (chainRoot === path)
|
|
285
|
+
return;
|
|
286
|
+
|
|
287
|
+
if (isCatchWithAppHandleErrorArrow(chainRoot))
|
|
288
|
+
return;
|
|
289
|
+
|
|
290
|
+
if (isCatchWithAppHandleErrorMember(chainRoot)) {
|
|
291
|
+
const updatedCatch = t.callExpression(
|
|
292
|
+
chainRoot.node.callee,
|
|
293
|
+
[buildCatchHandler()]
|
|
294
|
+
);
|
|
295
|
+
chainRoot.replaceWith(updatedCatch);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (isCatchWithAppHandleErrorWrapped(chainRoot)) {
|
|
300
|
+
const updatedCatch = t.callExpression(
|
|
301
|
+
chainRoot.node.callee,
|
|
302
|
+
[buildCatchHandler()]
|
|
303
|
+
);
|
|
304
|
+
chainRoot.replaceWith(updatedCatch);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const newChain = t.callExpression(
|
|
309
|
+
t.memberExpression(chainRoot.node, t.identifier('catch')),
|
|
310
|
+
[buildCatchHandler()]
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
chainRoot.replaceWith(newChain);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function buildCatchHandler(): types.ArrowFunctionExpression {
|
|
317
|
+
const errorIdentifier = t.identifier('e');
|
|
318
|
+
return t.arrowFunctionExpression(
|
|
319
|
+
[errorIdentifier],
|
|
320
|
+
t.callExpression(
|
|
321
|
+
t.memberExpression(t.identifier('app'), t.identifier('handleError')),
|
|
322
|
+
[t.identifier(errorIdentifier.name)]
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function getPromiseChainRoot(path: NodePath<types.CallExpression>): NodePath<types.CallExpression> {
|
|
328
|
+
|
|
329
|
+
let current = path;
|
|
330
|
+
|
|
331
|
+
while (1) {
|
|
332
|
+
|
|
333
|
+
const member = current.parentPath;
|
|
334
|
+
if (!member?.isMemberExpression())
|
|
335
|
+
break;
|
|
336
|
+
|
|
337
|
+
if (member.node.object !== current.node)
|
|
338
|
+
break;
|
|
339
|
+
|
|
340
|
+
if (member.node.property.type !== 'Identifier')
|
|
341
|
+
break;
|
|
342
|
+
|
|
343
|
+
const propName = member.node.property.name;
|
|
344
|
+
if (!['then', 'catch', 'finally'].includes(propName))
|
|
345
|
+
break;
|
|
346
|
+
|
|
347
|
+
const call = member.parentPath;
|
|
348
|
+
if (!call?.isCallExpression())
|
|
349
|
+
break;
|
|
350
|
+
|
|
351
|
+
if (call.node.callee !== member.node)
|
|
352
|
+
break;
|
|
353
|
+
|
|
354
|
+
current = call;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return current;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function isCatchCall(path: NodePath<types.CallExpression>): boolean {
|
|
361
|
+
|
|
362
|
+
const callee = path.node.callee;
|
|
363
|
+
if (callee.type !== 'MemberExpression')
|
|
364
|
+
return false;
|
|
365
|
+
|
|
366
|
+
if (callee.property.type !== 'Identifier' || callee.property.name !== 'catch')
|
|
367
|
+
return false;
|
|
368
|
+
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function isCatchWithAppHandleErrorMember(path: NodePath<types.CallExpression>): boolean {
|
|
373
|
+
|
|
374
|
+
if (!isCatchCall(path))
|
|
375
|
+
return false;
|
|
376
|
+
|
|
377
|
+
if (path.node.arguments.length !== 1)
|
|
378
|
+
return false;
|
|
379
|
+
|
|
380
|
+
const handler = path.node.arguments[0];
|
|
381
|
+
if (handler.type !== 'MemberExpression')
|
|
382
|
+
return false;
|
|
383
|
+
|
|
384
|
+
if (handler.object.type !== 'Identifier' || handler.object.name !== 'app')
|
|
385
|
+
return false;
|
|
386
|
+
|
|
387
|
+
if (handler.property.type !== 'Identifier' || handler.property.name !== 'handleError')
|
|
388
|
+
return false;
|
|
389
|
+
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function isCatchWithAppHandleErrorArrow(path: NodePath<types.CallExpression>): boolean {
|
|
394
|
+
|
|
395
|
+
if (!isCatchCall(path))
|
|
396
|
+
return false;
|
|
397
|
+
|
|
398
|
+
if (path.node.arguments.length !== 1)
|
|
399
|
+
return false;
|
|
400
|
+
|
|
401
|
+
const handler = path.node.arguments[0];
|
|
402
|
+
if (handler.type !== 'ArrowFunctionExpression')
|
|
403
|
+
return false;
|
|
404
|
+
|
|
405
|
+
if (
|
|
406
|
+
handler.params.length !== 1
|
|
407
|
+
||
|
|
408
|
+
handler.params[0].type !== 'Identifier'
|
|
409
|
+
)
|
|
410
|
+
return false;
|
|
411
|
+
|
|
412
|
+
const errorName = handler.params[0].name;
|
|
413
|
+
|
|
414
|
+
if (handler.body.type !== 'CallExpression')
|
|
415
|
+
return false;
|
|
416
|
+
|
|
417
|
+
const call = handler.body;
|
|
418
|
+
if (call.callee.type !== 'MemberExpression')
|
|
419
|
+
return false;
|
|
420
|
+
|
|
421
|
+
if (call.callee.object.type !== 'Identifier' || call.callee.object.name !== 'app')
|
|
422
|
+
return false;
|
|
423
|
+
|
|
424
|
+
if (call.callee.property.type !== 'Identifier' || call.callee.property.name !== 'handleError')
|
|
425
|
+
return false;
|
|
426
|
+
|
|
427
|
+
if (call.arguments.length !== 1)
|
|
428
|
+
return false;
|
|
429
|
+
|
|
430
|
+
const arg = call.arguments[0];
|
|
431
|
+
if (arg.type !== 'Identifier' || arg.name !== errorName)
|
|
432
|
+
return false;
|
|
433
|
+
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function isCatchWithAppHandleErrorWrapped(path: NodePath<types.CallExpression>): boolean {
|
|
438
|
+
|
|
439
|
+
if (!isCatchCall(path))
|
|
440
|
+
return false;
|
|
441
|
+
|
|
442
|
+
if (path.node.arguments.length !== 1)
|
|
443
|
+
return false;
|
|
444
|
+
|
|
445
|
+
const handler = path.node.arguments[0];
|
|
446
|
+
if (handler.type !== 'ArrowFunctionExpression')
|
|
447
|
+
return false;
|
|
448
|
+
|
|
449
|
+
if (
|
|
450
|
+
handler.params.length !== 1
|
|
451
|
+
||
|
|
452
|
+
handler.params[0].type !== 'Identifier'
|
|
453
|
+
)
|
|
454
|
+
return false;
|
|
455
|
+
|
|
456
|
+
const errorName = handler.params[0].name;
|
|
457
|
+
|
|
458
|
+
if (handler.body.type !== 'BlockStatement')
|
|
459
|
+
return false;
|
|
460
|
+
|
|
461
|
+
const statements = handler.body.body;
|
|
462
|
+
if (statements.length < 2)
|
|
463
|
+
return false;
|
|
464
|
+
|
|
465
|
+
const first = statements[0];
|
|
466
|
+
if (!(
|
|
467
|
+
first.type === 'ExpressionStatement'
|
|
468
|
+
&&
|
|
469
|
+
first.expression.type === 'CallExpression'
|
|
470
|
+
&&
|
|
471
|
+
first.expression.callee.type === 'MemberExpression'
|
|
472
|
+
&&
|
|
473
|
+
first.expression.callee.object.type === 'Identifier'
|
|
474
|
+
&&
|
|
475
|
+
first.expression.callee.object.name === 'console'
|
|
476
|
+
&&
|
|
477
|
+
first.expression.callee.property.type === 'Identifier'
|
|
478
|
+
&&
|
|
479
|
+
first.expression.callee.property.name === 'log'
|
|
480
|
+
&&
|
|
481
|
+
first.expression.arguments.length === 2
|
|
482
|
+
&&
|
|
483
|
+
first.expression.arguments[0].type === 'StringLiteral'
|
|
484
|
+
&&
|
|
485
|
+
first.expression.arguments[0].value === 'Error catched'
|
|
486
|
+
&&
|
|
487
|
+
first.expression.arguments[1].type === 'Identifier'
|
|
488
|
+
&&
|
|
489
|
+
first.expression.arguments[1].name === errorName
|
|
490
|
+
))
|
|
491
|
+
return false;
|
|
492
|
+
|
|
493
|
+
const second = statements[1];
|
|
494
|
+
if (!(
|
|
495
|
+
second.type === 'ExpressionStatement'
|
|
496
|
+
&&
|
|
497
|
+
second.expression.type === 'CallExpression'
|
|
498
|
+
&&
|
|
499
|
+
second.expression.callee.type === 'MemberExpression'
|
|
500
|
+
&&
|
|
501
|
+
second.expression.callee.object.type === 'Identifier'
|
|
502
|
+
&&
|
|
503
|
+
second.expression.callee.object.name === 'app'
|
|
504
|
+
&&
|
|
505
|
+
second.expression.callee.property.type === 'Identifier'
|
|
506
|
+
&&
|
|
507
|
+
second.expression.callee.property.name === 'handleError'
|
|
508
|
+
&&
|
|
509
|
+
second.expression.arguments.length === 1
|
|
510
|
+
&&
|
|
511
|
+
second.expression.arguments[0].type === 'Identifier'
|
|
512
|
+
&&
|
|
513
|
+
second.expression.arguments[0].name === errorName
|
|
514
|
+
))
|
|
515
|
+
return false;
|
|
516
|
+
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
|
|
278
520
|
function ensureApiExposedInRootFunction(
|
|
279
521
|
path: NodePath<types.CallExpression>,
|
|
280
522
|
pluginState: TPluginState
|
|
281
523
|
) {
|
|
282
|
-
|
|
524
|
+
const needsApi = !path.scope.hasBinding('api');
|
|
525
|
+
const needsApp = !path.scope.hasBinding('app');
|
|
526
|
+
if (!needsApi && !needsApp)
|
|
283
527
|
return;
|
|
284
528
|
|
|
285
529
|
const rootFunctionPath = getRootFunctionPath(path);
|
|
@@ -292,13 +536,42 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
292
536
|
if (!isProgramBodyLevelFunction(rootFunctionPath))
|
|
293
537
|
return;
|
|
294
538
|
|
|
539
|
+
const existingContextObjectPattern = findUseContextDestructuringObjectPattern(rootFunctionPath);
|
|
540
|
+
if (existingContextObjectPattern) {
|
|
541
|
+
|
|
542
|
+
const existingKeys = new Set(
|
|
543
|
+
existingContextObjectPattern.properties
|
|
544
|
+
.filter((p): p is types.ObjectProperty =>
|
|
545
|
+
p.type === 'ObjectProperty'
|
|
546
|
+
&& p.key.type === 'Identifier'
|
|
547
|
+
)
|
|
548
|
+
.map(p => (p.key as types.Identifier).name)
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
if (needsApi && !existingKeys.has('api')) {
|
|
552
|
+
existingContextObjectPattern.properties.push(
|
|
553
|
+
t.objectProperty(t.identifier('api'), t.identifier('api'), false, true),
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (needsApp && !existingKeys.has('app')) {
|
|
558
|
+
existingContextObjectPattern.properties.push(
|
|
559
|
+
t.objectProperty(t.identifier('app'), t.identifier('app'), false, true),
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
pluginState.needsUseContextImport = true;
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
295
567
|
if (pluginState.apiInjectedRootFunctions.has(rootFunctionPath.node))
|
|
296
568
|
return;
|
|
297
569
|
|
|
298
570
|
const exposeApiDeclaration = t.variableDeclaration('const', [
|
|
299
571
|
t.variableDeclarator(
|
|
300
572
|
t.objectPattern([
|
|
301
|
-
t.objectProperty(t.identifier('api'), t.identifier('api'), false, true),
|
|
573
|
+
...(needsApi ? [t.objectProperty(t.identifier('api'), t.identifier('api'), false, true)] : []),
|
|
574
|
+
...(needsApp ? [t.objectProperty(t.identifier('app'), t.identifier('app'), false, true)] : []),
|
|
302
575
|
]),
|
|
303
576
|
t.callExpression(t.identifier('useContext'), [])
|
|
304
577
|
)
|
|
@@ -318,6 +591,32 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
318
591
|
pluginState.needsUseContextImport = true;
|
|
319
592
|
}
|
|
320
593
|
|
|
594
|
+
function findUseContextDestructuringObjectPattern(
|
|
595
|
+
rootFunctionPath: NodePath<types.Function | types.ArrowFunctionExpression>
|
|
596
|
+
): types.ObjectPattern | undefined {
|
|
597
|
+
|
|
598
|
+
const body = rootFunctionPath.node.body;
|
|
599
|
+
if (body.type !== 'BlockStatement')
|
|
600
|
+
return;
|
|
601
|
+
|
|
602
|
+
for (const stmt of body.body) {
|
|
603
|
+
if (stmt.type !== 'VariableDeclaration' || stmt.kind !== 'const')
|
|
604
|
+
continue;
|
|
605
|
+
|
|
606
|
+
for (const declarator of stmt.declarations) {
|
|
607
|
+
if (declarator.id.type !== 'ObjectPattern')
|
|
608
|
+
continue;
|
|
609
|
+
if (!declarator.init || declarator.init.type !== 'CallExpression')
|
|
610
|
+
continue;
|
|
611
|
+
if (declarator.init.callee.type !== 'Identifier' || declarator.init.callee.name !== 'useContext')
|
|
612
|
+
continue;
|
|
613
|
+
if (declarator.init.arguments.length !== 0)
|
|
614
|
+
continue;
|
|
615
|
+
return declarator.id;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
321
620
|
function getRootFunctionPath(path: NodePath): NodePath<types.Function | types.ArrowFunctionExpression> | undefined {
|
|
322
621
|
|
|
323
622
|
let functionPath = path.getFunctionParent();
|
|
@@ -472,8 +771,6 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
472
771
|
relativeFileName = filename.substring( cli.paths.appRoot.length );
|
|
473
772
|
if (filename.startsWith( cli.paths.coreRoot ))
|
|
474
773
|
relativeFileName = filename.substring( cli.paths.coreRoot.length );
|
|
475
|
-
/*if (filename.startsWith('/node_modules/5htp-core/'))
|
|
476
|
-
relativeFileName = filename.substring( '/node_modules/5htp-core/'.length );*/
|
|
477
774
|
|
|
478
775
|
// The file isn't a route definition
|
|
479
776
|
if (relativeFileName === undefined) {
|
package/compiler/index.ts
CHANGED
|
@@ -273,17 +273,14 @@ export default class Compiler {
|
|
|
273
273
|
|
|
274
274
|
import { ${appClassIdentifier} as ${appClassIdentifier}Client } from "@/client";
|
|
275
275
|
import ${appClassIdentifier}Server from "@/server/.generated/app";
|
|
276
|
-
|
|
277
|
-
import { ApplicationProperties as ClientApplicationProperties } from "@client/app";
|
|
278
|
-
import { ApplicationProperties as ServerApplicationProperties } from "@server/app";
|
|
279
|
-
|
|
280
|
-
type ClientServices = Omit<${appClassIdentifier}Client, ClientApplicationProperties>;
|
|
281
|
-
type ServerServices = Omit<${appClassIdentifier}Server, ServerApplicationProperties | keyof ClientServices>;
|
|
282
|
-
|
|
283
|
-
type CombinedServices = ClientServices & ServerServices;
|
|
284
276
|
|
|
285
|
-
const
|
|
286
|
-
|
|
277
|
+
export const Router: ${appClassIdentifier}Client['Router'];
|
|
278
|
+
|
|
279
|
+
${sortedServices.map(service => service.name !== 'Router'
|
|
280
|
+
? `export const ${service.name}: ${appClassIdentifier}Server["${service.name}"];`
|
|
281
|
+
: ''
|
|
282
|
+
).join('\n')}
|
|
283
|
+
|
|
287
284
|
}
|
|
288
285
|
|
|
289
286
|
declare module '@models/types' {
|
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.6.3-
|
|
4
|
+
"version": "0.6.3-4",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp.git",
|
|
7
7
|
"license": "MIT",
|