proteum 1.0.0-1 → 1.0.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.
Files changed (51) hide show
  1. package/changelog.md +5 -0
  2. package/client/components/Dialog/index.less +1 -3
  3. package/package.json +3 -69
  4. package/server/app/container/console/index.ts +1 -1
  5. package/templates/composant.tsx +40 -0
  6. package/templates/form.ts +30 -0
  7. package/templates/modal.tsx +47 -0
  8. package/templates/modele.ts +56 -0
  9. package/templates/page.tsx +74 -0
  10. package/templates/route.ts +43 -0
  11. package/templates/service.ts +75 -0
  12. package/tsconfig.common.json +1 -2
  13. package/vscode/copyimportationpath/.eslintrc.json +24 -0
  14. package/vscode/copyimportationpath/.vscodeignore +12 -0
  15. package/vscode/copyimportationpath/CHANGELOG.md +9 -0
  16. package/vscode/copyimportationpath/README.md +3 -0
  17. package/vscode/copyimportationpath/copyimportationpath-0.0.1.vsix +0 -0
  18. package/vscode/copyimportationpath/out/extension.js +206 -0
  19. package/vscode/copyimportationpath/out/extension.js.map +1 -0
  20. package/vscode/copyimportationpath/package-lock.json +4536 -0
  21. package/vscode/copyimportationpath/package.json +86 -0
  22. package/vscode/copyimportationpath/src/extension.ts +300 -0
  23. package/vscode/copyimportationpath/tsconfig.json +22 -0
  24. package/vscode/copyimportationpath/vsc-extension-quickstart.md +42 -0
  25. package/cli/app/config.ts +0 -54
  26. package/cli/app/index.ts +0 -195
  27. package/cli/bin.js +0 -11
  28. package/cli/commands/build.ts +0 -34
  29. package/cli/commands/deploy/app.ts +0 -29
  30. package/cli/commands/deploy/web.ts +0 -60
  31. package/cli/commands/dev.ts +0 -109
  32. package/cli/commands/init.ts +0 -85
  33. package/cli/compiler/client/identite.ts +0 -72
  34. package/cli/compiler/client/index.ts +0 -334
  35. package/cli/compiler/common/babel/index.ts +0 -170
  36. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  37. package/cli/compiler/common/babel/plugins/services.ts +0 -579
  38. package/cli/compiler/common/babel/routes/imports.ts +0 -127
  39. package/cli/compiler/common/babel/routes/routes.ts +0 -1130
  40. package/cli/compiler/common/files/autres.ts +0 -39
  41. package/cli/compiler/common/files/images.ts +0 -35
  42. package/cli/compiler/common/files/style.ts +0 -78
  43. package/cli/compiler/common/index.ts +0 -154
  44. package/cli/compiler/index.ts +0 -532
  45. package/cli/compiler/server/index.ts +0 -211
  46. package/cli/index.ts +0 -189
  47. package/cli/paths.ts +0 -165
  48. package/cli/print.ts +0 -12
  49. package/cli/tsconfig.json +0 -38
  50. package/cli/utils/index.ts +0 -22
  51. package/cli/utils/keyboard.ts +0 -78
@@ -1,579 +0,0 @@
1
- /*----------------------------------
2
- - DEPENDANCES
3
- ----------------------------------*/
4
-
5
- // Npm
6
- import * as types from '@babel/types'
7
- import type { NodePath, PluginObj } from '@babel/core';
8
- import generate from '@babel/generator';
9
- import fs from 'fs';
10
- import path from 'path';
11
- import { parse } from '@babel/parser';
12
- import traverse from '@babel/traverse';
13
-
14
- // Core
15
- import cli from '@cli';
16
- import { App, TAppSide } from '../../../../app';
17
-
18
- /*----------------------------------
19
- - WEBPACK RULE
20
- ----------------------------------*/
21
-
22
- type TOptions = {
23
- side: TAppSide,
24
- app: App,
25
- debug?: boolean
26
- }
27
-
28
- /**
29
- * Extended source type: now includes "models"
30
- * so we can differentiate how we rewrite references.
31
- */
32
- type TImportSource = 'container' | 'services' | 'models' | 'request';
33
-
34
- module.exports = (options: TOptions) => (
35
- [Plugin, options]
36
- )
37
-
38
- type TImportedIndex = {
39
- local: string,
40
- imported: string, // The original “imported” name
41
- references: NodePath<types.Node>[], // reference paths
42
- source: TImportSource // container | application | models
43
- }
44
-
45
- type TRoutesIndex = {
46
- byFile: Map<string, Set<string>>,
47
- all: Set<string>,
48
- initialized: boolean
49
- }
50
-
51
- const routesIndexByAppRoot = new Map<string, TRoutesIndex>();
52
-
53
- function isRouteDecoratorExpression(expression: types.Expression): boolean {
54
- return (
55
- // Handles the case of @Route without parameters
56
- (types.isIdentifier(expression) && expression.name === 'Route')
57
- ||
58
- // Handles the case of @Route() with parameters
59
- (
60
- types.isCallExpression(expression)
61
- &&
62
- types.isIdentifier(expression.callee)
63
- &&
64
- expression.callee.name === 'Route'
65
- )
66
- );
67
- }
68
-
69
- function getRoutePathFromDecoratorExpression(expression: types.Expression): string | undefined {
70
- if (
71
- !types.isCallExpression(expression)
72
- ||
73
- !types.isIdentifier(expression.callee)
74
- ||
75
- expression.callee.name !== 'Route'
76
- )
77
- return;
78
-
79
- const firstArg = expression.arguments[0];
80
- if (!types.isStringLiteral(firstArg))
81
- return;
82
-
83
- return firstArg.value;
84
- }
85
-
86
- function extractRoutePathsFromCode(code: string, filename: string): Set<string> {
87
- const routePaths = new Set<string>();
88
-
89
- let ast: ReturnType<typeof parse> | undefined;
90
- try {
91
- ast = parse(code, {
92
- sourceType: 'module',
93
- sourceFilename: filename,
94
- plugins: [
95
- 'typescript',
96
- 'decorators-legacy',
97
- 'jsx',
98
- 'classProperties',
99
- 'classPrivateProperties',
100
- 'classPrivateMethods',
101
- 'dynamicImport',
102
- 'importMeta',
103
- 'optionalChaining',
104
- 'nullishCoalescingOperator',
105
- 'topLevelAwait',
106
- ],
107
- });
108
- } catch {
109
- return routePaths;
110
- }
111
-
112
- traverse(ast, {
113
- ClassMethod(path) {
114
- const { node } = path;
115
- if (!node.decorators || node.key.type !== 'Identifier')
116
- return;
117
-
118
- for (const decorator of node.decorators) {
119
- if (!isRouteDecoratorExpression(decorator.expression))
120
- continue;
121
-
122
- const routePath = getRoutePathFromDecoratorExpression(decorator.expression);
123
- if (routePath)
124
- routePaths.add(routePath);
125
- }
126
- }
127
- });
128
-
129
- return routePaths;
130
- }
131
-
132
- function listTsFiles(dirPath: string): string[] {
133
- let entries: fs.Dirent[];
134
- try {
135
- entries = fs.readdirSync(dirPath, { withFileTypes: true });
136
- } catch {
137
- return [];
138
- }
139
-
140
- const files: string[] = [];
141
- for (const entry of entries) {
142
- const fullPath = path.join(dirPath, entry.name);
143
- if (entry.isDirectory()) {
144
- files.push(...listTsFiles(fullPath));
145
- continue;
146
- }
147
-
148
- const isTs = fullPath.endsWith('.ts') || fullPath.endsWith('.tsx');
149
- if (!isTs || fullPath.endsWith('.d.ts'))
150
- continue;
151
-
152
- files.push(fullPath);
153
- }
154
- return files;
155
- }
156
-
157
- function initializeRoutesIndex(appRoot: string, index: TRoutesIndex) {
158
- const servicesDir = path.join(appRoot, 'server', 'services');
159
- const files = listTsFiles(servicesDir);
160
-
161
- for (const file of files) {
162
- let code: string;
163
- try {
164
- code = fs.readFileSync(file, 'utf8');
165
- } catch {
166
- continue;
167
- }
168
-
169
- const routes = extractRoutePathsFromCode(code, file);
170
- index.byFile.set(file, routes);
171
- }
172
-
173
- index.all.clear();
174
- for (const routes of index.byFile.values()) {
175
- for (const route of routes)
176
- index.all.add(route);
177
- }
178
- index.initialized = true;
179
- }
180
-
181
- function getRoutesIndex(appRoot: string): TRoutesIndex {
182
- let index = routesIndexByAppRoot.get(appRoot);
183
- if (!index) {
184
- index = {
185
- byFile: new Map(),
186
- all: new Set(),
187
- initialized: false
188
- };
189
- routesIndexByAppRoot.set(appRoot, index);
190
- }
191
-
192
- if (!index.initialized) {
193
- initializeRoutesIndex(appRoot, index);
194
- }
195
-
196
- return index;
197
- }
198
-
199
- function updateRoutesIndexForFile(index: TRoutesIndex, filename: string, routePaths: Set<string>) {
200
- index.byFile.set(filename, routePaths);
201
-
202
- index.all.clear();
203
- for (const routes of index.byFile.values()) {
204
- for (const route of routes)
205
- index.all.add(route);
206
- }
207
- }
208
-
209
- /*----------------------------------
210
- - PLUGIN
211
- ----------------------------------*/
212
- function Plugin(babel, { app, side, debug }: TOptions) {
213
-
214
- const t = babel.types as typeof types;
215
-
216
- /*
217
- Transforms:
218
- import { MyService, Environment } from '@app';
219
- import { MyModel } from '@models';
220
- ...
221
- MyService.method();
222
- Environment.name;
223
- MyModel.someCall();
224
-
225
- To:
226
- import container from '<path>/server/app/container';
227
- ...
228
- container.Environment.name;
229
- this.app.MyService.method();
230
- this.app.Models.client.MyModel.someCall();
231
-
232
- Processed files:
233
- @/server/services
234
- */
235
-
236
- const plugin: PluginObj<{
237
-
238
- debug: boolean,
239
-
240
- filename: string,
241
- processFile: boolean,
242
-
243
- // Count how many total imports we transform
244
- importedCount: number,
245
- routeMethods: string[],
246
- routePaths: Set<string>,
247
- routesIndex: TRoutesIndex,
248
- contextGuardedClassMethods: WeakSet<types.ClassMethod>,
249
-
250
- // For every local identifier, store info about how it should be rewritten
251
- imported: {
252
- [localName: string]: TImportedIndex
253
- }
254
- }> = {
255
-
256
- pre(state) {
257
- this.filename = state.opts.filename as string;
258
- this.processFile = this.filename.startsWith(cli.paths.appRoot + '/server/services');
259
-
260
- this.imported = {};
261
-
262
- this.importedCount = 0;
263
- this.debug = debug || false;
264
-
265
- this.routeMethods = [];
266
- this.routePaths = new Set();
267
-
268
- this.routesIndex = getRoutesIndex(app.paths.root);
269
- this.contextGuardedClassMethods = new WeakSet();
270
- },
271
-
272
- visitor: {
273
-
274
- // Detect decored methods before other plugins remove decorators
275
- Program(path) {
276
-
277
- if (!this.processFile) return;
278
-
279
- // Traverse the AST within the Program node
280
- path.traverse({
281
- ClassMethod: (subPath) => {
282
- const { node } = subPath;
283
- if (!node.decorators || node.key.type !== 'Identifier') return;
284
-
285
- for (const decorator of node.decorators) {
286
-
287
- const isRoute = isRouteDecoratorExpression(decorator.expression);
288
-
289
- if (!isRoute) continue;
290
-
291
- const methodName = node.key.name;
292
- this.routeMethods.push( methodName );
293
-
294
- const routePath = getRoutePathFromDecoratorExpression(decorator.expression);
295
- if (routePath)
296
- this.routePaths.add(routePath);
297
- }
298
- }
299
- });
300
-
301
- updateRoutesIndexForFile(this.routesIndex, this.filename, this.routePaths);
302
- },
303
-
304
- /**
305
- * Detect import statements from '@app' or '@models'
306
- */
307
- ImportDeclaration(path) {
308
- if (!this.processFile) return;
309
-
310
- const source = path.node.source.value;
311
- if (source !== '@app' && source !== '@models' && source !== '@request') {
312
- return;
313
- }
314
-
315
- // For '@app' and '@models', gather imported symbols
316
- for (const specifier of path.node.specifiers) {
317
- if (specifier.type !== 'ImportSpecifier') continue;
318
- if (specifier.imported.type !== 'Identifier') continue;
319
-
320
- this.importedCount++;
321
-
322
- let importSource: TImportSource;
323
- switch (source) {
324
- case '@app':
325
- // Distinguish whether it's a container service or an application service
326
- if (app.containerServices.includes(specifier.imported.name)) {
327
- importSource = 'container';
328
- } else {
329
- importSource = 'services';
330
- }
331
- break;
332
- case '@request':
333
- importSource = 'request';
334
- break;
335
- case '@models':
336
- // source === '@models'
337
- importSource = 'models';
338
- break;
339
- default:
340
- throw new Error(`Unknown import source: ${source}`);
341
- }
342
-
343
- this.imported[specifier.local.name] = {
344
- local: specifier.local.name,
345
- imported: specifier.imported.name,
346
- references: path.scope.bindings[specifier.local.name].referencePaths,
347
- source: importSource
348
- };
349
- }
350
-
351
- // Remove the original import line(s) and replace with any needed new import
352
- // For @app imports, we might import "container" if needed
353
- // For @models, we don’t import anything
354
- const replaceWith: any[] = [];
355
-
356
- // If this line had container references, add a default import for container
357
- // Example: import container from '<root>/server/app/container'
358
- if (source === '@app') {
359
- replaceWith.push(
360
- t.importDeclaration(
361
- [t.importDefaultSpecifier(t.identifier('container'))],
362
- t.stringLiteral(
363
- cli.paths.core.root + '/server/app/container'
364
- )
365
- )
366
- );
367
- }
368
-
369
- // Replace the original import statement with our new import(s) if any
370
- // or remove it entirely if no container references exist.
371
- path.replaceWithMultiple(replaceWith);
372
- },
373
-
374
- CallExpression(path) {
375
- if (!this.processFile)
376
- return;
377
-
378
- const classMethodPath = path.findParent(p => p.isClassMethod()) as NodePath<types.ClassMethod> | null;
379
- if (!classMethodPath)
380
- return;
381
-
382
- // Ignore constructors
383
- if (classMethodPath.node.kind === 'constructor')
384
- return;
385
-
386
- const callee = path.node.callee;
387
- if (!t.isMemberExpression(callee) && !(t as any).isOptionalMemberExpression?.(callee))
388
- return;
389
-
390
- // Build member chain segments: this.app.<Service>.<...>
391
- const segments: string[] = [];
392
- let current: any = callee;
393
- while (t.isMemberExpression(current) || (t as any).isOptionalMemberExpression?.(current)) {
394
- const prop = current.property;
395
- if (t.isIdentifier(prop)) {
396
- segments.unshift(prop.name);
397
- } else if (t.isStringLiteral(prop)) {
398
- segments.unshift(prop.value);
399
- } else {
400
- return;
401
- }
402
- current = current.object;
403
- }
404
-
405
- if (!t.isThisExpression(current))
406
- return;
407
-
408
- // Expect: this.app.<Service>.<method>
409
- if (segments.length < 3 || segments[0] !== 'app')
410
- return;
411
-
412
- const serviceLocalName = segments[1];
413
- const importedRef = this.imported[serviceLocalName];
414
- if (!importedRef || importedRef.source !== 'services')
415
- return;
416
-
417
- const routePath = [
418
- importedRef.imported || serviceLocalName,
419
- ...segments.slice(2)
420
- ].join('/');
421
-
422
- if (!this.routesIndex.all.has(routePath))
423
- return;
424
-
425
- // Ensure the parent function checks that `context` exists
426
- if (!this.contextGuardedClassMethods.has(classMethodPath.node)) {
427
- const guard = t.ifStatement(
428
- t.binaryExpression(
429
- '===',
430
- t.unaryExpression('typeof', t.identifier('context')),
431
- t.stringLiteral('undefined')
432
- ),
433
- t.blockStatement([
434
- t.throwStatement(
435
- t.newExpression(t.identifier('Error'), [
436
- t.stringLiteral('context variable should be passed in this function')
437
- ])
438
- )
439
- ])
440
- );
441
- classMethodPath.get('body').unshiftContainer('body', guard);
442
- this.contextGuardedClassMethods.add(classMethodPath.node);
443
- }
444
-
445
- // Ensure call arguments: second argument is `context`
446
- const args = path.node.arguments;
447
- if (args.length === 0) {
448
- args.push(t.identifier('undefined'), t.identifier('context'));
449
- } else if (args.length === 1) {
450
- args.push(t.identifier('context'));
451
- } else {
452
- args[1] = t.identifier('context') as any;
453
- }
454
- },
455
-
456
- // This visitor fires for every class method.
457
- ClassMethod(path) {
458
-
459
- // Must be a server service
460
- if (!this.processFile || path.replaced) return;
461
-
462
- // Must have a method name
463
- if (path.node.key.type !== 'Identifier') return;
464
-
465
- // Init context
466
- const methodName = path.node.key.name;
467
- let params = path.node.params;
468
-
469
- // Prefix references
470
- path.traverse({ Identifier: (subPath) => {
471
-
472
- const { node } = subPath;
473
- const name = node.name;
474
- const ref = this.imported[name];
475
- if (!ref || !ref.references) {
476
- return;
477
- }
478
-
479
- // Find a specific binding that hasn't been replaced yet
480
- const foundBinding = ref.references.find(binding => {
481
- return subPath.getPathLocation() === binding.getPathLocation();
482
- });
483
-
484
- if (!foundBinding || foundBinding.replaced)
485
- return;
486
-
487
- // Mark as replaced to avoid loops
488
- foundBinding.replaced = true;
489
-
490
- // Based on the source, replace the identifier with the proper MemberExpression
491
- if (ref.source === 'container') {
492
- // container.[identifier]
493
- // e.g. container.Environment
494
- subPath.replaceWith(
495
- t.memberExpression(
496
- t.identifier('container'),
497
- subPath.node
498
- )
499
- );
500
- }
501
- else if (ref.source === 'services') {
502
- // this.app.[identifier]
503
- // e.g. this.app.MyService
504
- subPath.replaceWith(
505
- t.memberExpression(
506
- t.memberExpression(
507
- t.thisExpression(),
508
- t.identifier('app')
509
- ),
510
- subPath.node
511
- )
512
- );
513
- }
514
- else if (ref.source === 'models') {
515
- // this.app.Models.client.[identifier]
516
- // e.g. this.app.Models.client.MyModel
517
- subPath.replaceWith(
518
- t.memberExpression(
519
- t.memberExpression(
520
- t.memberExpression(
521
- t.memberExpression(
522
- t.thisExpression(),
523
- t.identifier('app')
524
- ),
525
- t.identifier('Models')
526
- ),
527
- t.identifier('client')
528
- ),
529
- subPath.node
530
- )
531
- );
532
- }
533
- else if (ref.source === 'request') {
534
- // this.app.Models.client.[identifier]
535
- // e.g. this.app.Models.client.MyModel
536
- subPath.replaceWith(
537
- t.memberExpression(
538
- t.identifier('context'),
539
- subPath.node
540
- )
541
- );
542
- }
543
-
544
- } });
545
-
546
- if (
547
- this.routeMethods.includes(methodName)
548
- &&
549
- path.node.params.length < 2
550
- ) {
551
-
552
- // Expose router context variable via the second parameter
553
- params = [
554
- path.node.params[0] || t.objectPattern([]),
555
- t.identifier('context'),
556
- ];
557
-
558
- // Apply changes
559
- path.replaceWith(
560
- t.classMethod(
561
- path.node.kind,
562
- path.node.key,
563
- params,
564
- path.node.body,
565
- false,
566
- false,
567
- false,
568
- path.node.async
569
- )
570
- );
571
- }
572
-
573
- //console.log("ROUTE METHOD", this.filename, methodName, generate(path.node).code);
574
- }
575
- }
576
- };
577
-
578
- return plugin;
579
- }
@@ -1,127 +0,0 @@
1
- /*----------------------------------
2
- - DEPENDANCES
3
- ----------------------------------*/
4
-
5
- // Npm
6
- import type { ImportTransformer } from 'babel-plugin-glob-import';
7
- import * as types from '@babel/types'
8
- import path from 'path';
9
- import generate from '@babel/generator';
10
-
11
- // Core
12
- import cli from '@cli';
13
- import type { TAppSide, default as App } from '@cli/app';
14
-
15
- // Resources
16
- const routesToPreload = require( cli.paths.appRoot + '/client/pages/preload.json' );
17
-
18
- /*----------------------------------
19
- - CONFIG
20
- ----------------------------------*/
21
-
22
- const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
23
-
24
- /*----------------------------------
25
- - TRANSFORMER
26
- ----------------------------------*/
27
-
28
- module.exports = (app: App, side: TAppSide, dev: boolean): ImportTransformer => ({
29
-
30
- debug: false,
31
-
32
- test: (request) => (
33
- side === 'client'
34
- &&
35
- (
36
- request.source === '@client/pages/**/([a-z0-9]*).tsx'
37
- ||
38
- request.source === '@/client/pages/**/([a-z0-9]*).tsx'
39
- )
40
- &&
41
- request.type === 'import'
42
- ),
43
- replace: (request, matches, t) => {
44
-
45
- if (request.imported.type !== 'all')
46
- return;
47
-
48
- const imports: types.ImportDeclaration[] = [];
49
-
50
- // const routes = {
51
- // <chunkId1>: () => import(/* webpackChunkName: '<chunkId>' */ "<file>"),
52
- // <chunkId2>: () => require("<file>").default,
53
- // }
54
-
55
- const pageLoaders: types.ObjectProperty[] = [];
56
- for (const file of matches) {
57
-
58
- // Exclude layouts
59
- if (file.filename.includes("/_layout/")) {
60
- //console.log("Exclude", file, 'from pages loaders (its a layout)');
61
- continue;
62
- }
63
-
64
- // Page config
65
- const { chunkId } = cli.paths.getPageChunk(app, file.filename);
66
- const preloadPage = routesToPreload.includes(chunkId);
67
-
68
- // Preload = use sync import
69
- if (preloadPage) {
70
-
71
- // import <chunkId> from "<file>";
72
- imports.push(
73
- t.importDeclaration(
74
- [t.importSpecifier(
75
- t.identifier(chunkId),
76
- t.identifier('__register'),
77
- )],
78
- t.stringLiteral(file.filename)
79
- )
80
- );
81
-
82
- // { <chunkId>: <chunkId> }
83
- pageLoaders.push(
84
- t.objectProperty(
85
- t.stringLiteral(chunkId),
86
- t.identifier(chunkId)
87
- )
88
- );
89
-
90
- // Otherwise, use async import + chunk name
91
- } else {
92
-
93
- // <chunkId>: () => ...
94
- pageLoaders.push(
95
- t.objectProperty(
96
-
97
- t.stringLiteral(chunkId),
98
- // () => import(/* webpackChunkName: '<chunkId>' */ "<file>")
99
- t.arrowFunctionExpression([], t.callExpression(
100
-
101
- t.import(), [t.addComment(
102
- t.stringLiteral(file.filename),
103
- "leading",
104
- "webpackChunkName: '" + chunkId + "'"
105
- )]
106
- ))
107
- )
108
- )
109
- }
110
- }
111
-
112
- /*console.log( generate(t.variableDeclaration("const", [t.variableDeclarator(
113
- t.identifier(request.imported.name),
114
- t.objectExpression(pageLoaders)
115
- )])).code );*/
116
-
117
- return [
118
- ...imports,
119
- // const routes = { ... }
120
- t.variableDeclaration("const", [t.variableDeclarator(
121
- t.identifier(request.imported.name),
122
- t.objectExpression(pageLoaders)
123
- )])
124
- ]
125
-
126
- }
127
- })