5htp 0.6.3-1 → 0.6.3-2
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/index.ts +0 -10
- package/compiler/common/babel/plugins/services.ts +263 -13
- package/compiler/common/index.ts +0 -9
- package/compiler/index.ts +5 -3
- package/package.json +1 -1
- package/compiler/common/babel/plugins/form.ts +0 -191
- package/compiler/common/babel/plugins/icones-svg.ts +0 -376
- package/compiler/common/babel/plugins/injection-dependances/index.ts +0 -225
- package/compiler/common/babel/plugins/injection-dependances/remplacerFonction.ts +0 -226
- package/compiler/common/babel/plugins/queries/index.ts +0 -166
- package/compiler/common/plugins/indexage/_utils/Stringify.ts +0 -72
- package/compiler/common/plugins/indexage/_utils/annotations.ts +0 -88
- package/compiler/common/plugins/indexage/_utils/iterateur.ts +0 -52
- package/compiler/common/plugins/indexage/icones-svg/index.ts +0 -207
- package/compiler/common/plugins/indexage/index.ts +0 -134
- package/compiler/common/plugins/indexage/indexeur.ts +0 -13
- package/compiler/common/plugins/indexage/injection-dependances/index.ts +0 -68
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
// Npm
|
|
6
6
|
import type webpack from 'webpack';
|
|
7
7
|
import PresetBabel, { Options } from '@babel/preset-env';
|
|
8
|
-
// Core
|
|
9
|
-
import PluginIndexage from '../plugins/indexage';
|
|
10
8
|
|
|
11
9
|
import cli from '@cli';
|
|
12
10
|
import type { TAppSide, App } from '@cli/app';
|
|
@@ -70,10 +68,6 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
|
|
|
70
68
|
// Désactive car ralenti compilation
|
|
71
69
|
cacheCompression: false,
|
|
72
70
|
|
|
73
|
-
metadataSubscribers: [
|
|
74
|
-
PluginIndexage.metadataContextFunctionName
|
|
75
|
-
],
|
|
76
|
-
|
|
77
71
|
compact: !dev,
|
|
78
72
|
|
|
79
73
|
// https://babeljs.io/docs/usage/options/
|
|
@@ -165,14 +159,10 @@ module.exports = (app: App, side: TAppSide, dev: boolean): webpack.RuleSetRule[]
|
|
|
165
159
|
],
|
|
166
160
|
|
|
167
161
|
overrides: [
|
|
168
|
-
|
|
169
|
-
require('./plugins/icones-svg')(app),
|
|
170
162
|
|
|
171
163
|
...(side === 'client' ? [
|
|
172
164
|
|
|
173
165
|
] : [
|
|
174
|
-
//require('./plugins/queries'),
|
|
175
|
-
//require('./plugins/injection-dependances'),
|
|
176
166
|
]),
|
|
177
167
|
]
|
|
178
168
|
}
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
import * as types from '@babel/types'
|
|
7
7
|
import type { NodePath, PluginObj } from '@babel/core';
|
|
8
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';
|
|
9
13
|
|
|
10
14
|
// Core
|
|
11
15
|
import cli from '@cli';
|
|
@@ -38,6 +42,170 @@ type TImportedIndex = {
|
|
|
38
42
|
source: TImportSource // container | application | models
|
|
39
43
|
}
|
|
40
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
|
+
|
|
41
209
|
/*----------------------------------
|
|
42
210
|
- PLUGIN
|
|
43
211
|
----------------------------------*/
|
|
@@ -75,6 +243,9 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
75
243
|
// Count how many total imports we transform
|
|
76
244
|
importedCount: number,
|
|
77
245
|
routeMethods: string[],
|
|
246
|
+
routePaths: Set<string>,
|
|
247
|
+
routesIndex: TRoutesIndex,
|
|
248
|
+
contextGuardedClassMethods: WeakSet<types.ClassMethod>,
|
|
78
249
|
|
|
79
250
|
// For every local identifier, store info about how it should be rewritten
|
|
80
251
|
imported: {
|
|
@@ -92,6 +263,10 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
92
263
|
this.debug = debug || false;
|
|
93
264
|
|
|
94
265
|
this.routeMethods = [];
|
|
266
|
+
this.routePaths = new Set();
|
|
267
|
+
|
|
268
|
+
this.routesIndex = getRoutesIndex(app.paths.root);
|
|
269
|
+
this.contextGuardedClassMethods = new WeakSet();
|
|
95
270
|
},
|
|
96
271
|
|
|
97
272
|
visitor: {
|
|
@@ -109,28 +284,21 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
109
284
|
|
|
110
285
|
for (const decorator of node.decorators) {
|
|
111
286
|
|
|
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
|
-
);
|
|
287
|
+
const isRoute = isRouteDecoratorExpression(decorator.expression);
|
|
125
288
|
|
|
126
289
|
if (!isRoute) continue;
|
|
127
290
|
|
|
128
291
|
const methodName = node.key.name;
|
|
129
292
|
this.routeMethods.push( methodName );
|
|
130
293
|
|
|
294
|
+
const routePath = getRoutePathFromDecoratorExpression(decorator.expression);
|
|
295
|
+
if (routePath)
|
|
296
|
+
this.routePaths.add(routePath);
|
|
131
297
|
}
|
|
132
298
|
}
|
|
133
299
|
});
|
|
300
|
+
|
|
301
|
+
updateRoutesIndexForFile(this.routesIndex, this.filename, this.routePaths);
|
|
134
302
|
},
|
|
135
303
|
|
|
136
304
|
/**
|
|
@@ -203,6 +371,88 @@ function Plugin(babel, { app, side, debug }: TOptions) {
|
|
|
203
371
|
path.replaceWithMultiple(replaceWith);
|
|
204
372
|
},
|
|
205
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
|
+
|
|
206
456
|
// This visitor fires for every class method.
|
|
207
457
|
ClassMethod(path) {
|
|
208
458
|
|
package/compiler/common/index.ts
CHANGED
|
@@ -8,9 +8,6 @@ import dayjs from 'dayjs';
|
|
|
8
8
|
|
|
9
9
|
// Plugins
|
|
10
10
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
11
|
-
import PluginIndexage from './plugins/indexage';
|
|
12
|
-
import IconesSvg from './plugins/indexage/icones-svg';
|
|
13
|
-
import InjectDeps from './plugins/indexage/injection-dependances';
|
|
14
11
|
|
|
15
12
|
// Core
|
|
16
13
|
import cli from '../..';
|
|
@@ -88,12 +85,6 @@ export default function createCommonConfig(
|
|
|
88
85
|
|
|
89
86
|
}),
|
|
90
87
|
|
|
91
|
-
new PluginIndexage(side === 'client' ? {
|
|
92
|
-
'icones-svg': new IconesSvg(app),
|
|
93
|
-
} : {
|
|
94
|
-
//'injection-dependances': new InjectDeps,
|
|
95
|
-
}),
|
|
96
|
-
|
|
97
88
|
...(side === 'client' && cli.args.analyze ? [
|
|
98
89
|
|
|
99
90
|
new BundleAnalyzerPlugin({
|
package/compiler/index.ts
CHANGED
|
@@ -344,13 +344,15 @@ export default (): ClientContext => React.useContext<ClientContext>(ReactClientC
|
|
|
344
344
|
// @/server/.generated/app.ts
|
|
345
345
|
fs.outputFileSync(
|
|
346
346
|
path.join( app.paths.server.generated, 'app.ts'),
|
|
347
|
-
`
|
|
347
|
+
`
|
|
348
|
+
import { Application } from '@server/app/index';
|
|
349
|
+
import { ServicesContainer } from '@server/app/service/container';
|
|
348
350
|
|
|
349
351
|
${imported.join('\n')}
|
|
350
352
|
|
|
351
|
-
export default class ${appClassIdentifier} extends Application {
|
|
353
|
+
export default class ${appClassIdentifier} extends Application<ServicesContainer, CurrentUser> {
|
|
352
354
|
|
|
353
|
-
//
|
|
355
|
+
// Make sure the services typigs are reflecting the config and referring to the app
|
|
354
356
|
${sortedServices.map(service =>
|
|
355
357
|
`public ${service.name}!: ReturnType<${appClassIdentifier}["registered"]["${service.id}"]["start"]>;`
|
|
356
358
|
).join('\n')}
|
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-2",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
import { PluginObj } from '@babel/core';
|
|
6
|
-
|
|
7
|
-
import * as types from '@babel/types'
|
|
8
|
-
import generate from '@babel/generator';
|
|
9
|
-
|
|
10
|
-
/*----------------------------------
|
|
11
|
-
- WEBPACK RULE
|
|
12
|
-
----------------------------------*/
|
|
13
|
-
module.exports = {
|
|
14
|
-
test: "**/client/**/*.tsx",
|
|
15
|
-
plugins: [
|
|
16
|
-
[Plugin]
|
|
17
|
-
]
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const debug = false
|
|
21
|
-
|
|
22
|
-
/*----------------------------------
|
|
23
|
-
- PLUGIN
|
|
24
|
-
----------------------------------*/
|
|
25
|
-
function Plugin (babel) {
|
|
26
|
-
|
|
27
|
-
const t = babel.types as typeof types;
|
|
28
|
-
|
|
29
|
-
const plugin: PluginObj<{
|
|
30
|
-
fichier: string,
|
|
31
|
-
cancel: boolean
|
|
32
|
-
}> = {
|
|
33
|
-
pre(state) {
|
|
34
|
-
|
|
35
|
-
this.fichier = state.opts.filename as string;
|
|
36
|
-
|
|
37
|
-
if (!('useForm' in state.scope.bindings))
|
|
38
|
-
this.cancel = true;
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
visitor: {
|
|
42
|
-
JSXElement(instruction) {
|
|
43
|
-
|
|
44
|
-
if (this.cancel === true)
|
|
45
|
-
return;
|
|
46
|
-
|
|
47
|
-
const balise = instruction.node.openingElement;
|
|
48
|
-
|
|
49
|
-
/*
|
|
50
|
-
<Champs.metas.titre className="full" attrsChamp={{ className: "h1" }} />
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
if (!(
|
|
54
|
-
balise.selfClosing === true
|
|
55
|
-
&&
|
|
56
|
-
balise.name.type === 'JSXMemberExpression'
|
|
57
|
-
&&
|
|
58
|
-
balise.name.property.type === 'JSXIdentifier'
|
|
59
|
-
))
|
|
60
|
-
return;
|
|
61
|
-
|
|
62
|
-
debug && console.log(`[compilation][babel][form] Original: `, generate(instruction.node).code);
|
|
63
|
-
|
|
64
|
-
// Si le premier element du memberexpression est Champ
|
|
65
|
-
let nomA: types.JSXMemberExpression | types.JSXIdentifier = balise.name;
|
|
66
|
-
while (nomA.type === 'JSXMemberExpression')
|
|
67
|
-
nomA = nomA.object;
|
|
68
|
-
if (!nomA.name.startsWith('Champs'))
|
|
69
|
-
return;
|
|
70
|
-
|
|
71
|
-
// Ne pas parcourir les élements enfant
|
|
72
|
-
// Avec .stop, babel arrête d'itérer les élements voisins à partir du 6ème - 7ème
|
|
73
|
-
//instruction.stop();
|
|
74
|
-
instruction.skip();
|
|
75
|
-
|
|
76
|
-
// Transformation de la lste des attributs en un objet
|
|
77
|
-
/*
|
|
78
|
-
className="full" attrsChamp={{ className: "h1" }}
|
|
79
|
-
|
|
80
|
-
=>
|
|
81
|
-
|
|
82
|
-
{ className: "full", attrsChamp: { className: "h1" } }
|
|
83
|
-
*/
|
|
84
|
-
let objAttributs: types.ObjectProperty[] = [];
|
|
85
|
-
for (const attribut of balise.attributes)
|
|
86
|
-
if (
|
|
87
|
-
attribut.type === 'JSXAttribute' &&
|
|
88
|
-
attribut.value !== undefined &&
|
|
89
|
-
typeof attribut.name.name === "string"
|
|
90
|
-
) {
|
|
91
|
-
|
|
92
|
-
let propValue: types.ObjectProperty["value"];
|
|
93
|
-
if (attribut.value === null) // <Champ.titre autoFocus />
|
|
94
|
-
propValue = t.booleanLiteral(true);
|
|
95
|
-
else if (attribut.value.type !== 'JSXExpressionContainer')
|
|
96
|
-
propValue = attribut.value;
|
|
97
|
-
else if (attribut.value.expression.type !== 'JSXEmptyExpression')
|
|
98
|
-
propValue = attribut.value.expression;
|
|
99
|
-
else
|
|
100
|
-
propValue = t.nullLiteral();
|
|
101
|
-
|
|
102
|
-
objAttributs.push(
|
|
103
|
-
t.objectProperty(
|
|
104
|
-
t.identifier( attribut.name.name ),
|
|
105
|
-
propValue
|
|
106
|
-
)
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Traverse chaque branche du chemin du champ, dans l'ordre inverse
|
|
111
|
-
// NOTE: on aurai pu reconstituer le chemin et créer les memberexpressions en une seule itération
|
|
112
|
-
// Mais le fait d ele faire en deux itérations rend le code plus claire et maintenable
|
|
113
|
-
let cheminComposant: string[] = []
|
|
114
|
-
let brancheA: types.JSXMemberExpression | types.JSXIdentifier = balise.name;
|
|
115
|
-
while (brancheA.type === 'JSXMemberExpression') {
|
|
116
|
-
|
|
117
|
-
const { property } = brancheA;
|
|
118
|
-
|
|
119
|
-
cheminComposant.unshift(property.name)
|
|
120
|
-
brancheA = brancheA.object;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
let cheminSchema: types.MemberExpression | types.OptionalMemberExpression = t.memberExpression(
|
|
124
|
-
t.identifier('Champs'),
|
|
125
|
-
t.identifier('schema')
|
|
126
|
-
);
|
|
127
|
-
let cheminDonnees: types.MemberExpression | types.OptionalMemberExpression = t.memberExpression(
|
|
128
|
-
t.identifier('Champs'),
|
|
129
|
-
t.identifier('data')
|
|
130
|
-
);
|
|
131
|
-
const iDerniereBranche = cheminComposant.length - 1
|
|
132
|
-
for (let iBranche = iDerniereBranche; iBranche >= 0; iBranche--) {
|
|
133
|
-
|
|
134
|
-
const branche = cheminComposant[ iBranche ];
|
|
135
|
-
|
|
136
|
-
cheminSchema = t.optionalMemberExpression(
|
|
137
|
-
cheminSchema,
|
|
138
|
-
t.identifier( branche ),
|
|
139
|
-
undefined,
|
|
140
|
-
true
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
if (iBranche !== iDerniereBranche)
|
|
144
|
-
cheminDonnees = t.optionalMemberExpression(
|
|
145
|
-
cheminDonnees,
|
|
146
|
-
t.identifier(branche),
|
|
147
|
-
undefined,
|
|
148
|
-
true
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Remplacement
|
|
154
|
-
/*
|
|
155
|
-
{Champs._render( Champs.metas?.titre, Champs._data.metas?.titre, 'metas.titre', {
|
|
156
|
-
className: "full",
|
|
157
|
-
attrsChamp: { className: "h1" }
|
|
158
|
-
})}
|
|
159
|
-
*/
|
|
160
|
-
const remplacement = t.callExpression(
|
|
161
|
-
|
|
162
|
-
// Champs.render
|
|
163
|
-
t.memberExpression(
|
|
164
|
-
t.identifier('Champs'),
|
|
165
|
-
t.identifier('render')
|
|
166
|
-
),
|
|
167
|
-
[
|
|
168
|
-
// Champs.<chemin>
|
|
169
|
-
cheminSchema,
|
|
170
|
-
|
|
171
|
-
// Champs._data.<chemin>
|
|
172
|
-
cheminDonnees,
|
|
173
|
-
|
|
174
|
-
// Chemin
|
|
175
|
-
t.stringLiteral( cheminComposant.join('.') ),
|
|
176
|
-
|
|
177
|
-
// { <attrs> }
|
|
178
|
-
t.objectExpression(objAttributs)
|
|
179
|
-
]
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
debug && console.log(`[compilation][babel][form] Remplacement: `, generate(remplacement).code );
|
|
183
|
-
|
|
184
|
-
instruction.replaceWith(remplacement);
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
return plugin;
|
|
191
|
-
}
|