5htp 0.0.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.
Files changed (35) hide show
  1. package/package.json +94 -0
  2. package/src/commands/build.ts +32 -0
  3. package/src/commands/deploy/app.ts +29 -0
  4. package/src/commands/deploy/web.ts +62 -0
  5. package/src/commands/dev.ts +100 -0
  6. package/src/compiler/client/identite.ts +70 -0
  7. package/src/compiler/client/index.ts +335 -0
  8. package/src/compiler/common/babel/index.ts +261 -0
  9. package/src/compiler/common/babel/plugins/form.ts +191 -0
  10. package/src/compiler/common/babel/plugins/icones-svg.ts +350 -0
  11. package/src/compiler/common/babel/plugins/importations.ts +337 -0
  12. package/src/compiler/common/babel/plugins/injection-dependances/index.ts +223 -0
  13. package/src/compiler/common/babel/plugins/injection-dependances/remplacerFonction.ts +226 -0
  14. package/src/compiler/common/babel/plugins/models.ts +241 -0
  15. package/src/compiler/common/babel/plugins/pages.ts +185 -0
  16. package/src/compiler/common/babel/plugins/queries/index.ts +166 -0
  17. package/src/compiler/common/files/autres.ts +37 -0
  18. package/src/compiler/common/files/images.ts +19 -0
  19. package/src/compiler/common/files/style.ts +64 -0
  20. package/src/compiler/common/index.ts +148 -0
  21. package/src/compiler/common/plugins/indexage/_utils/Stringify.ts +72 -0
  22. package/src/compiler/common/plugins/indexage/_utils/annotations.ts +88 -0
  23. package/src/compiler/common/plugins/indexage/_utils/iterateur.ts +52 -0
  24. package/src/compiler/common/plugins/indexage/icones-svg/index.ts +198 -0
  25. package/src/compiler/common/plugins/indexage/index.ts +132 -0
  26. package/src/compiler/common/plugins/indexage/indexeur.ts +13 -0
  27. package/src/compiler/common/plugins/indexage/injection-dependances/index.ts +68 -0
  28. package/src/compiler/index.ts +86 -0
  29. package/src/compiler/server/index.ts +177 -0
  30. package/src/index.ts +192 -0
  31. package/src/paths.ts +158 -0
  32. package/src/print.ts +12 -0
  33. package/src/utils/index.ts +22 -0
  34. package/src/utils/keyboard.ts +78 -0
  35. package/tsconfig.json +38 -0
@@ -0,0 +1,226 @@
1
+
2
+ import * as types from '@babel/types'
3
+ import generate from "@babel/generator";
4
+
5
+ const servicesViaContexte: {
6
+ [nomService: string]: string
7
+ } = {
8
+ User: 'user',
9
+
10
+ Request: 'req',
11
+ Response: 'res',
12
+ NextFunction: 'next'
13
+ } as const
14
+
15
+ const debug = false
16
+
17
+ export default (t: typeof types) => {
18
+
19
+ function remplacerFonction(arg: types.ArrowFunctionExpression): null | types.ArrowFunctionExpression;
20
+ function remplacerFonction(arg: types.ClassMethod): null | types.ClassMethod;
21
+ function remplacerFonction(
22
+ arg: types.ArrowFunctionExpression | types.ClassMethod
23
+ ): null | types.ArrowFunctionExpression | types.ClassMethod {
24
+
25
+ const dejaTraite = (
26
+ arg.params.length === 1
27
+ &&
28
+ arg.params[0].type === 'RestElement'
29
+ )
30
+ if (dejaTraite)
31
+ return null;
32
+
33
+ // Return null = inchangé
34
+ if (arg.body.type !== 'BlockStatement')
35
+ return null;
36
+
37
+ let declarations: types.VariableDeclarator[] = [];
38
+ let instanciations: types.ExpressionStatement[] = [];
39
+ let extractions: types.ExpressionStatement[] = [];
40
+
41
+ // Transforme les paramètres en une liste d'instanciations
42
+ for (let iParam = 0; iParam < arg.params.length; iParam++) {
43
+ const param = arg.params[iParam];
44
+
45
+ // utilisateur: User
46
+ if (
47
+ param.type === 'Identifier' && param.typeAnnotation
48
+ &&
49
+ param.typeAnnotation.type === 'TSTypeAnnotation'
50
+ &&
51
+ param.typeAnnotation.typeAnnotation.type === 'TSTypeReference'
52
+ &&
53
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier'
54
+ ) {
55
+
56
+ const typeParam = param.typeAnnotation.typeAnnotation.typeName.name;
57
+ const nomParam = param.name;
58
+
59
+ // Déclaration
60
+ declarations.push(
61
+ t.variableDeclarator(
62
+ t.identifier(nomParam)
63
+ )
64
+ );
65
+
66
+ // Instanciation (quand args[0] = contexte)
67
+ if (typeParam in servicesViaContexte) {
68
+
69
+ // <nomParam> = args[ 0 ][ servicesViaContexte[ typeParam ] ];
70
+ instanciations.push(
71
+ t.expressionStatement(
72
+ t.assignmentExpression(
73
+ '=',
74
+ t.identifier(nomParam),
75
+ t.memberExpression(
76
+ t.memberExpression(
77
+ t.identifier('args'),
78
+ t.numericLiteral(0),
79
+ true
80
+ ),
81
+ t.identifier(servicesViaContexte[typeParam])
82
+ )
83
+ )
84
+ )
85
+ )
86
+
87
+ // Le type du paramètre est un service reconnu
88
+ } else if (this.servicesImportes[typeParam] !== undefined) {
89
+
90
+ // <nomParam> = new <typeParam>( args[0] );
91
+ instanciations.push(
92
+ t.expressionStatement(
93
+ t.assignmentExpression(
94
+ '=',
95
+ t.identifier(nomParam),
96
+ t.newExpression(
97
+ t.identifier(typeParam),
98
+ [
99
+ t.memberExpression(
100
+ t.identifier('args'),
101
+ t.numericLiteral(0),
102
+ true
103
+ )
104
+ ]
105
+ )
106
+ )
107
+ )
108
+ );
109
+
110
+ } else {
111
+ console.log(this.servicesImportes);
112
+ throw new Error(`Impossible de trouver l'import associée au type portant pour nom ${typeParam} (fichier: ${this.fichier}). Liste des iportations trouvées au dessus.`)
113
+ }
114
+
115
+ // Extractions
116
+ // <nomParam> = args[ <index> ]
117
+ extractions.push(
118
+ t.expressionStatement(
119
+ t.assignmentExpression(
120
+ '=',
121
+ t.identifier(nomParam),
122
+ t.memberExpression(
123
+ t.identifier('args'),
124
+ t.identifier( iParam.toString() ),
125
+ true
126
+ )
127
+ )
128
+ )
129
+ );
130
+
131
+ }
132
+ }
133
+
134
+ // Inchangé
135
+ if (instanciations.length === 0)
136
+ return null;
137
+
138
+ const conditionSiDoitInstancier = (
139
+ t.logicalExpression(
140
+ '&&',
141
+ t.logicalExpression(
142
+ '&&',
143
+
144
+ // args[0] !== undefined
145
+ t.binaryExpression(
146
+ '!==',
147
+ t.memberExpression(
148
+ t.identifier('args'),
149
+ t.numericLiteral(0),
150
+ true
151
+ ),
152
+ t.identifier('undefined')
153
+ ),
154
+
155
+ // typeof args[0] === 'object'
156
+ t.binaryExpression(
157
+ '===',
158
+ t.unaryExpression(
159
+ 'typeof',
160
+ t.memberExpression(
161
+ t.identifier('args'),
162
+ t.identifier('0'),
163
+ true
164
+ )
165
+ ),
166
+ t.stringLiteral('object')
167
+ )
168
+ ),
169
+
170
+ // args[0].type === 'contexte_requete'
171
+ t.binaryExpression(
172
+ '===',
173
+ t.memberExpression(
174
+ t.memberExpression(
175
+ t.identifier('args'),
176
+ t.identifier('0'),
177
+ true
178
+ ),
179
+ t.identifier('type')
180
+ ),
181
+ t.stringLiteral('contexte_requete')
182
+ )
183
+ )
184
+ )
185
+
186
+ const body = t.blockStatement([
187
+ t.variableDeclaration('let', declarations),
188
+
189
+ // if (args[0] !== undefined && typeof args[0] === 'object' && args[0].type === 'contexte_requete')
190
+ t.ifStatement(
191
+ conditionSiDoitInstancier,
192
+
193
+ t.blockStatement(instanciations),
194
+
195
+ t.blockStatement(extractions)
196
+ ),
197
+ ...arg.body.body
198
+ ]);
199
+
200
+ // Remplacement paramètres et ajout des instanciations
201
+ const remplacement = arg.type === 'ArrowFunctionExpression'
202
+ ? t.arrowFunctionExpression(
203
+ [t.restElement( t.identifier('args') )],
204
+ body,
205
+ arg.async
206
+ )
207
+ : t.classMethod(
208
+ 'constructor',
209
+ t.identifier('constructor'),
210
+ [t.restElement( t.identifier('args') )],
211
+ body
212
+ )
213
+
214
+ if (debug) {
215
+ console.log('-----------------------------');
216
+ console.log(generate(arg).code);
217
+ console.log('=>');
218
+ console.log(generate(remplacement).code);
219
+ console.log('-----------------------------');
220
+ }
221
+
222
+ return remplacement;
223
+ }
224
+
225
+ return remplacerFonction;
226
+ }
@@ -0,0 +1,241 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import * as types from '@babel/types'
7
+ import type { PluginObj, NodePath } from '@babel/core';
8
+ import generate from '@babel/generator';
9
+
10
+ // Core
11
+ import type { TAppSide } from '@cli/index';
12
+
13
+ /*----------------------------------
14
+ - WEBPACK RULE
15
+ ----------------------------------*/
16
+
17
+ type TOptions = {
18
+ side: TAppSide
19
+ }
20
+
21
+ module.exports = (options: TOptions) => ({
22
+ test: "**/server/models/**/*.ts",
23
+ plugins: [
24
+ [Plugin, options]
25
+ ]
26
+ })
27
+
28
+ module.exports.Plugin = Plugin;
29
+
30
+ const debug = true;
31
+
32
+ const metasKey = 'metadata';
33
+
34
+ /*----------------------------------
35
+ - PLUGIN
36
+ ----------------------------------*/
37
+ function Plugin(babel, { }: TOptions) {
38
+
39
+ const t = babel.types as typeof types;
40
+
41
+ const plugin: PluginObj<{ filename: string }> = {
42
+ pre(state) {
43
+
44
+ this.filename = state.opts.filename as string;
45
+
46
+ },
47
+ visitor: {
48
+ Program(path) {
49
+
50
+ const filename = this.filename;
51
+
52
+ // Lorsque les visiteurs sont déclarés à la racine du plugin,
53
+ // Impossible d'obtenir les ast des décorateurs car ils ont déjà été compilés ...
54
+ // Pourquoi cela fonctionne en passant par Program.traverse ?
55
+ path.traverse({
56
+ Decorator(path) {
57
+
58
+ injectMetadatas(path, filename, t);
59
+
60
+ },
61
+ });
62
+
63
+
64
+ }
65
+
66
+ }
67
+ };
68
+
69
+ return plugin;
70
+ }
71
+
72
+ /*----------------------------------
73
+ - EXTRACTION
74
+ ----------------------------------*/
75
+ function injectMetadatas( path: NodePath<types.Decorator>, filename: string, t: typeof types ) {
76
+
77
+ // @Table( <database>, <table>, <options?> )
78
+ const expression = path.node.expression;
79
+ if (!(
80
+ expression.type === 'CallExpression'
81
+ &&
82
+ expression.callee.type === 'Identifier'
83
+ &&
84
+ expression.callee.name === 'Table'
85
+ &&
86
+ expression.arguments.length >= 2
87
+ ))
88
+ return;
89
+
90
+ // Class
91
+ const classe = path.parent;
92
+ if (classe.type !== 'ClassDeclaration')
93
+ return;
94
+
95
+ debug && console.log(`Processing class ${classe.id.name}`);
96
+
97
+ // Only process if metadata are not already defined
98
+ let [database, table, options] = expression.arguments;
99
+ if (options !== undefined) {
100
+
101
+ if (options.type !== 'ObjectExpression')
102
+ throw new Error(`Error in ${filename}: The 3rd argument of @Table must be an object expression.`);
103
+
104
+ const hasMetas = options.properties.some(p =>
105
+ p.type === 'ObjectProperty'
106
+ &&
107
+ p.key.type === 'Identifier'
108
+ &&
109
+ p.key.name === metasKey
110
+ );
111
+
112
+ if (hasMetas) {
113
+ debug && console.log(`Metadata already provides for class ${classe.id.name} (${filename})`);
114
+ return;
115
+ }
116
+ }
117
+
118
+ // Extract metadata
119
+ const attributes = extractMetadata(classe, t);
120
+ //debug && console.log( generate(attributes).code );
121
+ const metasProperty = t.objectProperty(
122
+ t.identifier(metasKey),
123
+ t.objectExpression(attributes)
124
+ )
125
+
126
+ // Insert metas in options
127
+ if (options === undefined)
128
+ options = t.objectExpression([metasProperty]);
129
+ else
130
+ options = t.objectExpression([...options.properties, metasProperty]);
131
+
132
+ // Update decorator
133
+ path.replaceWith(t.decorator(
134
+ t.callExpression(t.identifier('Table'), [
135
+ database,
136
+ table,
137
+ options
138
+ ])
139
+ ));
140
+ }
141
+
142
+ function extractMetadata(classe: types.ClassDeclaration, t: typeof types) {
143
+
144
+ const attributes: types.ObjectProperty[] = [];
145
+
146
+ // Lecture des propriétés et méthodes de la classe
147
+ for (const prop of classe.body.body) {
148
+
149
+ if (!(
150
+ // non-statique
151
+ !prop.static
152
+ &&
153
+ (
154
+ // Propriété simple
155
+ prop.type === 'ClassProperty'
156
+ ||
157
+ // Getter
158
+ (prop.type === 'ClassMethod' && prop.kind === 'get')
159
+ )
160
+ &&
161
+ // Publique
162
+ prop.accessibility === 'public'
163
+ &&
164
+ prop.key.type === 'Identifier'
165
+ ))
166
+ continue;
167
+
168
+ const nomProp = prop.key.name;
169
+
170
+ // Détermine si la propriété est exposée à l'api
171
+ // = possède le décorateur @API()
172
+ const exposeToAPI = prop.decorators && prop.decorators.some((decorateur) =>
173
+ decorateur.expression.type === 'CallExpression'
174
+ &&
175
+ decorateur.expression.callee.type === 'Identifier'
176
+ &&
177
+ decorateur.expression.callee.name === 'API'
178
+ );
179
+
180
+ if (!exposeToAPI) continue;
181
+
182
+ let type: any;
183
+ if (prop.type === 'ClassProperty')
184
+ type = prop.typeAnnotation;
185
+ else
186
+ type = prop.returnType;
187
+
188
+ // Verif si type spécifié
189
+ if (!type)
190
+ throw new Error(`Unable to extract type of ${classe.id.name}.${prop.key.name}.`);
191
+
192
+ // Sérialisation du type
193
+ const typeString = generate(type.typeAnnotation).code;
194
+
195
+ debug && console.log( classe.id.name + '.' + nomProp + ': ' + typeString );
196
+
197
+ // Sérialisation valeur defaut
198
+ const defaut = prop.type === 'ClassProperty' && prop.value && ('value' in prop.value)
199
+ ? prop.value
200
+ : t.identifier('undefined')
201
+
202
+ attributes.push(
203
+ t.objectProperty( t.identifier(nomProp), t.objectExpression([
204
+
205
+ t.objectProperty(
206
+ t.identifier('nom'),
207
+ t.stringLiteral(nomProp)
208
+ ),
209
+
210
+ t.objectProperty(
211
+ t.identifier('nomComplet'),
212
+ t.stringLiteral(prop.optional ? nomProp + '?' : nomProp)
213
+ ),
214
+
215
+ t.objectProperty(
216
+ t.identifier('type'),
217
+ t.stringLiteral(typeString)
218
+ ),
219
+
220
+ t.objectProperty(
221
+ t.identifier('optionnel'),
222
+ t.booleanLiteral(prop.optional === true)
223
+ ),
224
+
225
+ t.objectProperty(
226
+ t.identifier('api'),
227
+ t.booleanLiteral(exposeToAPI)
228
+ ),
229
+
230
+ t.objectProperty(
231
+ t.identifier('defaut'),
232
+ defaut
233
+ ),
234
+
235
+ ]))
236
+ );
237
+ }
238
+
239
+ return attributes;
240
+
241
+ }
@@ -0,0 +1,185 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import * as types from '@babel/types'
7
+ import type { PluginObj, NodePath } from '@babel/core';
8
+ import generate from '@babel/generator';
9
+
10
+ // Core
11
+ import cli from '@cli';
12
+ import { TAppSide } from '@cli/index';
13
+
14
+ /*----------------------------------
15
+ - WEBPACK RULE
16
+ ----------------------------------*/
17
+
18
+ type TOptions = {
19
+ side: TAppSide
20
+ }
21
+
22
+ module.exports = (options: TOptions) => ({
23
+ test: "**/client/pages/**/*.tsx",
24
+ plugins: [
25
+ [Plugin, options]
26
+ ]
27
+ })
28
+
29
+ const debug = false;
30
+
31
+ /*----------------------------------
32
+ - PLUGIN
33
+ ----------------------------------*/
34
+ function Plugin(babel, { side }: TOptions) {
35
+
36
+ const t = babel.types as typeof types;
37
+ let program: NodePath<types.Program>;
38
+
39
+ const plugin: PluginObj<{
40
+ filename: string
41
+ }> = {
42
+ pre(state) {
43
+
44
+ this.filename = state.opts.filename as string;
45
+
46
+ },
47
+ visitor: {
48
+
49
+ Program(path) {
50
+ program = path;
51
+ },
52
+
53
+ CallExpression(path) {
54
+
55
+ // route.xxx( <PATH>, ... )
56
+ if (!(
57
+ path.node.callee.type === 'MemberExpression'
58
+ &&
59
+ path.node.callee.object.type === "Identifier"
60
+ &&
61
+ path.node.callee.object.name === "route"
62
+ &&
63
+ path.node.arguments.length >= 2
64
+ ))
65
+ return;
66
+
67
+ const [routePath, ...routeArgs] = path.node.arguments;
68
+ debug && console.log(`[routes]`, this.filename, ...routeArgs.map(n => n.type));
69
+
70
+ // Inject chunk id in options (2nd arg)
71
+ const status = addChunkId(routeArgs, this.filename);
72
+ if (status === 'ALREADY_PROCESSED')
73
+ return;
74
+
75
+ // Transform 2nd arg of renderer to a useContext spread
76
+ addRendererContext(routeArgs, this.filename);
77
+
78
+ const replacement = t.callExpression( path.node.callee, [ routePath, ...routeArgs ]);
79
+ debug && console.log( generate(replacement).code );
80
+
81
+ // Force export default
82
+ if (path.parent.type === 'ExportDefaultDeclaration')
83
+ path.replaceWith( replacement );
84
+ else
85
+ path.parentPath.replaceWith(
86
+ t.exportDefaultDeclaration( replacement )
87
+ )
88
+
89
+ }
90
+
91
+ }
92
+ };
93
+
94
+ function addChunkId(
95
+ routeArgs: types.CallExpression["arguments"],
96
+ filename: string
97
+ ): void | 'ALREADY_PROCESSED' {
98
+
99
+ if (routeArgs[0].type === 'ObjectExpression') {
100
+
101
+ if (routeArgs[0].properties.some(o =>
102
+ o.type === 'ObjectProperty'
103
+ &&
104
+ o.key.type === 'Identifier'
105
+ &&
106
+ o.key.name === 'id'
107
+ )) {
108
+ debug && console.log(`[routes]`, filename, 'Already Processed');
109
+ return 'ALREADY_PROCESSED';
110
+ }
111
+
112
+ } else
113
+ routeArgs.unshift(t.objectExpression([]));
114
+
115
+ const { filepath, chunkId } = cli.paths.getPageChunk(filename);
116
+ debug && console.log(`[routes]`, filename, '=>', chunkId);
117
+
118
+ // Add object property
119
+ (routeArgs[0] as types.ObjectExpression).properties.push(
120
+ t.objectProperty(
121
+ t.identifier('id'),
122
+ t.stringLiteral(chunkId)
123
+ ),
124
+ t.objectProperty(
125
+ t.identifier('filepath'),
126
+ t.stringLiteral(filepath)
127
+ )
128
+ );
129
+
130
+ }
131
+
132
+ function addRendererContext(
133
+ routeArgs: types.CallExpression["arguments"],
134
+ filename: string
135
+ ) {
136
+
137
+ // ( <data>, { response, api }) => ....
138
+ const renderer = routeArgs[ routeArgs.length - 1 ];
139
+ if (!(
140
+ renderer.type === 'ArrowFunctionExpression'
141
+ &&
142
+ renderer.params.length > 1
143
+ ))
144
+ return;
145
+
146
+ // Remove 2nd arg (renderer = react component, so only 1 arg for props)
147
+ const declaration = renderer.params.pop() as types.ArrowFunctionExpression["params"][number];
148
+ // const <param2> = useContext();
149
+ const ctxDeclaration = t.variableDeclaration('const', [t.variableDeclarator(
150
+ declaration,
151
+ t.callExpression(t.identifier('useContext'), [])
152
+ )])
153
+
154
+ // Add Declaration
155
+ switch (renderer.body.type) {
156
+ case 'BlockStatement':
157
+ renderer.body.body.unshift(ctxDeclaration);
158
+ break;
159
+ // TODO: Si type === JSXElement, remplacer par BlockStatement (ctxDeclaration + return JSX)
160
+ /*case 'BlockStatement':
161
+ renderer.re
162
+ break;*/
163
+ default:
164
+ throw new Error(`Unknown body type for the renderer: ${renderer.body.type}`);
165
+ }
166
+
167
+ // Add usecontext import if it doesn't exists
168
+ if (program.scope.bindings["useContext"] === undefined) {
169
+
170
+ debug && console.log(`[routes]`, filename, `Adding useContext import from @context`);
171
+
172
+ program.unshiftContainer(
173
+ 'body',
174
+ t.importDeclaration(
175
+ [t.importDefaultSpecifier(t.identifier('useContext'))],
176
+ t.stringLiteral('@client/context')
177
+ )
178
+ );
179
+ }
180
+
181
+
182
+ }
183
+
184
+ return plugin;
185
+ }