ether-code 0.2.7 → 0.2.9
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/cli/compiler.js +6 -6
- package/cli/ether.js +233 -868
- package/package.json +1 -1
package/cli/compiler.js
CHANGED
|
@@ -107,7 +107,7 @@ class EtherCompiler {
|
|
|
107
107
|
return mappings[target] || target
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
compileFile(filePath) {
|
|
111
111
|
const content = fs.readFileSync(filePath, 'utf-8')
|
|
112
112
|
const fileName = path.basename(filePath, '.eth')
|
|
113
113
|
|
|
@@ -116,11 +116,11 @@ class EtherCompiler {
|
|
|
116
116
|
const code = this.generate(ast, target)
|
|
117
117
|
|
|
118
118
|
const extension = this.getExtension(target)
|
|
119
|
-
const outputPath =
|
|
119
|
+
const outputPath = fileName + extension
|
|
120
120
|
|
|
121
121
|
return {
|
|
122
122
|
source: filePath,
|
|
123
|
-
target,
|
|
123
|
+
target: target,
|
|
124
124
|
outputs: [{
|
|
125
125
|
path: outputPath,
|
|
126
126
|
content: code
|
|
@@ -227,17 +227,17 @@ class EtherCompiler {
|
|
|
227
227
|
return TARGET_EXTENSIONS[target] || TARGET_EXTENSIONS[normalizedTarget] || '.js'
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
check(filePath) {
|
|
231
231
|
const content = fs.readFileSync(filePath, 'utf-8')
|
|
232
232
|
const target = this.detectTarget(content, filePath)
|
|
233
233
|
|
|
234
234
|
try {
|
|
235
235
|
this.parse(content, target)
|
|
236
236
|
} catch (err) {
|
|
237
|
-
throw new Error(
|
|
237
|
+
throw new Error('Erreur de syntaxe: ' + err.message)
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
return { valid: true, target }
|
|
240
|
+
return { valid: true, target: target }
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
getTargets() {
|
package/cli/ether.js
CHANGED
|
@@ -6,7 +6,7 @@ const http = require('http')
|
|
|
6
6
|
const { EtherCompiler } = require('./compiler')
|
|
7
7
|
const { Watcher } = require('./watcher')
|
|
8
8
|
|
|
9
|
-
const VERSION = '0.2.
|
|
9
|
+
const VERSION = '0.2.9'
|
|
10
10
|
|
|
11
11
|
const COLORS = {
|
|
12
12
|
reset: '\x1b[0m',
|
|
@@ -20,163 +20,131 @@ const COLORS = {
|
|
|
20
20
|
cyan: '\x1b[36m'
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const MIME_TYPES = {
|
|
24
|
+
'.html': 'text/html',
|
|
25
|
+
'.css': 'text/css',
|
|
26
|
+
'.js': 'application/javascript',
|
|
27
|
+
'.json': 'application/json',
|
|
28
|
+
'.png': 'image/png',
|
|
29
|
+
'.jpg': 'image/jpeg',
|
|
30
|
+
'.jpeg': 'image/jpeg',
|
|
31
|
+
'.gif': 'image/gif',
|
|
32
|
+
'.svg': 'image/svg+xml',
|
|
33
|
+
'.ico': 'image/x-icon',
|
|
34
|
+
'.woff': 'font/woff',
|
|
35
|
+
'.woff2': 'font/woff2',
|
|
36
|
+
'.ttf': 'font/ttf',
|
|
37
|
+
'.eot': 'application/vnd.ms-fontobject'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function log(msg, color) {
|
|
41
|
+
console.log((color || '') + msg + COLORS.reset)
|
|
25
42
|
}
|
|
26
43
|
|
|
27
44
|
function logSuccess(msg) {
|
|
28
|
-
log(
|
|
45
|
+
console.log(COLORS.green + '✓ ' + msg + COLORS.reset)
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
function logError(msg) {
|
|
32
|
-
log(
|
|
49
|
+
console.log(COLORS.red + '✗ ' + msg + COLORS.reset)
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
function logInfo(msg) {
|
|
36
|
-
log(
|
|
53
|
+
console.log(COLORS.cyan + 'ℹ ' + msg + COLORS.reset)
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
function logWarning(msg) {
|
|
40
|
-
log(
|
|
57
|
+
console.log(COLORS.yellow + '⚠ ' + msg + COLORS.reset)
|
|
41
58
|
}
|
|
42
59
|
|
|
43
60
|
function showBanner() {
|
|
44
|
-
console.log(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
${COLORS.dim}Le langage intentionnel - v${VERSION}${COLORS.reset}
|
|
54
|
-
`)
|
|
61
|
+
console.log(COLORS.cyan + COLORS.bright)
|
|
62
|
+
console.log(' ███████╗████████╗██╗ ██╗███████╗██████╗ ')
|
|
63
|
+
console.log(' ██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗')
|
|
64
|
+
console.log(' █████╗ ██║ ███████║█████╗ ██████╔╝')
|
|
65
|
+
console.log(' ██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗')
|
|
66
|
+
console.log(' ███████╗ ██║ ██║ ██║███████╗██║ ██║')
|
|
67
|
+
console.log(' ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝')
|
|
68
|
+
console.log(COLORS.reset)
|
|
69
|
+
console.log(' ' + COLORS.dim + 'Le langage intentionnel - v' + VERSION + COLORS.reset)
|
|
55
70
|
}
|
|
56
71
|
|
|
57
72
|
function showHelp() {
|
|
58
73
|
showBanner()
|
|
59
|
-
console.log(
|
|
60
|
-
|
|
61
|
-
ether <commande> [options]
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
${COLORS.bright}EXEMPLES${COLORS.reset}
|
|
82
|
-
${COLORS.dim}# Initialiser un projet${COLORS.reset}
|
|
83
|
-
ether init
|
|
84
|
-
|
|
85
|
-
${COLORS.dim}# Compiler le projet${COLORS.reset}
|
|
86
|
-
ether build
|
|
87
|
-
|
|
88
|
-
${COLORS.dim}# Mode développement avec serveur${COLORS.reset}
|
|
89
|
-
ether dev
|
|
90
|
-
|
|
91
|
-
${COLORS.dim}# Mode développement sur port 8080${COLORS.reset}
|
|
92
|
-
ether dev -p 8080
|
|
93
|
-
|
|
94
|
-
${COLORS.bright}DOCUMENTATION${COLORS.reset}
|
|
95
|
-
https://ether-code.com/docs
|
|
96
|
-
`)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function showVersion() {
|
|
100
|
-
console.log(`Ether v${VERSION}`)
|
|
74
|
+
console.log('')
|
|
75
|
+
console.log(COLORS.bright + 'UTILISATION' + COLORS.reset)
|
|
76
|
+
console.log(' ether <commande> [options]')
|
|
77
|
+
console.log('')
|
|
78
|
+
console.log(COLORS.bright + 'COMMANDES' + COLORS.reset)
|
|
79
|
+
console.log(' ' + COLORS.cyan + 'init' + COLORS.reset + ' Initialiser un nouveau projet Ether')
|
|
80
|
+
console.log(' ' + COLORS.cyan + 'build' + COLORS.reset + ' Compiler les fichiers .eth')
|
|
81
|
+
console.log(' ' + COLORS.cyan + 'dev' + COLORS.reset + ' Mode développement avec serveur')
|
|
82
|
+
console.log(' ' + COLORS.cyan + 'help' + COLORS.reset + ' Afficher cette aide')
|
|
83
|
+
console.log(' ' + COLORS.cyan + 'version' + COLORS.reset + ' Afficher la version')
|
|
84
|
+
console.log('')
|
|
85
|
+
console.log(COLORS.bright + 'OPTIONS' + COLORS.reset)
|
|
86
|
+
console.log(' -o, --output Dossier de sortie')
|
|
87
|
+
console.log(' -p, --port Port du serveur (défaut: 3000)')
|
|
88
|
+
console.log(' -v, --verbose Mode verbeux')
|
|
89
|
+
console.log('')
|
|
90
|
+
console.log(COLORS.bright + 'EXEMPLES' + COLORS.reset)
|
|
91
|
+
console.log(' ether init')
|
|
92
|
+
console.log(' ether build')
|
|
93
|
+
console.log(' ether dev')
|
|
94
|
+
console.log(' ether dev -p 8080')
|
|
101
95
|
}
|
|
102
96
|
|
|
103
97
|
function loadConfig(configPath) {
|
|
104
98
|
const defaultConfig = {
|
|
105
|
-
src: '
|
|
106
|
-
out: '
|
|
107
|
-
targets: {},
|
|
108
|
-
i18n: 'fr',
|
|
99
|
+
src: 'src',
|
|
100
|
+
out: 'dist',
|
|
109
101
|
port: 3000,
|
|
110
|
-
|
|
111
|
-
ignored: ['node_modules', '.git', 'dist']
|
|
112
|
-
}
|
|
102
|
+
lang: 'fr'
|
|
113
103
|
}
|
|
114
|
-
|
|
115
|
-
const configFile = configPath || path.join(process.cwd(), 'ether.config.js')
|
|
116
104
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const userConfig = require(configFile)
|
|
120
|
-
return { ...defaultConfig, ...userConfig }
|
|
121
|
-
} catch (err) {
|
|
122
|
-
logError(`Erreur de configuration: ${err.message}`)
|
|
123
|
-
return defaultConfig
|
|
124
|
-
}
|
|
125
|
-
}
|
|
105
|
+
const configFile = configPath || 'ether.config.js'
|
|
106
|
+
const fullPath = path.resolve(process.cwd(), configFile)
|
|
126
107
|
|
|
127
|
-
|
|
128
|
-
if (fs.existsSync(jsonConfig)) {
|
|
108
|
+
if (fs.existsSync(fullPath)) {
|
|
129
109
|
try {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
} catch (err) {
|
|
134
|
-
logError(`Erreur de configuration: ${err.message}`)
|
|
110
|
+
const userConfig = require(fullPath)
|
|
111
|
+
return Object.assign({}, defaultConfig, userConfig)
|
|
112
|
+
} catch (e) {
|
|
135
113
|
return defaultConfig
|
|
136
114
|
}
|
|
137
115
|
}
|
|
138
|
-
|
|
116
|
+
|
|
139
117
|
return defaultConfig
|
|
140
118
|
}
|
|
141
119
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
'.eot': 'application/vnd.ms-fontobject'
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const LIVE_RELOAD_SCRIPT = `
|
|
160
|
-
<script>
|
|
161
|
-
(function() {
|
|
162
|
-
var source = new EventSource('/__ether_live_reload');
|
|
163
|
-
source.onmessage = function(e) {
|
|
164
|
-
if (e.data === 'reload') {
|
|
165
|
-
window.location.reload();
|
|
120
|
+
function findEthFiles(dir) {
|
|
121
|
+
const files = []
|
|
122
|
+
|
|
123
|
+
function scan(directory) {
|
|
124
|
+
const items = fs.readdirSync(directory)
|
|
125
|
+
for (let i = 0; i < items.length; i++) {
|
|
126
|
+
const item = items[i]
|
|
127
|
+
const fullPath = path.join(directory, item)
|
|
128
|
+
const stat = fs.statSync(fullPath)
|
|
129
|
+
if (stat.isDirectory()) {
|
|
130
|
+
scan(fullPath)
|
|
131
|
+
} else if (item.endsWith('.eth')) {
|
|
132
|
+
files.push(fullPath)
|
|
133
|
+
}
|
|
166
134
|
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
</script>
|
|
173
|
-
`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
scan(dir)
|
|
138
|
+
return files
|
|
139
|
+
}
|
|
174
140
|
|
|
175
|
-
function
|
|
141
|
+
function startServer(outDir, port) {
|
|
176
142
|
const clients = []
|
|
177
143
|
|
|
178
|
-
const
|
|
179
|
-
|
|
144
|
+
const liveReloadScript = '<script>(function(){var es=new EventSource("/__ether_reload");es.onmessage=function(e){if(e.data==="reload")location.reload()};})();</script>'
|
|
145
|
+
|
|
146
|
+
const server = http.createServer(function(req, res) {
|
|
147
|
+
if (req.url === '/__ether_reload') {
|
|
180
148
|
res.writeHead(200, {
|
|
181
149
|
'Content-Type': 'text/event-stream',
|
|
182
150
|
'Cache-Control': 'no-cache',
|
|
@@ -185,21 +153,15 @@ function createDevServer(outDir, port) {
|
|
|
185
153
|
})
|
|
186
154
|
res.write('data: connected\n\n')
|
|
187
155
|
clients.push(res)
|
|
188
|
-
req.on('close', ()
|
|
189
|
-
const
|
|
190
|
-
if (
|
|
156
|
+
req.on('close', function() {
|
|
157
|
+
const idx = clients.indexOf(res)
|
|
158
|
+
if (idx !== -1) clients.splice(idx, 1)
|
|
191
159
|
})
|
|
192
160
|
return
|
|
193
161
|
}
|
|
194
162
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (!filePath.includes('.') && !filePath.endsWith('/')) {
|
|
198
|
-
const htmlPath = filePath + '.html'
|
|
199
|
-
if (fs.existsSync(htmlPath)) {
|
|
200
|
-
filePath = htmlPath
|
|
201
|
-
}
|
|
202
|
-
}
|
|
163
|
+
const urlPath = req.url.split('?')[0]
|
|
164
|
+
let filePath = path.join(outDir, urlPath === '/' ? 'index.html' : urlPath)
|
|
203
165
|
|
|
204
166
|
if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
|
|
205
167
|
filePath = path.join(filePath, 'index.html')
|
|
@@ -207,553 +169,107 @@ function createDevServer(outDir, port) {
|
|
|
207
169
|
|
|
208
170
|
if (!fs.existsSync(filePath)) {
|
|
209
171
|
res.writeHead(404, { 'Content-Type': 'text/html' })
|
|
210
|
-
res.end(
|
|
211
|
-
<!DOCTYPE html>
|
|
212
|
-
<html>
|
|
213
|
-
<head><title>404 - Non trouvé</title></head>
|
|
214
|
-
<body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
215
|
-
<h1>404</h1>
|
|
216
|
-
<p>Fichier non trouvé: ${req.url}</p>
|
|
217
|
-
<p style="color: #666;">Serveur Ether Dev</p>
|
|
218
|
-
</body>
|
|
219
|
-
</html>
|
|
220
|
-
`)
|
|
172
|
+
res.end('<h1>404 - Non trouve</h1><p>' + req.url + '</p>')
|
|
221
173
|
return
|
|
222
174
|
}
|
|
223
175
|
|
|
224
176
|
const ext = path.extname(filePath).toLowerCase()
|
|
225
|
-
const
|
|
177
|
+
const mime = MIME_TYPES[ext] || 'application/octet-stream'
|
|
226
178
|
|
|
227
|
-
fs.readFile(filePath, (err, content)
|
|
179
|
+
fs.readFile(filePath, function(err, content) {
|
|
228
180
|
if (err) {
|
|
229
181
|
res.writeHead(500)
|
|
230
|
-
res.end(
|
|
182
|
+
res.end('Erreur: ' + err.message)
|
|
231
183
|
return
|
|
232
184
|
}
|
|
233
185
|
|
|
234
186
|
if (ext === '.html') {
|
|
235
187
|
let html = content.toString()
|
|
236
|
-
if (html.
|
|
237
|
-
html = html.replace('</body>',
|
|
238
|
-
} else if (html.includes('</html>')) {
|
|
239
|
-
html = html.replace('</html>', `${LIVE_RELOAD_SCRIPT}</html>`)
|
|
188
|
+
if (html.indexOf('</body>') !== -1) {
|
|
189
|
+
html = html.replace('</body>', liveReloadScript + '</body>')
|
|
240
190
|
} else {
|
|
241
|
-
html
|
|
191
|
+
html = html + liveReloadScript
|
|
242
192
|
}
|
|
243
193
|
content = html
|
|
244
194
|
}
|
|
245
195
|
|
|
246
|
-
res.writeHead(200, { 'Content-Type':
|
|
196
|
+
res.writeHead(200, { 'Content-Type': mime })
|
|
247
197
|
res.end(content)
|
|
248
198
|
})
|
|
249
199
|
})
|
|
250
200
|
|
|
251
|
-
server.
|
|
252
|
-
logSuccess(`Serveur démarré sur ${COLORS.cyan}http://localhost:${port}${COLORS.reset}`)
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
server.on('error', (err) => {
|
|
201
|
+
server.on('error', function(err) {
|
|
256
202
|
if (err.code === 'EADDRINUSE') {
|
|
257
|
-
logError(
|
|
203
|
+
logError('Port ' + port + ' deja utilise')
|
|
258
204
|
} else {
|
|
259
|
-
logError(
|
|
205
|
+
logError('Erreur serveur: ' + err.message)
|
|
260
206
|
}
|
|
261
207
|
process.exit(1)
|
|
262
208
|
})
|
|
263
209
|
|
|
210
|
+
server.listen(port, function() {
|
|
211
|
+
logSuccess('Serveur demarre sur http://localhost:' + port)
|
|
212
|
+
})
|
|
213
|
+
|
|
264
214
|
return {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
})
|
|
270
|
-
},
|
|
271
|
-
close: () => {
|
|
272
|
-
clients.forEach(client => client.end())
|
|
273
|
-
server.close()
|
|
215
|
+
reload: function() {
|
|
216
|
+
for (let i = 0; i < clients.length; i++) {
|
|
217
|
+
clients[i].write('data: reload\n\n')
|
|
218
|
+
}
|
|
274
219
|
}
|
|
275
220
|
}
|
|
276
221
|
}
|
|
277
222
|
|
|
278
|
-
|
|
223
|
+
function cmdInit() {
|
|
279
224
|
showBanner()
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const cwd = process.cwd()
|
|
283
|
-
|
|
284
|
-
const srcDir = path.join(cwd, 'src')
|
|
285
|
-
if (!fs.existsSync(srcDir)) {
|
|
286
|
-
fs.mkdirSync(srcDir, { recursive: true })
|
|
287
|
-
logSuccess('Dossier src/ créé')
|
|
288
|
-
}
|
|
225
|
+
console.log('')
|
|
289
226
|
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const publicDir = path.join(cwd, 'public')
|
|
297
|
-
if (!fs.existsSync(publicDir)) {
|
|
298
|
-
fs.mkdirSync(publicDir, { recursive: true })
|
|
299
|
-
logSuccess('Dossier public/ créé')
|
|
300
|
-
}
|
|
301
|
-
|
|
227
|
+
const projectDir = process.cwd()
|
|
228
|
+
const srcDir = path.join(projectDir, 'src')
|
|
229
|
+
const distDir = path.join(projectDir, 'dist')
|
|
230
|
+
const publicDir = path.join(projectDir, 'public')
|
|
302
231
|
const imagesDir = path.join(publicDir, 'images')
|
|
303
|
-
if (!fs.existsSync(imagesDir)) {
|
|
304
|
-
fs.mkdirSync(imagesDir, { recursive: true })
|
|
305
|
-
logSuccess('Dossier public/images/ créé')
|
|
306
|
-
}
|
|
307
|
-
|
|
308
232
|
const videosDir = path.join(publicDir, 'videos')
|
|
309
|
-
if (!fs.existsSync(videosDir)) {
|
|
310
|
-
fs.mkdirSync(videosDir, { recursive: true })
|
|
311
|
-
logSuccess('Dossier public/videos/ créé')
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const projectName = path.basename(cwd)
|
|
315
|
-
const packageJsonPath = path.join(cwd, 'package.json')
|
|
316
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
317
|
-
const packageJson = {
|
|
318
|
-
name: projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
|
|
319
|
-
version: '1.0.0',
|
|
320
|
-
description: 'Projet Ether',
|
|
321
|
-
main: 'dist/index.html',
|
|
322
|
-
scripts: {
|
|
323
|
-
dev: 'ether dev',
|
|
324
|
-
build: 'ether build'
|
|
325
|
-
},
|
|
326
|
-
keywords: ['ether'],
|
|
327
|
-
author: '',
|
|
328
|
-
license: 'MIT'
|
|
329
|
-
}
|
|
330
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
331
|
-
logSuccess('Fichier package.json créé')
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const configContent = `module.exports = {
|
|
335
|
-
src: './src',
|
|
336
|
-
out: './dist',
|
|
337
|
-
|
|
338
|
-
i18n: 'fr',
|
|
339
|
-
port: 3000,
|
|
340
233
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
html: {
|
|
347
|
-
extension: '.html',
|
|
348
|
-
minify: false
|
|
349
|
-
},
|
|
350
|
-
js: {
|
|
351
|
-
extension: '.js',
|
|
352
|
-
minify: false
|
|
353
|
-
}
|
|
354
|
-
},
|
|
234
|
+
if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir, { recursive: true })
|
|
235
|
+
if (!fs.existsSync(distDir)) fs.mkdirSync(distDir, { recursive: true })
|
|
236
|
+
if (!fs.existsSync(publicDir)) fs.mkdirSync(publicDir, { recursive: true })
|
|
237
|
+
if (!fs.existsSync(imagesDir)) fs.mkdirSync(imagesDir, { recursive: true })
|
|
238
|
+
if (!fs.existsSync(videosDir)) fs.mkdirSync(videosDir, { recursive: true })
|
|
355
239
|
|
|
356
|
-
|
|
357
|
-
ignored: ['node_modules', '.git', 'dist']
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
`
|
|
361
|
-
|
|
362
|
-
const configPath = path.join(cwd, 'ether.config.js')
|
|
363
|
-
if (!fs.existsSync(configPath)) {
|
|
364
|
-
fs.writeFileSync(configPath, configContent)
|
|
365
|
-
logSuccess('Fichier ether.config.js créé')
|
|
366
|
-
} else {
|
|
367
|
-
logWarning('ether.config.js existe déjà')
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const exampleHtml = `// cible: html
|
|
371
|
-
|
|
372
|
-
document
|
|
373
|
-
tete
|
|
374
|
-
meta charset: "UTF-8"
|
|
375
|
-
meta name: "viewport", content: "width=device-width, initial-scale=1.0"
|
|
376
|
-
titre "Ether - Le langage intentionnel"
|
|
377
|
-
lien rel: "stylesheet", href: "styles.css"
|
|
240
|
+
const configContent = 'module.exports = {\n src: "src",\n out: "dist",\n port: 3000,\n lang: "fr"\n}\n'
|
|
378
241
|
|
|
379
|
-
corps
|
|
380
|
-
entete classe: "hero"
|
|
381
|
-
nav classe: "navbar"
|
|
382
|
-
div classe: "logo"
|
|
383
|
-
span classe: "logo-icon"
|
|
384
|
-
"◈"
|
|
385
|
-
span "Ether"
|
|
386
|
-
liste-non-ordonnee classe: "nav-links"
|
|
387
|
-
element-liste
|
|
388
|
-
lien href: "#features"
|
|
389
|
-
"Fonctionnalités"
|
|
390
|
-
element-liste
|
|
391
|
-
lien href: "#examples"
|
|
392
|
-
"Exemples"
|
|
393
|
-
element-liste
|
|
394
|
-
lien href: "#docs"
|
|
395
|
-
"Documentation"
|
|
396
|
-
|
|
397
|
-
div classe: "hero-content"
|
|
398
|
-
titre1 classe: "hero-title"
|
|
399
|
-
"Écrivez du code"
|
|
400
|
-
saut-ligne
|
|
401
|
-
span classe: "gradient-text"
|
|
402
|
-
"comme vous pensez"
|
|
403
|
-
paragraphe classe: "hero-subtitle"
|
|
404
|
-
"Ether est un langage intentionnel qui compile vers HTML, CSS, JavaScript et plus encore. Naturel, intuitif, puissant."
|
|
405
|
-
div classe: "hero-buttons"
|
|
406
|
-
lien href: "#start", classe: "btn btn-primary"
|
|
407
|
-
"Commencer"
|
|
408
|
-
lien href: "#learn", classe: "btn btn-secondary"
|
|
409
|
-
"En savoir plus"
|
|
410
|
-
|
|
411
|
-
principal
|
|
412
|
-
section id: "features", classe: "features"
|
|
413
|
-
titre2 classe: "section-title"
|
|
414
|
-
"Pourquoi Ether ?"
|
|
415
|
-
div classe: "features-grid"
|
|
416
|
-
article classe: "feature-card"
|
|
417
|
-
div classe: "feature-icon"
|
|
418
|
-
"🎯"
|
|
419
|
-
titre3 "Intuitif"
|
|
420
|
-
paragraphe "Écrivez du code en langage naturel. Plus besoin de mémoriser des syntaxes complexes."
|
|
421
|
-
article classe: "feature-card"
|
|
422
|
-
div classe: "feature-icon"
|
|
423
|
-
"⚡"
|
|
424
|
-
titre3 "Rapide"
|
|
425
|
-
paragraphe "Compilation instantanée avec rechargement automatique en mode développement."
|
|
426
|
-
article classe: "feature-card"
|
|
427
|
-
div classe: "feature-icon"
|
|
428
|
-
"🌍"
|
|
429
|
-
titre3 "Multilingue"
|
|
430
|
-
paragraphe "Codez en français, anglais, espagnol et plus. Votre langue, votre code."
|
|
431
|
-
article classe: "feature-card"
|
|
432
|
-
div classe: "feature-icon"
|
|
433
|
-
"🔧"
|
|
434
|
-
titre3 "Flexible"
|
|
435
|
-
paragraphe "Compile vers HTML, CSS, JS, PHP, Python, SQL et bien d'autres langages."
|
|
436
|
-
|
|
437
|
-
section id: "examples", classe: "examples"
|
|
438
|
-
titre2 classe: "section-title"
|
|
439
|
-
"Simple et élégant"
|
|
440
|
-
div classe: "code-comparison"
|
|
441
|
-
div classe: "code-block"
|
|
442
|
-
div classe: "code-header"
|
|
443
|
-
"Ether"
|
|
444
|
-
pre
|
|
445
|
-
code
|
|
446
|
-
"document\\n corps\\n titre1 \\"Bonjour\\"\\n paragraphe \\"Le monde\\""
|
|
447
|
-
div classe: "code-arrow"
|
|
448
|
-
"→"
|
|
449
|
-
div classe: "code-block"
|
|
450
|
-
div classe: "code-header"
|
|
451
|
-
"HTML"
|
|
452
|
-
pre
|
|
453
|
-
code
|
|
454
|
-
"<!DOCTYPE html>\\n<html>\\n <body>\\n <h1>Bonjour</h1>\\n <p>Le monde</p>\\n </body>\\n</html>"
|
|
455
|
-
|
|
456
|
-
pied classe: "footer"
|
|
457
|
-
paragraphe
|
|
458
|
-
"Créé avec"
|
|
459
|
-
span classe: "heart"
|
|
460
|
-
" ♥ "
|
|
461
|
-
"par la communauté Ether"
|
|
462
|
-
paragraphe classe: "copyright"
|
|
463
|
-
"© 2025 Ether. MIT License."
|
|
464
|
-
|
|
465
|
-
script src: "app.js"
|
|
466
|
-
`
|
|
467
|
-
|
|
468
|
-
const exampleCss = `// cible: css
|
|
469
|
-
|
|
470
|
-
racine
|
|
471
|
-
couleur-primaire: "#6366f1"
|
|
472
|
-
couleur-secondaire: "#8b5cf6"
|
|
473
|
-
couleur-accent: "#06b6d4"
|
|
474
|
-
couleur-fond: "#0f0f23"
|
|
475
|
-
couleur-surface: "#1a1a2e"
|
|
476
|
-
couleur-texte: "#e2e8f0"
|
|
477
|
-
couleur-texte-pale: "#94a3b8"
|
|
478
|
-
|
|
479
|
-
*
|
|
480
|
-
marge: 0
|
|
481
|
-
remplissage: 0
|
|
482
|
-
modele-boite: border-box
|
|
483
|
-
|
|
484
|
-
corps
|
|
485
|
-
famille-police: "system-ui", "-apple-system", "sans-serif"
|
|
486
|
-
couleur-fond: var(--couleur-fond)
|
|
487
|
-
couleur: var(--couleur-texte)
|
|
488
|
-
hauteur-ligne: 1.6
|
|
489
|
-
|
|
490
|
-
.hero
|
|
491
|
-
min-hauteur: 100vh
|
|
492
|
-
fond: "linear-gradient(135deg, var(--couleur-fond) 0%, var(--couleur-surface) 100%)"
|
|
493
|
-
position: relative
|
|
494
|
-
debordement: cache
|
|
495
|
-
|
|
496
|
-
.navbar
|
|
497
|
-
affichage: flex
|
|
498
|
-
justifier-contenu: space-between
|
|
499
|
-
aligner-elements: center
|
|
500
|
-
remplissage: "1.5rem 5%"
|
|
501
|
-
position: fixed
|
|
502
|
-
largeur: 100%
|
|
503
|
-
haut: 0
|
|
504
|
-
z-index: 100
|
|
505
|
-
fond: "rgba(15, 15, 35, 0.9)"
|
|
506
|
-
flou-fond: "10px"
|
|
507
|
-
|
|
508
|
-
.logo
|
|
509
|
-
affichage: flex
|
|
510
|
-
aligner-elements: center
|
|
511
|
-
espace: "0.5rem"
|
|
512
|
-
taille-police: "1.5rem"
|
|
513
|
-
poids-police: 700
|
|
514
|
-
|
|
515
|
-
.logo-icon
|
|
516
|
-
taille-police: "2rem"
|
|
517
|
-
couleur: var(--couleur-primaire)
|
|
518
|
-
|
|
519
|
-
.nav-links
|
|
520
|
-
affichage: flex
|
|
521
|
-
liste-style: none
|
|
522
|
-
espace: "2rem"
|
|
523
|
-
|
|
524
|
-
.nav-links lien
|
|
525
|
-
couleur: var(--couleur-texte-pale)
|
|
526
|
-
decoration-texte: none
|
|
527
|
-
transition: "couleur 0.3s"
|
|
528
|
-
au survol
|
|
529
|
-
couleur: var(--couleur-primaire)
|
|
530
|
-
|
|
531
|
-
.hero-content
|
|
532
|
-
texte-aligne: center
|
|
533
|
-
remplissage: "12rem 5% 5rem"
|
|
534
|
-
max-largeur: "800px"
|
|
535
|
-
marge: "0 auto"
|
|
536
|
-
|
|
537
|
-
.hero-title
|
|
538
|
-
taille-police: "3.5rem"
|
|
539
|
-
poids-police: 800
|
|
540
|
-
marge-bas: "1.5rem"
|
|
541
|
-
hauteur-ligne: 1.2
|
|
542
|
-
|
|
543
|
-
.gradient-text
|
|
544
|
-
fond: "linear-gradient(90deg, var(--couleur-primaire), var(--couleur-accent))"
|
|
545
|
-
decoupe-fond: text
|
|
546
|
-
couleur: transparent
|
|
547
|
-
|
|
548
|
-
.hero-subtitle
|
|
549
|
-
taille-police: "1.25rem"
|
|
550
|
-
couleur: var(--couleur-texte-pale)
|
|
551
|
-
marge-bas: "2.5rem"
|
|
552
|
-
max-largeur: "600px"
|
|
553
|
-
marge-gauche: auto
|
|
554
|
-
marge-droite: auto
|
|
555
|
-
|
|
556
|
-
.hero-buttons
|
|
557
|
-
affichage: flex
|
|
558
|
-
espace: "1rem"
|
|
559
|
-
justifier-contenu: center
|
|
560
|
-
|
|
561
|
-
.btn
|
|
562
|
-
remplissage: "0.875rem 2rem"
|
|
563
|
-
rayon-bordure: "0.5rem"
|
|
564
|
-
taille-police: "1rem"
|
|
565
|
-
poids-police: 600
|
|
566
|
-
decoration-texte: none
|
|
567
|
-
transition: "transform 0.2s, box-shadow 0.2s"
|
|
568
|
-
au survol
|
|
569
|
-
transformation: "translateY(-2px)"
|
|
570
|
-
|
|
571
|
-
.btn-primary
|
|
572
|
-
fond: "linear-gradient(90deg, var(--couleur-primaire), var(--couleur-secondaire))"
|
|
573
|
-
couleur: white
|
|
574
|
-
au survol
|
|
575
|
-
ombre-boite: "0 10px 30px rgba(99, 102, 241, 0.4)"
|
|
576
|
-
|
|
577
|
-
.btn-secondary
|
|
578
|
-
fond: transparent
|
|
579
|
-
couleur: var(--couleur-texte)
|
|
580
|
-
bordure: "2px solid var(--couleur-primaire)"
|
|
581
|
-
au survol
|
|
582
|
-
fond: "rgba(99, 102, 241, 0.1)"
|
|
583
|
-
|
|
584
|
-
.features
|
|
585
|
-
remplissage: "6rem 5%"
|
|
586
|
-
|
|
587
|
-
.section-title
|
|
588
|
-
texte-aligne: center
|
|
589
|
-
taille-police: "2.5rem"
|
|
590
|
-
marge-bas: "3rem"
|
|
591
|
-
|
|
592
|
-
.features-grid
|
|
593
|
-
affichage: grid
|
|
594
|
-
colonnes-grille: "repeat(auto-fit, minmax(250px, 1fr))"
|
|
595
|
-
espace: "2rem"
|
|
596
|
-
max-largeur: "1200px"
|
|
597
|
-
marge: "0 auto"
|
|
598
|
-
|
|
599
|
-
.feature-card
|
|
600
|
-
fond: var(--couleur-surface)
|
|
601
|
-
remplissage: "2rem"
|
|
602
|
-
rayon-bordure: "1rem"
|
|
603
|
-
texte-aligne: center
|
|
604
|
-
transition: "transform 0.3s"
|
|
605
|
-
au survol
|
|
606
|
-
transformation: "translateY(-5px)"
|
|
242
|
+
const indexContent = '// cible: html\n\ndocument\n tete\n meta charset: "UTF-8"\n meta name: "viewport", content: "width=device-width, initial-scale=1.0"\n titre "Mon projet Ether"\n lien rel: "stylesheet", href: "styles.css"\n corps\n entete classe: "header"\n titre1 "Bienvenue"\n principal classe: "main"\n paragraphe "Mon premier projet Ether!"\n pied classe: "footer"\n paragraphe "Cree avec Ether"\n'
|
|
607
243
|
|
|
608
|
-
.
|
|
609
|
-
taille-police: "3rem"
|
|
610
|
-
marge-bas: "1rem"
|
|
244
|
+
const stylesContent = '// cible: css\n\n.header\n fond: bleu\n couleur: blanc\n padding: 2rem\n texte aligne: centre\n\n.main\n padding: 2rem\n\n.footer\n fond: gris fonce\n couleur: blanc\n padding: 1rem\n texte aligne: centre\n'
|
|
611
245
|
|
|
612
|
-
.
|
|
613
|
-
marge-bas: "0.75rem"
|
|
614
|
-
taille-police: "1.25rem"
|
|
246
|
+
const appContent = '// cible: js\n\nconsole.log("Ether ready!")\n'
|
|
615
247
|
|
|
616
|
-
|
|
617
|
-
couleur: var(--couleur-texte-pale)
|
|
248
|
+
const packageContent = '{\n "name": "mon-projet-ether",\n "version": "1.0.0",\n "scripts": {\n "dev": "ether dev",\n "build": "ether build"\n }\n}\n'
|
|
618
249
|
|
|
619
|
-
.
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
.
|
|
624
|
-
affichage: flex
|
|
625
|
-
aligner-elements: center
|
|
626
|
-
justifier-contenu: center
|
|
627
|
-
espace: "2rem"
|
|
628
|
-
flex-wrap: wrap
|
|
629
|
-
max-largeur: "1000px"
|
|
630
|
-
marge: "0 auto"
|
|
631
|
-
|
|
632
|
-
.code-block
|
|
633
|
-
fond: var(--couleur-fond)
|
|
634
|
-
rayon-bordure: "0.75rem"
|
|
635
|
-
debordement: cache
|
|
636
|
-
min-largeur: "300px"
|
|
637
|
-
|
|
638
|
-
.code-header
|
|
639
|
-
fond: "rgba(99, 102, 241, 0.2)"
|
|
640
|
-
remplissage: "0.75rem 1rem"
|
|
641
|
-
poids-police: 600
|
|
642
|
-
couleur: var(--couleur-primaire)
|
|
643
|
-
|
|
644
|
-
.code-block pre
|
|
645
|
-
remplissage: "1.5rem"
|
|
646
|
-
marge: 0
|
|
647
|
-
|
|
648
|
-
.code-block code
|
|
649
|
-
famille-police: "Fira Code", "Monaco", monospace
|
|
650
|
-
taille-police: "0.9rem"
|
|
651
|
-
blanc: pre
|
|
652
|
-
|
|
653
|
-
.code-arrow
|
|
654
|
-
taille-police: "2rem"
|
|
655
|
-
couleur: var(--couleur-primaire)
|
|
656
|
-
|
|
657
|
-
.footer
|
|
658
|
-
texte-aligne: center
|
|
659
|
-
remplissage: "3rem 5%"
|
|
660
|
-
fond: var(--couleur-fond)
|
|
661
|
-
|
|
662
|
-
.heart
|
|
663
|
-
couleur: "#ef4444"
|
|
664
|
-
|
|
665
|
-
.copyright
|
|
666
|
-
marge-haut: "0.5rem"
|
|
667
|
-
couleur: var(--couleur-texte-pale)
|
|
668
|
-
taille-police: "0.875rem"
|
|
669
|
-
|
|
670
|
-
@media (max-largeur: 768px)
|
|
671
|
-
.hero-title
|
|
672
|
-
taille-police: "2.5rem"
|
|
673
|
-
.nav-links
|
|
674
|
-
affichage: none
|
|
675
|
-
.code-arrow
|
|
676
|
-
transformation: "rotate(90deg)"
|
|
677
|
-
`
|
|
678
|
-
|
|
679
|
-
const exampleJs = `// cible: js
|
|
680
|
-
|
|
681
|
-
constante annee = nouveau Date().getFullYear()
|
|
682
|
-
|
|
683
|
-
fonction initialiser()
|
|
684
|
-
constante copyright = document.querySelector(".copyright")
|
|
685
|
-
si copyright
|
|
686
|
-
copyright.textContent = "© " + annee + " Ether. MIT License."
|
|
687
|
-
|
|
688
|
-
constante liens = document.querySelectorAll("a[href^='#']")
|
|
689
|
-
pour chaque lien dans liens
|
|
690
|
-
lien.addEventListener "click", fonction(e)
|
|
691
|
-
e.preventDefault()
|
|
692
|
-
constante cible = document.querySelector(this.getAttribute("href"))
|
|
693
|
-
si cible
|
|
694
|
-
cible.scrollIntoView({ behavior: "smooth" })
|
|
695
|
-
|
|
696
|
-
document.addEventListener "DOMContentLoaded", initialiser
|
|
697
|
-
`
|
|
698
|
-
|
|
699
|
-
const examplePath = path.join(srcDir, 'index.eth')
|
|
700
|
-
if (!fs.existsSync(examplePath)) {
|
|
701
|
-
fs.writeFileSync(examplePath, exampleHtml)
|
|
702
|
-
logSuccess('Fichier src/index.eth créé')
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
const cssPath = path.join(srcDir, 'styles.eth')
|
|
706
|
-
if (!fs.existsSync(cssPath)) {
|
|
707
|
-
fs.writeFileSync(cssPath, exampleCss)
|
|
708
|
-
logSuccess('Fichier src/styles.eth créé')
|
|
709
|
-
}
|
|
250
|
+
fs.writeFileSync(path.join(projectDir, 'ether.config.js'), configContent)
|
|
251
|
+
fs.writeFileSync(path.join(srcDir, 'index.eth'), indexContent)
|
|
252
|
+
fs.writeFileSync(path.join(srcDir, 'styles.eth'), stylesContent)
|
|
253
|
+
fs.writeFileSync(path.join(srcDir, 'app.eth'), appContent)
|
|
254
|
+
fs.writeFileSync(path.join(projectDir, 'package.json'), packageContent)
|
|
710
255
|
|
|
711
|
-
|
|
712
|
-
if (!fs.existsSync(jsPath)) {
|
|
713
|
-
fs.writeFileSync(jsPath, exampleJs)
|
|
714
|
-
logSuccess('Fichier src/app.eth créé')
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
const logoSvg = `<?xml version="1.0" encoding="UTF-8"?>
|
|
718
|
-
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 499 500">
|
|
719
|
-
<defs>
|
|
720
|
-
<linearGradient id="g1" gradientUnits="userSpaceOnUse" x1="1.106" y1="250.0527" x2="498.8623" y2="250.0527">
|
|
721
|
-
<stop offset="0" style="stop-color:#03AFC6"/><stop offset="0.5126" style="stop-color:#31BAD3"/><stop offset="1" style="stop-color:#3EC4DD"/>
|
|
722
|
-
</linearGradient>
|
|
723
|
-
<linearGradient id="g2" gradientUnits="userSpaceOnUse" x1="56.332" y1="250.0532" x2="470.3037" y2="250.0532">
|
|
724
|
-
<stop offset="0" style="stop-color:#4758A7"/><stop offset="0.2597" style="stop-color:#6F53A2"/><stop offset="0.5939" style="stop-color:#924A9D"/><stop offset="0.8518" style="stop-color:#A64399"/><stop offset="1" style="stop-color:#AE4097"/>
|
|
725
|
-
</linearGradient>
|
|
726
|
-
<linearGradient id="g3" gradientUnits="userSpaceOnUse" x1="144.1313" y1="289.1055" x2="448.2786" y2="147.2793">
|
|
727
|
-
<stop offset="0" style="stop-color:#5E6AB2"/><stop offset="0.1138" style="stop-color:#5A77B7"/><stop offset="0.4161" style="stop-color:#4D96C8"/><stop offset="0.6753" style="stop-color:#3DADD5"/><stop offset="0.8782" style="stop-color:#30BBDD"/><stop offset="1" style="stop-color:#24C1E1"/>
|
|
728
|
-
</linearGradient>
|
|
729
|
-
<linearGradient id="g4" gradientUnits="userSpaceOnUse" x1="223.2749" y1="258.8877" x2="387.1369" y2="182.4776">
|
|
730
|
-
<stop offset="0" style="stop-color:#5E6AB2"/><stop offset="0.1138" style="stop-color:#5A77B7"/><stop offset="0.4161" style="stop-color:#4D96C8"/><stop offset="0.6753" style="stop-color:#3DADD5"/><stop offset="0.8782" style="stop-color:#30BBDD"/><stop offset="1" style="stop-color:#24C1E1"/>
|
|
731
|
-
</linearGradient>
|
|
732
|
-
</defs>
|
|
733
|
-
<path fill="url(#g1)" d="M5.381,238.563c-5.468-13.48-5.838-18.365-0.256-29.006c5.582-10.641,129.113-178.821,157.852-196.679C191.716-4.979,414.415,0.938,431.034,1.795c16.621,0.856,39.463,3.869,45.858,10.234c6.395,6.365,10.242,8.502,12.175,17.908c1.932,9.406,7.304,45.665,8.664,91.185c1.362,45.521,1.822,152.92-0.505,186.578c-2.325,33.658-1.465,47.184-14.553,67.173c-13.089,19.987-218.044,111.611-232.689,117.413c-14.646,5.801-35.404,16.623-62.205-6.569C160.979,462.526,5.381,238.563,5.381,238.563z"/>
|
|
734
|
-
<path fill="url(#g2)" d="M291.136,436.653c-7.71,3.354-52.39,24.228-61.917,23.915c-10.871-0.359-16.045-4.679-36.578-31.196C157.484,383.969,67.434,258.436,60.702,243.983c-5.766-12.377-6.472-19.474,1.826-32.931c8.299-13.456,105.229-151.605,117.666-160.906c12.648-9.458,23.041-10.032,35.5-10.188c55.329-0.694,152.766-0.725,225.992,1.368c16.294,0.466,24.063,11.799,24.653,21.583c5.707,94.576,6.6,150.435-6.481,266.374c-3.107,27.537-16.15,39.634-36.553,49.895C402.604,389.586,301.741,432.036,291.136,436.653z"/>
|
|
735
|
-
<path fill="url(#g3)" d="M397.598,278.148c2.596,0.083,3.073,1.179,3.474,1.965c0.642,1.265,0.51,3.642-0.264,5.969c-0.545,1.638-10.225,33.388-13.646,43.11c-1.364,3.871-2.896,4.9-5.702,6.357c-2.692,1.396-132.598,52.559-143.222,56.099c-6.013,2.006-6.541,0.742-9.292-1.695c-2.749-2.437-107.08-151.266-109.972-155.301c-2.893-4.034-1.419-6.227-0.711-7.854c1.636-3.759,78.848-110.176,84.417-116.574c5.57-6.398,8.097-8.37,12.46-11.03c2.771-1.689,5.406-3.374,11.53-3.739c12.276-0.731,183.793-0.426,192.787,0.333c4.049,0.342,7.233,1.441,6.384,6.319c-0.853,4.879-9.874,46.584-8.671,43.199c1.204-3.385-1.01,5.33-8.432,5.348c-7.422,0.02-153.731,0-157.729,0.039c-6.107,0.06-6.991,0.443-7.952,1.426c-2.176,2.226-54.269,71.788-57.427,75.836c-3.157,4.048-2.247,5.316,1.448,9.065c3.695,3.748,69.606,62.824,69.606,62.824s-10.604-21.547-8.459-21.547"/>
|
|
736
|
-
<path fill="url(#g4)" d="M213.282,235.909c14.12-20.019,28.129-36.342,31.945-40.798c5.362-6.26,5.762-5.197,8.629-5.197c2.869,0,132.714,0.003,132.714,0.003s2.916-0.469,4.863,1.864c1.029,1.235-0.298,5.654-0.298,5.654l-9.552,40.332c0,0-1.318,5.72-6.366,5.649C334.696,242.847,208.748,250.903,213.282,235.909"/>
|
|
737
|
-
</svg>`
|
|
738
|
-
|
|
739
|
-
const logoPath = path.join(imagesDir, 'Logo_Ether.svg')
|
|
740
|
-
if (!fs.existsSync(logoPath)) {
|
|
741
|
-
fs.writeFileSync(logoPath, logoSvg)
|
|
742
|
-
logSuccess('Fichier public/images/Logo_Ether.svg créé')
|
|
743
|
-
}
|
|
744
|
-
|
|
256
|
+
logSuccess('Projet initialise!')
|
|
745
257
|
console.log('')
|
|
746
|
-
|
|
747
|
-
console.log('')
|
|
748
|
-
|
|
749
|
-
console.log(
|
|
750
|
-
console.log(
|
|
258
|
+
logInfo('Structure creee:')
|
|
259
|
+
console.log(' src/index.eth')
|
|
260
|
+
console.log(' src/styles.eth')
|
|
261
|
+
console.log(' src/app.eth')
|
|
262
|
+
console.log(' public/images/')
|
|
263
|
+
console.log(' public/videos/')
|
|
264
|
+
console.log(' ether.config.js')
|
|
265
|
+
console.log(' package.json')
|
|
751
266
|
console.log('')
|
|
267
|
+
logInfo('Commandes:')
|
|
268
|
+
console.log(' ether build Compiler')
|
|
269
|
+
console.log(' ether dev Serveur de developpement')
|
|
752
270
|
}
|
|
753
271
|
|
|
754
|
-
|
|
755
|
-
const startTime = Date.now()
|
|
756
|
-
|
|
272
|
+
function cmdBuild(options) {
|
|
757
273
|
if (!options.quiet) {
|
|
758
274
|
showBanner()
|
|
759
275
|
logInfo('Compilation en cours...')
|
|
@@ -765,7 +281,7 @@ async function cmdBuild(options) {
|
|
|
765
281
|
const outDir = path.resolve(process.cwd(), options.output || config.out)
|
|
766
282
|
|
|
767
283
|
if (!fs.existsSync(srcDir)) {
|
|
768
|
-
logError(
|
|
284
|
+
logError('Dossier source introuvable: ' + srcDir)
|
|
769
285
|
process.exit(1)
|
|
770
286
|
}
|
|
771
287
|
|
|
@@ -774,61 +290,58 @@ async function cmdBuild(options) {
|
|
|
774
290
|
}
|
|
775
291
|
|
|
776
292
|
const compiler = new EtherCompiler(config)
|
|
777
|
-
|
|
778
293
|
const files = findEthFiles(srcDir)
|
|
779
294
|
|
|
780
295
|
if (files.length === 0) {
|
|
781
|
-
logWarning('Aucun fichier .eth
|
|
296
|
+
logWarning('Aucun fichier .eth trouve')
|
|
782
297
|
return
|
|
783
298
|
}
|
|
784
299
|
|
|
785
300
|
let successCount = 0
|
|
786
301
|
let errorCount = 0
|
|
787
302
|
|
|
788
|
-
for (
|
|
303
|
+
for (let i = 0; i < files.length; i++) {
|
|
304
|
+
const file = files[i]
|
|
789
305
|
try {
|
|
790
306
|
const relativePath = path.relative(srcDir, file)
|
|
791
|
-
const result =
|
|
307
|
+
const result = compiler.compileFile(file)
|
|
792
308
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
309
|
+
if (result && result.outputs) {
|
|
310
|
+
for (let j = 0; j < result.outputs.length; j++) {
|
|
311
|
+
const output = result.outputs[j]
|
|
312
|
+
const outPath = path.join(outDir, output.path)
|
|
313
|
+
const outDirPath = path.dirname(outPath)
|
|
314
|
+
|
|
315
|
+
if (!fs.existsSync(outDirPath)) {
|
|
316
|
+
fs.mkdirSync(outDirPath, { recursive: true })
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
fs.writeFileSync(outPath, output.content)
|
|
320
|
+
|
|
321
|
+
if (options.verbose) {
|
|
322
|
+
logSuccess(relativePath + ' -> ' + output.path)
|
|
323
|
+
}
|
|
805
324
|
}
|
|
806
325
|
}
|
|
807
326
|
|
|
808
327
|
successCount++
|
|
809
328
|
} catch (err) {
|
|
810
329
|
errorCount++
|
|
811
|
-
logError(
|
|
812
|
-
|
|
813
|
-
if (options.verbose) {
|
|
814
|
-
console.error(err.stack)
|
|
815
|
-
}
|
|
330
|
+
logError(path.relative(srcDir, file) + ': ' + err.message)
|
|
816
331
|
}
|
|
817
332
|
}
|
|
818
333
|
|
|
819
|
-
const duration = Date.now() - startTime
|
|
820
|
-
|
|
821
334
|
if (!options.quiet) {
|
|
822
335
|
console.log('')
|
|
823
336
|
if (errorCount === 0) {
|
|
824
|
-
logSuccess(
|
|
337
|
+
logSuccess(successCount + ' fichier(s) compile(s)')
|
|
825
338
|
} else {
|
|
826
|
-
logWarning(
|
|
339
|
+
logWarning(successCount + ' succes, ' + errorCount + ' erreur(s)')
|
|
827
340
|
}
|
|
828
341
|
}
|
|
829
342
|
}
|
|
830
343
|
|
|
831
|
-
|
|
344
|
+
function cmdDev(options) {
|
|
832
345
|
showBanner()
|
|
833
346
|
|
|
834
347
|
const config = loadConfig(options.config)
|
|
@@ -837,7 +350,7 @@ async function cmdDev(options) {
|
|
|
837
350
|
const port = options.port || config.port || 3000
|
|
838
351
|
|
|
839
352
|
if (!fs.existsSync(srcDir)) {
|
|
840
|
-
logError(
|
|
353
|
+
logError('Dossier source introuvable: ' + srcDir)
|
|
841
354
|
process.exit(1)
|
|
842
355
|
}
|
|
843
356
|
|
|
@@ -845,260 +358,112 @@ async function cmdDev(options) {
|
|
|
845
358
|
fs.mkdirSync(outDir, { recursive: true })
|
|
846
359
|
}
|
|
847
360
|
|
|
848
|
-
logInfo(
|
|
849
|
-
logInfo(
|
|
361
|
+
logInfo('Surveillance de ' + srcDir)
|
|
362
|
+
logInfo('Sortie vers ' + outDir)
|
|
850
363
|
console.log('')
|
|
851
364
|
|
|
852
|
-
|
|
853
|
-
if (!options.noServer) {
|
|
854
|
-
devServer = createDevServer(outDir, port)
|
|
855
|
-
}
|
|
365
|
+
const devServer = startServer(outDir, port)
|
|
856
366
|
|
|
857
|
-
console.log('')
|
|
858
367
|
logInfo('Compilation initiale...')
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
await cmdBuild({ ...options, quiet: true })
|
|
862
|
-
logSuccess('Compilation terminée')
|
|
863
|
-
} catch (err) {
|
|
864
|
-
logWarning(`Erreur de compilation: ${err.message}`)
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
console.log('')
|
|
868
|
-
logInfo('En attente de modifications... (Ctrl+C pour arrêter)')
|
|
368
|
+
cmdBuild(Object.assign({}, options, { quiet: true }))
|
|
369
|
+
logSuccess('Compilation terminee')
|
|
869
370
|
console.log('')
|
|
371
|
+
logInfo('En attente de modifications... (Ctrl+C pour arreter)')
|
|
870
372
|
|
|
871
|
-
const watcher = new Watcher(srcDir, config.watch)
|
|
872
373
|
const compiler = new EtherCompiler(config)
|
|
374
|
+
const watcher = new Watcher(srcDir, config.watch)
|
|
873
375
|
|
|
874
|
-
watcher.on('change',
|
|
875
|
-
if (!filePath.endsWith('.eth')) return
|
|
876
|
-
|
|
877
|
-
const relativePath = path.relative(srcDir, filePath)
|
|
878
|
-
logInfo(`Modification: ${relativePath}`)
|
|
879
|
-
|
|
880
|
-
try {
|
|
881
|
-
const result = await compiler.compileFile(filePath)
|
|
882
|
-
|
|
883
|
-
for (const output of result.outputs) {
|
|
884
|
-
const outPath = path.join(outDir, output.path)
|
|
885
|
-
const outDirPath = path.dirname(outPath)
|
|
886
|
-
|
|
887
|
-
if (!fs.existsSync(outDirPath)) {
|
|
888
|
-
fs.mkdirSync(outDirPath, { recursive: true })
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
fs.writeFileSync(outPath, output.content)
|
|
892
|
-
logSuccess(`→ ${output.path}`)
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
if (devServer) {
|
|
896
|
-
devServer.reload()
|
|
897
|
-
}
|
|
898
|
-
} catch (err) {
|
|
899
|
-
logError(err.message)
|
|
900
|
-
}
|
|
901
|
-
})
|
|
902
|
-
|
|
903
|
-
watcher.on('add', async (filePath) => {
|
|
376
|
+
watcher.on('change', function(filePath) {
|
|
904
377
|
if (!filePath.endsWith('.eth')) return
|
|
905
378
|
|
|
906
379
|
const relativePath = path.relative(srcDir, filePath)
|
|
907
|
-
logInfo(
|
|
380
|
+
logInfo('Modification: ' + relativePath)
|
|
908
381
|
|
|
909
382
|
try {
|
|
910
|
-
const result =
|
|
383
|
+
const result = compiler.compileFile(filePath)
|
|
911
384
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
385
|
+
if (result && result.outputs) {
|
|
386
|
+
for (let i = 0; i < result.outputs.length; i++) {
|
|
387
|
+
const output = result.outputs[i]
|
|
388
|
+
const outPath = path.join(outDir, output.path)
|
|
389
|
+
const outDirPath = path.dirname(outPath)
|
|
390
|
+
|
|
391
|
+
if (!fs.existsSync(outDirPath)) {
|
|
392
|
+
fs.mkdirSync(outDirPath, { recursive: true })
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
fs.writeFileSync(outPath, output.content)
|
|
396
|
+
logSuccess('-> ' + output.path)
|
|
918
397
|
}
|
|
919
|
-
|
|
920
|
-
fs.writeFileSync(outPath, output.content)
|
|
921
|
-
logSuccess(`→ ${output.path}`)
|
|
922
398
|
}
|
|
923
399
|
|
|
924
|
-
|
|
925
|
-
devServer.reload()
|
|
926
|
-
}
|
|
400
|
+
devServer.reload()
|
|
927
401
|
} catch (err) {
|
|
928
402
|
logError(err.message)
|
|
929
403
|
}
|
|
930
404
|
})
|
|
931
405
|
|
|
932
|
-
watcher.on('unlink', (filePath) => {
|
|
933
|
-
if (!filePath.endsWith('.eth')) return
|
|
934
|
-
logWarning(`Fichier supprimé: ${path.relative(srcDir, filePath)}`)
|
|
935
|
-
})
|
|
936
|
-
|
|
937
406
|
watcher.start()
|
|
938
|
-
|
|
939
|
-
process.on('SIGINT', () => {
|
|
940
|
-
console.log('')
|
|
941
|
-
logInfo('Arrêt du mode développement')
|
|
942
|
-
watcher.stop()
|
|
943
|
-
if (devServer) {
|
|
944
|
-
devServer.close()
|
|
945
|
-
}
|
|
946
|
-
process.exit(0)
|
|
947
|
-
})
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
async function cmdCheck(options) {
|
|
951
|
-
showBanner()
|
|
952
|
-
logInfo('Vérification de la syntaxe...')
|
|
953
|
-
console.log('')
|
|
954
|
-
|
|
955
|
-
const config = loadConfig(options.config)
|
|
956
|
-
const srcDir = path.resolve(process.cwd(), config.src)
|
|
957
|
-
|
|
958
|
-
if (!fs.existsSync(srcDir)) {
|
|
959
|
-
logError(`Dossier source introuvable: ${srcDir}`)
|
|
960
|
-
process.exit(1)
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
const compiler = new EtherCompiler(config)
|
|
964
|
-
const files = findEthFiles(srcDir)
|
|
965
|
-
|
|
966
|
-
if (files.length === 0) {
|
|
967
|
-
logWarning('Aucun fichier .eth trouvé')
|
|
968
|
-
return
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
let validCount = 0
|
|
972
|
-
let errorCount = 0
|
|
973
|
-
|
|
974
|
-
for (const file of files) {
|
|
975
|
-
const relativePath = path.relative(srcDir, file)
|
|
976
|
-
|
|
977
|
-
try {
|
|
978
|
-
await compiler.check(file)
|
|
979
|
-
logSuccess(relativePath)
|
|
980
|
-
validCount++
|
|
981
|
-
} catch (err) {
|
|
982
|
-
logError(`${relativePath}: ${err.message}`)
|
|
983
|
-
errorCount++
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
console.log('')
|
|
988
|
-
if (errorCount === 0) {
|
|
989
|
-
logSuccess(`${validCount} fichier(s) valide(s)`)
|
|
990
|
-
} else {
|
|
991
|
-
logError(`${errorCount} erreur(s) sur ${files.length} fichier(s)`)
|
|
992
|
-
process.exit(1)
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
function findEthFiles(dir) {
|
|
997
|
-
const files = []
|
|
998
|
-
|
|
999
|
-
function scan(currentDir) {
|
|
1000
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true })
|
|
1001
|
-
|
|
1002
|
-
for (const entry of entries) {
|
|
1003
|
-
const fullPath = path.join(currentDir, entry.name)
|
|
1004
|
-
|
|
1005
|
-
if (entry.isDirectory()) {
|
|
1006
|
-
if (!['node_modules', '.git', 'dist'].includes(entry.name)) {
|
|
1007
|
-
scan(fullPath)
|
|
1008
|
-
}
|
|
1009
|
-
} else if (entry.name.endsWith('.eth')) {
|
|
1010
|
-
files.push(fullPath)
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
scan(dir)
|
|
1016
|
-
return files
|
|
1017
407
|
}
|
|
1018
408
|
|
|
1019
409
|
function parseArgs(args) {
|
|
1020
|
-
const options = {
|
|
1021
|
-
|
|
1022
|
-
config: null,
|
|
1023
|
-
output: null,
|
|
1024
|
-
port: null,
|
|
1025
|
-
verbose: false,
|
|
1026
|
-
quiet: false,
|
|
1027
|
-
watch: false,
|
|
1028
|
-
noServer: false
|
|
1029
|
-
}
|
|
410
|
+
const options = {}
|
|
411
|
+
let command = null
|
|
1030
412
|
|
|
1031
|
-
let i = 0
|
|
1032
|
-
while (i < args.length) {
|
|
413
|
+
for (let i = 0; i < args.length; i++) {
|
|
1033
414
|
const arg = args[i]
|
|
1034
415
|
|
|
1035
|
-
if (arg === '-
|
|
1036
|
-
options.
|
|
416
|
+
if (arg === '-p' || arg === '--port') {
|
|
417
|
+
options.port = parseInt(args[++i], 10)
|
|
1037
418
|
} else if (arg === '-o' || arg === '--output') {
|
|
1038
419
|
options.output = args[++i]
|
|
1039
|
-
} else if (arg === '-
|
|
1040
|
-
options.
|
|
420
|
+
} else if (arg === '-c' || arg === '--config') {
|
|
421
|
+
options.config = args[++i]
|
|
1041
422
|
} else if (arg === '-v' || arg === '--verbose') {
|
|
1042
423
|
options.verbose = true
|
|
1043
424
|
} else if (arg === '-q' || arg === '--quiet') {
|
|
1044
425
|
options.quiet = true
|
|
1045
|
-
} else if (arg
|
|
1046
|
-
|
|
1047
|
-
} else if (arg === '--no-color') {
|
|
1048
|
-
for (const key in COLORS) {
|
|
1049
|
-
COLORS[key] = ''
|
|
1050
|
-
}
|
|
1051
|
-
} else if (arg === '--no-server') {
|
|
1052
|
-
options.noServer = true
|
|
1053
|
-
} else if (!arg.startsWith('-')) {
|
|
1054
|
-
if (!options.command) {
|
|
1055
|
-
options.command = arg
|
|
1056
|
-
}
|
|
426
|
+
} else if (!arg.startsWith('-') && !command) {
|
|
427
|
+
command = arg
|
|
1057
428
|
}
|
|
1058
|
-
|
|
1059
|
-
i++
|
|
1060
429
|
}
|
|
1061
430
|
|
|
1062
|
-
return options
|
|
431
|
+
return { command: command, options: options }
|
|
1063
432
|
}
|
|
1064
433
|
|
|
1065
|
-
|
|
434
|
+
function main() {
|
|
1066
435
|
const args = process.argv.slice(2)
|
|
1067
|
-
const
|
|
436
|
+
const parsed = parseArgs(args)
|
|
437
|
+
const command = parsed.command
|
|
438
|
+
const options = parsed.options
|
|
439
|
+
|
|
440
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
441
|
+
showHelp()
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (command === 'version' || command === '--version' || command === '-V') {
|
|
446
|
+
console.log('Ether v' + VERSION)
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (command === 'init') {
|
|
451
|
+
cmdInit()
|
|
452
|
+
return
|
|
453
|
+
}
|
|
1068
454
|
|
|
1069
|
-
if (
|
|
1070
|
-
options
|
|
455
|
+
if (command === 'build') {
|
|
456
|
+
cmdBuild(options)
|
|
457
|
+
return
|
|
1071
458
|
}
|
|
1072
459
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
break
|
|
1077
|
-
case 'build':
|
|
1078
|
-
await cmdBuild(options)
|
|
1079
|
-
break
|
|
1080
|
-
case 'dev':
|
|
1081
|
-
case 'watch':
|
|
1082
|
-
await cmdDev(options)
|
|
1083
|
-
break
|
|
1084
|
-
case 'check':
|
|
1085
|
-
await cmdCheck(options)
|
|
1086
|
-
break
|
|
1087
|
-
case 'version':
|
|
1088
|
-
case '-V':
|
|
1089
|
-
case '--version':
|
|
1090
|
-
showVersion()
|
|
1091
|
-
break
|
|
1092
|
-
case 'help':
|
|
1093
|
-
case '-h':
|
|
1094
|
-
case '--help':
|
|
1095
|
-
default:
|
|
1096
|
-
showHelp()
|
|
1097
|
-
break
|
|
460
|
+
if (command === 'dev' || command === 'watch') {
|
|
461
|
+
cmdDev(options)
|
|
462
|
+
return
|
|
1098
463
|
}
|
|
464
|
+
|
|
465
|
+
logError('Commande inconnue: ' + command)
|
|
466
|
+
console.log('Tapez "ether help" pour voir les commandes disponibles')
|
|
1099
467
|
}
|
|
1100
468
|
|
|
1101
|
-
main()
|
|
1102
|
-
logError(err.message)
|
|
1103
|
-
process.exit(1)
|
|
1104
|
-
})
|
|
469
|
+
main()
|