5htp 0.2.3 → 0.3.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/package.json +3 -4
- package/readme.md +15 -11
- package/skeleton/src/server/models.ts +117 -0
- package/src/app/config.ts +4 -2
- package/src/app/index.ts +27 -10
- package/src/commands/build.ts +3 -6
- package/src/commands/dev.ts +7 -7
- package/src/compiler/client/index.ts +1 -1
- package/src/compiler/common/babel/index.ts +2 -3
- package/src/compiler/common/babel/plugins/services.ts +122 -90
- package/src/compiler/common/babel/routes/routes.ts +42 -24
- package/src/compiler/common/plugins/indexage/icones-svg/index.ts +11 -12
- package/src/compiler/common/plugins/indexage/index.ts +6 -4
- package/src/compiler/index.ts +193 -73
- package/src/compiler/server/index.ts +3 -3
- package/src/index.ts +9 -8
- package/src/paths.ts +1 -1
- package/src/compiler/common/babel/plugins/models.old.ts +0 -241
- package/src/compiler/common/babel/routes/routes_old.ts +0 -152
- package/src/compiler/common/utils/fixNpmLink.ts +0 -46
|
@@ -1,241 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,152 +0,0 @@
|
|
|
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 App, { TAppSide } from '../../../../app';
|
|
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 app = new App();
|
|
37
|
-
|
|
38
|
-
const t = babel.types as typeof types;
|
|
39
|
-
let program: NodePath<types.Program>;
|
|
40
|
-
|
|
41
|
-
const plugin: PluginObj<{
|
|
42
|
-
filename: string
|
|
43
|
-
}> = {
|
|
44
|
-
pre(state) {
|
|
45
|
-
|
|
46
|
-
this.filename = state.opts.filename as string;
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
visitor: {
|
|
50
|
-
|
|
51
|
-
Program(path) {
|
|
52
|
-
program = path;
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
CallExpression(path) {
|
|
56
|
-
|
|
57
|
-
// route.xxx( <PATH>, ... )
|
|
58
|
-
if (!(
|
|
59
|
-
path.node.callee.type === 'MemberExpression'
|
|
60
|
-
&&
|
|
61
|
-
path.node.callee.object.type === "Identifier"
|
|
62
|
-
&&
|
|
63
|
-
path.node.callee.object.name === "route"
|
|
64
|
-
&&
|
|
65
|
-
path.node.arguments.length >= 2
|
|
66
|
-
))
|
|
67
|
-
return;
|
|
68
|
-
|
|
69
|
-
const [routePath, ...routeArgs] = path.node.arguments;
|
|
70
|
-
debug && console.log(`[routes]`, this.filename, ...routeArgs.map(n => n.type));
|
|
71
|
-
|
|
72
|
-
// Inject chunk id in options (2nd arg)
|
|
73
|
-
const status = addChunkId(routeArgs, this.filename);
|
|
74
|
-
if (status === 'ALREADY_PROCESSED')
|
|
75
|
-
return;
|
|
76
|
-
|
|
77
|
-
// Transform 2nd arg of renderer to a useContext spread
|
|
78
|
-
addRendererContext(routeArgs, this.filename);
|
|
79
|
-
|
|
80
|
-
const replacement = t.callExpression( path.node.callee, [ routePath, ...routeArgs ]);
|
|
81
|
-
debug && console.log( generate(replacement).code );
|
|
82
|
-
|
|
83
|
-
path.replaceWith( replacement );
|
|
84
|
-
|
|
85
|
-
// Force export default
|
|
86
|
-
// NOTE: now done by app-import.ts
|
|
87
|
-
/*if (path.parent.type === 'ExportDefaultDeclaration')
|
|
88
|
-
path.replaceWith( replacement );
|
|
89
|
-
else
|
|
90
|
-
path.parentPath.replaceWith(
|
|
91
|
-
t.exportDefaultDeclaration( replacement )
|
|
92
|
-
)*/
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
function addRendererContext(
|
|
100
|
-
routeArgs: types.CallExpression["arguments"],
|
|
101
|
-
filename: string
|
|
102
|
-
) {
|
|
103
|
-
|
|
104
|
-
// ( <data>, { response, api }) => ....
|
|
105
|
-
const renderer = routeArgs[ routeArgs.length - 1 ];
|
|
106
|
-
if (!(
|
|
107
|
-
renderer.type === 'ArrowFunctionExpression'
|
|
108
|
-
&&
|
|
109
|
-
renderer.params.length > 1
|
|
110
|
-
))
|
|
111
|
-
return;
|
|
112
|
-
|
|
113
|
-
// Remove 2nd arg (renderer = react component, so only 1 arg for props)
|
|
114
|
-
const declaration = renderer.params.pop() as types.ArrowFunctionExpression["params"][number];
|
|
115
|
-
// const <param2> = useContext();
|
|
116
|
-
const ctxDeclaration = t.variableDeclaration('const', [t.variableDeclarator(
|
|
117
|
-
declaration,
|
|
118
|
-
t.callExpression(t.identifier('useContext'), [])
|
|
119
|
-
)])
|
|
120
|
-
|
|
121
|
-
// Add Declaration
|
|
122
|
-
switch (renderer.body.type) {
|
|
123
|
-
case 'BlockStatement':
|
|
124
|
-
renderer.body.body.unshift(ctxDeclaration);
|
|
125
|
-
break;
|
|
126
|
-
// TODO: Si type === JSXElement, remplacer par BlockStatement (ctxDeclaration + return JSX)
|
|
127
|
-
/*case 'BlockStatement':
|
|
128
|
-
renderer.re
|
|
129
|
-
break;*/
|
|
130
|
-
default:
|
|
131
|
-
throw new Error(`Unknown body type for the renderer: ${renderer.body.type}`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Add usecontext import if it doesn't exists
|
|
135
|
-
if (program.scope.bindings["useContext"] === undefined) {
|
|
136
|
-
|
|
137
|
-
debug && console.log(`[routes]`, filename, `Adding useContext import from @context`);
|
|
138
|
-
|
|
139
|
-
program.unshiftContainer(
|
|
140
|
-
'body',
|
|
141
|
-
t.importDeclaration(
|
|
142
|
-
[t.importDefaultSpecifier(t.identifier('useContext'))],
|
|
143
|
-
t.stringLiteral('@/client/context')
|
|
144
|
-
)
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return plugin;
|
|
152
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
|
|
5
|
-
// Npm
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import fs from 'fs-extra';
|
|
8
|
-
|
|
9
|
-
// App
|
|
10
|
-
import type App from '../../../app';
|
|
11
|
-
|
|
12
|
-
/*----------------------------------
|
|
13
|
-
- TYPES
|
|
14
|
-
----------------------------------*/
|
|
15
|
-
|
|
16
|
-
/*----------------------------------
|
|
17
|
-
- UTTILS
|
|
18
|
-
----------------------------------*/
|
|
19
|
-
export const fixNpmLinkIssues = ( app: App ) => {
|
|
20
|
-
|
|
21
|
-
const corePath = path.join(app.paths.root, '/node_modules/5htp-core');
|
|
22
|
-
if (!fs.lstatSync( corePath ).isSymbolicLink())
|
|
23
|
-
return console.info("Not fixing npm issue because 5htp-core wasn't installed with npm link.");
|
|
24
|
-
|
|
25
|
-
console.info(`Fix NPM link issues ...`);
|
|
26
|
-
|
|
27
|
-
const appModules = path.join(app.paths.root, 'node_modules');
|
|
28
|
-
const coreModules = path.join(corePath, 'node_modules');
|
|
29
|
-
|
|
30
|
-
// When the 5htp package is installed from npm link,
|
|
31
|
-
// Modules are installed locally and not glbally as with with the 5htp package from NPM.
|
|
32
|
-
// So we need to symbilnk the http-core node_modules in one of the parents of server.js.
|
|
33
|
-
// It avoids errors like: "Error: Cannot find module 'intl'"
|
|
34
|
-
fs.symlinkSync( coreModules, path.join(app.paths.bin, 'node_modules') );
|
|
35
|
-
|
|
36
|
-
// Same problem: when 5htp-core is installed via npm link,
|
|
37
|
-
// Typescript doesn't detect React and shows mission JSX errors
|
|
38
|
-
const preactCoreModule = path.join(coreModules, 'preact');
|
|
39
|
-
const preactAppModule = path.join(appModules, 'preact');
|
|
40
|
-
const reactAppModule = path.join(appModules, 'react');
|
|
41
|
-
|
|
42
|
-
if (!fs.existsSync( preactAppModule ))
|
|
43
|
-
fs.symlinkSync( preactCoreModule, preactAppModule );
|
|
44
|
-
if (!fs.existsSync( reactAppModule ))
|
|
45
|
-
fs.symlinkSync( path.join(preactCoreModule, 'compat'), reactAppModule );
|
|
46
|
-
}
|