ether-code 0.1.8 → 0.1.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/ether-compiler.js +190 -0
- package/ether-parser.js +3059 -0
- package/package.json +3 -2
- package/cli/ether.js +0 -700
- package/cli/watcher.js +0 -106
- package/i18n/i18n-css.json +0 -743
- package/i18n/i18n-graphql.json +0 -1531
- package/i18n/i18n-html.json +0 -572
- package/i18n/i18n-js.json +0 -2790
- package/i18n/i18n-node.json +0 -2442
- package/i18n/i18n-php.json +0 -4306
- package/i18n/i18n-python.json +0 -3080
- package/i18n/i18n-react.json +0 -1784
- package/i18n/i18n-ruby.json +0 -1858
- package/i18n/i18n-sql.json +0 -3466
- package/i18n/i18n-ts.json +0 -442
- package/lexer/ether-lexer.js +0 -869
- package/lexer/tokens.js +0 -292
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ether-code",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Ether - Le langage intentionnel",
|
|
5
5
|
"main": "cli/compiler.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,8 +37,9 @@
|
|
|
37
37
|
"cli/",
|
|
38
38
|
"generators/",
|
|
39
39
|
"lexer/",
|
|
40
|
-
"parsers/",
|
|
41
40
|
"i18n/",
|
|
41
|
+
"ether-parser.js",
|
|
42
|
+
"ether-compiler.js",
|
|
42
43
|
"README.md",
|
|
43
44
|
"LICENSE"
|
|
44
45
|
]
|
package/cli/ether.js
DELETED
|
@@ -1,700 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
const http = require('http')
|
|
6
|
-
const { EtherCompiler } = require('./compiler')
|
|
7
|
-
const { Watcher } = require('./watcher')
|
|
8
|
-
|
|
9
|
-
const VERSION = '0.1.8'
|
|
10
|
-
|
|
11
|
-
const COLORS = {
|
|
12
|
-
reset: '\x1b[0m',
|
|
13
|
-
bright: '\x1b[1m',
|
|
14
|
-
dim: '\x1b[2m',
|
|
15
|
-
red: '\x1b[31m',
|
|
16
|
-
green: '\x1b[32m',
|
|
17
|
-
yellow: '\x1b[33m',
|
|
18
|
-
blue: '\x1b[34m',
|
|
19
|
-
magenta: '\x1b[35m',
|
|
20
|
-
cyan: '\x1b[36m'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function log(msg, color = '') {
|
|
24
|
-
console.log(`${color}${msg}${COLORS.reset}`)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function logSuccess(msg) {
|
|
28
|
-
log(`✓ ${msg}`, COLORS.green)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function logError(msg) {
|
|
32
|
-
log(`✗ ${msg}`, COLORS.red)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function logInfo(msg) {
|
|
36
|
-
log(`ℹ ${msg}`, COLORS.cyan)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function logWarning(msg) {
|
|
40
|
-
log(`⚠ ${msg}`, COLORS.yellow)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function showBanner() {
|
|
44
|
-
console.log(`
|
|
45
|
-
${COLORS.cyan}${COLORS.bright}
|
|
46
|
-
███████╗████████╗██╗ ██╗███████╗██████╗
|
|
47
|
-
██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗
|
|
48
|
-
█████╗ ██║ ███████║█████╗ ██████╔╝
|
|
49
|
-
██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗
|
|
50
|
-
███████╗ ██║ ██║ ██║███████╗██║ ██║
|
|
51
|
-
╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
52
|
-
${COLORS.reset}
|
|
53
|
-
${COLORS.dim}Le langage intentionnel - v${VERSION}${COLORS.reset}
|
|
54
|
-
`)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function showHelp() {
|
|
58
|
-
showBanner()
|
|
59
|
-
console.log(`
|
|
60
|
-
${COLORS.bright}UTILISATION${COLORS.reset}
|
|
61
|
-
ether <commande> [options]
|
|
62
|
-
|
|
63
|
-
${COLORS.bright}COMMANDES${COLORS.reset}
|
|
64
|
-
${COLORS.cyan}init${COLORS.reset} Initialiser un nouveau projet Ether
|
|
65
|
-
${COLORS.cyan}build${COLORS.reset} Compiler les fichiers .eth
|
|
66
|
-
${COLORS.cyan}dev${COLORS.reset} Mode développement (serveur + watch + live reload)
|
|
67
|
-
${COLORS.cyan}check${COLORS.reset} Vérifier la syntaxe sans compiler
|
|
68
|
-
${COLORS.cyan}help${COLORS.reset} Afficher cette aide
|
|
69
|
-
${COLORS.cyan}version${COLORS.reset} Afficher la version
|
|
70
|
-
|
|
71
|
-
${COLORS.bright}OPTIONS${COLORS.reset}
|
|
72
|
-
-c, --config Chemin vers le fichier de configuration
|
|
73
|
-
-o, --output Dossier de sortie
|
|
74
|
-
-p, --port Port du serveur de développement (défaut: 3000)
|
|
75
|
-
-w, --watch Surveiller les changements (alias de dev)
|
|
76
|
-
-v, --verbose Mode verbeux
|
|
77
|
-
-q, --quiet Mode silencieux
|
|
78
|
-
--no-color Désactiver les couleurs
|
|
79
|
-
|
|
80
|
-
${COLORS.bright}EXEMPLES${COLORS.reset}
|
|
81
|
-
${COLORS.dim}# Initialiser un projet${COLORS.reset}
|
|
82
|
-
ether init
|
|
83
|
-
|
|
84
|
-
${COLORS.dim}# Compiler le projet${COLORS.reset}
|
|
85
|
-
ether build
|
|
86
|
-
|
|
87
|
-
${COLORS.dim}# Mode développement sur localhost:3000${COLORS.reset}
|
|
88
|
-
ether dev
|
|
89
|
-
|
|
90
|
-
${COLORS.dim}# Mode développement sur un autre port${COLORS.reset}
|
|
91
|
-
ether dev -p 8080
|
|
92
|
-
|
|
93
|
-
${COLORS.bright}DOCUMENTATION${COLORS.reset}
|
|
94
|
-
https://ether-code.com/docs
|
|
95
|
-
`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function showVersion() {
|
|
99
|
-
console.log(`Ether v${VERSION}`)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function loadConfig(configPath) {
|
|
103
|
-
const defaultConfig = {
|
|
104
|
-
src: './src',
|
|
105
|
-
out: './dist',
|
|
106
|
-
targets: {},
|
|
107
|
-
i18n: 'fr',
|
|
108
|
-
watch: {
|
|
109
|
-
ignored: ['node_modules', '.git', 'dist']
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const configFile = configPath || path.join(process.cwd(), 'ether.config.js')
|
|
114
|
-
|
|
115
|
-
if (fs.existsSync(configFile)) {
|
|
116
|
-
try {
|
|
117
|
-
const userConfig = require(configFile)
|
|
118
|
-
return { ...defaultConfig, ...userConfig }
|
|
119
|
-
} catch (err) {
|
|
120
|
-
logError(`Erreur de configuration: ${err.message}`)
|
|
121
|
-
return defaultConfig
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const jsonConfig = path.join(process.cwd(), 'ether.config.json')
|
|
126
|
-
if (fs.existsSync(jsonConfig)) {
|
|
127
|
-
try {
|
|
128
|
-
const content = fs.readFileSync(jsonConfig, 'utf-8')
|
|
129
|
-
const userConfig = JSON.parse(content)
|
|
130
|
-
return { ...defaultConfig, ...userConfig }
|
|
131
|
-
} catch (err) {
|
|
132
|
-
logError(`Erreur de configuration: ${err.message}`)
|
|
133
|
-
return defaultConfig
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return defaultConfig
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async function cmdInit() {
|
|
141
|
-
showBanner()
|
|
142
|
-
logInfo('Initialisation du projet Ether...')
|
|
143
|
-
|
|
144
|
-
const cwd = process.cwd()
|
|
145
|
-
|
|
146
|
-
const srcDir = path.join(cwd, 'src')
|
|
147
|
-
if (!fs.existsSync(srcDir)) {
|
|
148
|
-
fs.mkdirSync(srcDir, { recursive: true })
|
|
149
|
-
logSuccess('Dossier src/ créé')
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const publicDir = path.join(cwd, 'public')
|
|
153
|
-
if (!fs.existsSync(publicDir)) {
|
|
154
|
-
fs.mkdirSync(publicDir, { recursive: true })
|
|
155
|
-
logSuccess('Dossier public/ créé')
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const imagesDir = path.join(publicDir, 'images')
|
|
159
|
-
if (!fs.existsSync(imagesDir)) {
|
|
160
|
-
fs.mkdirSync(imagesDir, { recursive: true })
|
|
161
|
-
logSuccess('Dossier public/images/ créé')
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const videosDir = path.join(publicDir, 'videos')
|
|
165
|
-
if (!fs.existsSync(videosDir)) {
|
|
166
|
-
fs.mkdirSync(videosDir, { recursive: true })
|
|
167
|
-
logSuccess('Dossier public/videos/ créé')
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const configContent = `module.exports = {
|
|
171
|
-
src: './src',
|
|
172
|
-
out: './dist',
|
|
173
|
-
|
|
174
|
-
i18n: 'fr',
|
|
175
|
-
|
|
176
|
-
targets: {
|
|
177
|
-
css: {
|
|
178
|
-
extension: '.css',
|
|
179
|
-
minify: false
|
|
180
|
-
},
|
|
181
|
-
html: {
|
|
182
|
-
extension: '.html',
|
|
183
|
-
minify: false
|
|
184
|
-
},
|
|
185
|
-
js: {
|
|
186
|
-
extension: '.js',
|
|
187
|
-
minify: false
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
watch: {
|
|
192
|
-
ignored: ['node_modules', '.git', 'dist']
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
`
|
|
196
|
-
|
|
197
|
-
const configPath = path.join(cwd, 'ether.config.js')
|
|
198
|
-
if (!fs.existsSync(configPath)) {
|
|
199
|
-
fs.writeFileSync(configPath, configContent)
|
|
200
|
-
logSuccess('Fichier ether.config.js créé')
|
|
201
|
-
} else {
|
|
202
|
-
logWarning('ether.config.js existe déjà')
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const projectName = path.basename(cwd)
|
|
206
|
-
const packageJson = {
|
|
207
|
-
name: projectName,
|
|
208
|
-
version: "1.0.0",
|
|
209
|
-
description: "Projet Ether",
|
|
210
|
-
scripts: {
|
|
211
|
-
dev: "ether dev",
|
|
212
|
-
build: "ether build",
|
|
213
|
-
check: "ether check"
|
|
214
|
-
},
|
|
215
|
-
keywords: ["ether"],
|
|
216
|
-
license: "MIT"
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const packagePath = path.join(cwd, 'package.json')
|
|
220
|
-
if (!fs.existsSync(packagePath)) {
|
|
221
|
-
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2))
|
|
222
|
-
logSuccess('Fichier package.json créé')
|
|
223
|
-
} else {
|
|
224
|
-
logWarning('package.json existe déjà')
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const exampleEth = `html
|
|
228
|
-
tête
|
|
229
|
-
titre "Ma première page Ether"
|
|
230
|
-
corps
|
|
231
|
-
entete
|
|
232
|
-
titre1 "Bienvenue sur Ether"
|
|
233
|
-
paragraphe "Le langage intentionnel"
|
|
234
|
-
principal
|
|
235
|
-
section #hero
|
|
236
|
-
titre2 "Commencez maintenant"
|
|
237
|
-
paragraphe "Programmez dans votre langue naturelle."
|
|
238
|
-
bouton .primary "Démarrer"
|
|
239
|
-
pied
|
|
240
|
-
paragraphe "© 2025 Créé avec Ether"
|
|
241
|
-
`
|
|
242
|
-
|
|
243
|
-
const examplePath = path.join(srcDir, 'index.eth')
|
|
244
|
-
if (!fs.existsSync(examplePath)) {
|
|
245
|
-
fs.writeFileSync(examplePath, exampleEth)
|
|
246
|
-
logSuccess('Fichier exemple src/index.eth créé')
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
console.log('')
|
|
250
|
-
logSuccess('Projet initialisé avec succès!')
|
|
251
|
-
console.log('')
|
|
252
|
-
logInfo('Prochaines étapes:')
|
|
253
|
-
console.log(` 1. Éditer ${COLORS.cyan}src/index.eth${COLORS.reset}`)
|
|
254
|
-
console.log(` 2. Lancer ${COLORS.cyan}ether dev${COLORS.reset} pour le mode développement`)
|
|
255
|
-
console.log(` 3. Ou ${COLORS.cyan}ether build${COLORS.reset} pour compiler`)
|
|
256
|
-
console.log('')
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
async function cmdBuild(options) {
|
|
260
|
-
const startTime = Date.now()
|
|
261
|
-
|
|
262
|
-
if (!options.quiet) {
|
|
263
|
-
showBanner()
|
|
264
|
-
logInfo('Compilation en cours...')
|
|
265
|
-
console.log('')
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const config = loadConfig(options.config)
|
|
269
|
-
const srcDir = path.resolve(process.cwd(), config.src)
|
|
270
|
-
const outDir = path.resolve(process.cwd(), options.output || config.out)
|
|
271
|
-
const publicDir = path.resolve(process.cwd(), config.public || 'public')
|
|
272
|
-
|
|
273
|
-
if (!fs.existsSync(srcDir)) {
|
|
274
|
-
logError(`Dossier source introuvable: ${srcDir}`)
|
|
275
|
-
process.exit(1)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (!fs.existsSync(outDir)) {
|
|
279
|
-
fs.mkdirSync(outDir, { recursive: true })
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (fs.existsSync(publicDir)) {
|
|
283
|
-
copyDir(publicDir, outDir)
|
|
284
|
-
if (!options.quiet) {
|
|
285
|
-
logSuccess('Dossier public/ copié vers dist/')
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const compiler = new EtherCompiler(config)
|
|
290
|
-
|
|
291
|
-
const files = findEthFiles(srcDir)
|
|
292
|
-
|
|
293
|
-
if (files.length === 0) {
|
|
294
|
-
logWarning('Aucun fichier .eth trouvé')
|
|
295
|
-
return
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
let successCount = 0
|
|
299
|
-
let errorCount = 0
|
|
300
|
-
|
|
301
|
-
for (const file of files) {
|
|
302
|
-
try {
|
|
303
|
-
const relativePath = path.relative(srcDir, file)
|
|
304
|
-
const result = await compiler.compileFile(file)
|
|
305
|
-
|
|
306
|
-
for (const output of result.outputs) {
|
|
307
|
-
const outPath = path.join(outDir, output.path)
|
|
308
|
-
const outDirPath = path.dirname(outPath)
|
|
309
|
-
|
|
310
|
-
if (!fs.existsSync(outDirPath)) {
|
|
311
|
-
fs.mkdirSync(outDirPath, { recursive: true })
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
fs.writeFileSync(outPath, output.content)
|
|
315
|
-
|
|
316
|
-
if (options.verbose) {
|
|
317
|
-
logSuccess(`${relativePath} → ${output.path}`)
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
successCount++
|
|
322
|
-
} catch (err) {
|
|
323
|
-
errorCount++
|
|
324
|
-
logError(`${path.relative(srcDir, file)}: ${err.message}`)
|
|
325
|
-
|
|
326
|
-
if (options.verbose) {
|
|
327
|
-
console.error(err.stack)
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const duration = Date.now() - startTime
|
|
333
|
-
|
|
334
|
-
console.log('')
|
|
335
|
-
if (errorCount === 0) {
|
|
336
|
-
logSuccess(`${successCount} fichier(s) compilé(s) en ${duration}ms`)
|
|
337
|
-
} else {
|
|
338
|
-
logWarning(`${successCount} succès, ${errorCount} erreur(s) en ${duration}ms`)
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
async function cmdDev(options) {
|
|
343
|
-
showBanner()
|
|
344
|
-
|
|
345
|
-
const config = loadConfig(options.config)
|
|
346
|
-
const srcDir = path.resolve(process.cwd(), config.src)
|
|
347
|
-
const outDir = path.resolve(process.cwd(), options.output || config.out)
|
|
348
|
-
const port = options.port || config.port || 3000
|
|
349
|
-
|
|
350
|
-
if (!fs.existsSync(srcDir)) {
|
|
351
|
-
logError(`Dossier source introuvable: ${srcDir}`)
|
|
352
|
-
process.exit(1)
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
logInfo(`Surveillance de ${srcDir}`)
|
|
356
|
-
logInfo(`Sortie vers ${outDir}`)
|
|
357
|
-
console.log('')
|
|
358
|
-
|
|
359
|
-
await cmdBuild({ ...options, quiet: true })
|
|
360
|
-
|
|
361
|
-
const clients = []
|
|
362
|
-
|
|
363
|
-
const MIME_TYPES = {
|
|
364
|
-
'.html': 'text/html',
|
|
365
|
-
'.css': 'text/css',
|
|
366
|
-
'.js': 'application/javascript',
|
|
367
|
-
'.json': 'application/json',
|
|
368
|
-
'.png': 'image/png',
|
|
369
|
-
'.jpg': 'image/jpeg',
|
|
370
|
-
'.jpeg': 'image/jpeg',
|
|
371
|
-
'.gif': 'image/gif',
|
|
372
|
-
'.svg': 'image/svg+xml',
|
|
373
|
-
'.ico': 'image/x-icon',
|
|
374
|
-
'.webp': 'image/webp',
|
|
375
|
-
'.mp4': 'video/mp4',
|
|
376
|
-
'.webm': 'video/webm',
|
|
377
|
-
'.woff': 'font/woff',
|
|
378
|
-
'.woff2': 'font/woff2',
|
|
379
|
-
'.ttf': 'font/ttf'
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const LIVE_RELOAD_SCRIPT = `
|
|
383
|
-
<script>
|
|
384
|
-
(function() {
|
|
385
|
-
const es = new EventSource('/__ether_reload');
|
|
386
|
-
es.onmessage = function(e) {
|
|
387
|
-
if (e.data === 'reload') {
|
|
388
|
-
window.location.reload();
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
es.onerror = function() {
|
|
392
|
-
es.close();
|
|
393
|
-
setTimeout(function() { window.location.reload(); }, 1000);
|
|
394
|
-
};
|
|
395
|
-
})();
|
|
396
|
-
</script>
|
|
397
|
-
</body>`
|
|
398
|
-
|
|
399
|
-
const server = http.createServer((req, res) => {
|
|
400
|
-
if (req.url === '/__ether_reload') {
|
|
401
|
-
res.writeHead(200, {
|
|
402
|
-
'Content-Type': 'text/event-stream',
|
|
403
|
-
'Cache-Control': 'no-cache',
|
|
404
|
-
'Connection': 'keep-alive',
|
|
405
|
-
'Access-Control-Allow-Origin': '*'
|
|
406
|
-
})
|
|
407
|
-
res.write('data: connected\n\n')
|
|
408
|
-
clients.push(res)
|
|
409
|
-
req.on('close', () => {
|
|
410
|
-
const index = clients.indexOf(res)
|
|
411
|
-
if (index > -1) clients.splice(index, 1)
|
|
412
|
-
})
|
|
413
|
-
return
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
let filePath = req.url === '/' ? '/index.html' : req.url
|
|
417
|
-
filePath = filePath.split('?')[0]
|
|
418
|
-
filePath = path.join(outDir, filePath)
|
|
419
|
-
|
|
420
|
-
const ext = path.extname(filePath).toLowerCase()
|
|
421
|
-
const contentType = MIME_TYPES[ext] || 'application/octet-stream'
|
|
422
|
-
|
|
423
|
-
fs.readFile(filePath, (err, content) => {
|
|
424
|
-
if (err) {
|
|
425
|
-
if (err.code === 'ENOENT') {
|
|
426
|
-
res.writeHead(404)
|
|
427
|
-
res.end('404 - Fichier non trouvé')
|
|
428
|
-
} else {
|
|
429
|
-
res.writeHead(500)
|
|
430
|
-
res.end('Erreur serveur')
|
|
431
|
-
}
|
|
432
|
-
return
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (ext === '.html') {
|
|
436
|
-
content = content.toString().replace('</body>', LIVE_RELOAD_SCRIPT)
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
res.writeHead(200, { 'Content-Type': contentType })
|
|
440
|
-
res.end(content)
|
|
441
|
-
})
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
server.listen(port, () => {
|
|
445
|
-
logSuccess(`Serveur démarré sur http://localhost:${port}`)
|
|
446
|
-
console.log('')
|
|
447
|
-
logInfo('En attente de modifications... (Ctrl+C pour arrêter)')
|
|
448
|
-
console.log('')
|
|
449
|
-
})
|
|
450
|
-
|
|
451
|
-
function notifyClients() {
|
|
452
|
-
clients.forEach(client => {
|
|
453
|
-
client.write('data: reload\n\n')
|
|
454
|
-
})
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const watcher = new Watcher(srcDir, config.watch)
|
|
458
|
-
const compiler = new EtherCompiler(config)
|
|
459
|
-
|
|
460
|
-
watcher.on('change', async (filePath) => {
|
|
461
|
-
if (!filePath.endsWith('.eth')) return
|
|
462
|
-
|
|
463
|
-
const relativePath = path.relative(srcDir, filePath)
|
|
464
|
-
logInfo(`Modification: ${relativePath}`)
|
|
465
|
-
|
|
466
|
-
try {
|
|
467
|
-
const result = await compiler.compileFile(filePath)
|
|
468
|
-
|
|
469
|
-
for (const output of result.outputs) {
|
|
470
|
-
const outPath = path.join(outDir, output.path)
|
|
471
|
-
const outDirPath = path.dirname(outPath)
|
|
472
|
-
|
|
473
|
-
if (!fs.existsSync(outDirPath)) {
|
|
474
|
-
fs.mkdirSync(outDirPath, { recursive: true })
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
fs.writeFileSync(outPath, output.content)
|
|
478
|
-
logSuccess(`→ ${output.path}`)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
notifyClients()
|
|
482
|
-
} catch (err) {
|
|
483
|
-
logError(err.message)
|
|
484
|
-
}
|
|
485
|
-
})
|
|
486
|
-
|
|
487
|
-
watcher.on('add', async (filePath) => {
|
|
488
|
-
if (!filePath.endsWith('.eth')) return
|
|
489
|
-
|
|
490
|
-
const relativePath = path.relative(srcDir, filePath)
|
|
491
|
-
logInfo(`Nouveau fichier: ${relativePath}`)
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
const result = await compiler.compileFile(filePath)
|
|
495
|
-
|
|
496
|
-
for (const output of result.outputs) {
|
|
497
|
-
const outPath = path.join(outDir, output.path)
|
|
498
|
-
const outDirPath = path.dirname(outPath)
|
|
499
|
-
|
|
500
|
-
if (!fs.existsSync(outDirPath)) {
|
|
501
|
-
fs.mkdirSync(outDirPath, { recursive: true })
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
fs.writeFileSync(outPath, output.content)
|
|
505
|
-
logSuccess(`→ ${output.path}`)
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
notifyClients()
|
|
509
|
-
} catch (err) {
|
|
510
|
-
logError(err.message)
|
|
511
|
-
}
|
|
512
|
-
})
|
|
513
|
-
|
|
514
|
-
watcher.on('unlink', (filePath) => {
|
|
515
|
-
if (!filePath.endsWith('.eth')) return
|
|
516
|
-
logWarning(`Fichier supprimé: ${path.relative(srcDir, filePath)}`)
|
|
517
|
-
})
|
|
518
|
-
|
|
519
|
-
watcher.start()
|
|
520
|
-
|
|
521
|
-
process.on('SIGINT', () => {
|
|
522
|
-
console.log('')
|
|
523
|
-
logInfo('Arrêt du serveur de développement')
|
|
524
|
-
server.close()
|
|
525
|
-
watcher.stop()
|
|
526
|
-
process.exit(0)
|
|
527
|
-
})
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
async function cmdCheck(options) {
|
|
531
|
-
showBanner()
|
|
532
|
-
logInfo('Vérification de la syntaxe...')
|
|
533
|
-
console.log('')
|
|
534
|
-
|
|
535
|
-
const config = loadConfig(options.config)
|
|
536
|
-
const srcDir = path.resolve(process.cwd(), config.src)
|
|
537
|
-
|
|
538
|
-
if (!fs.existsSync(srcDir)) {
|
|
539
|
-
logError(`Dossier source introuvable: ${srcDir}`)
|
|
540
|
-
process.exit(1)
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
const compiler = new EtherCompiler(config)
|
|
544
|
-
const files = findEthFiles(srcDir)
|
|
545
|
-
|
|
546
|
-
if (files.length === 0) {
|
|
547
|
-
logWarning('Aucun fichier .eth trouvé')
|
|
548
|
-
return
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
let validCount = 0
|
|
552
|
-
let errorCount = 0
|
|
553
|
-
|
|
554
|
-
for (const file of files) {
|
|
555
|
-
const relativePath = path.relative(srcDir, file)
|
|
556
|
-
|
|
557
|
-
try {
|
|
558
|
-
await compiler.check(file)
|
|
559
|
-
logSuccess(relativePath)
|
|
560
|
-
validCount++
|
|
561
|
-
} catch (err) {
|
|
562
|
-
logError(`${relativePath}: ${err.message}`)
|
|
563
|
-
errorCount++
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
console.log('')
|
|
568
|
-
if (errorCount === 0) {
|
|
569
|
-
logSuccess(`${validCount} fichier(s) valide(s)`)
|
|
570
|
-
} else {
|
|
571
|
-
logError(`${errorCount} erreur(s) sur ${files.length} fichier(s)`)
|
|
572
|
-
process.exit(1)
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
function findEthFiles(dir) {
|
|
577
|
-
const files = []
|
|
578
|
-
|
|
579
|
-
function scan(currentDir) {
|
|
580
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true })
|
|
581
|
-
|
|
582
|
-
for (const entry of entries) {
|
|
583
|
-
const fullPath = path.join(currentDir, entry.name)
|
|
584
|
-
|
|
585
|
-
if (entry.isDirectory()) {
|
|
586
|
-
if (!['node_modules', '.git', 'dist'].includes(entry.name)) {
|
|
587
|
-
scan(fullPath)
|
|
588
|
-
}
|
|
589
|
-
} else if (entry.name.endsWith('.eth')) {
|
|
590
|
-
files.push(fullPath)
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
scan(dir)
|
|
596
|
-
return files
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
function copyDir(src, dest) {
|
|
600
|
-
if (!fs.existsSync(dest)) {
|
|
601
|
-
fs.mkdirSync(dest, { recursive: true })
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
const entries = fs.readdirSync(src, { withFileTypes: true })
|
|
605
|
-
|
|
606
|
-
for (const entry of entries) {
|
|
607
|
-
const srcPath = path.join(src, entry.name)
|
|
608
|
-
const destPath = path.join(dest, entry.name)
|
|
609
|
-
|
|
610
|
-
if (entry.isDirectory()) {
|
|
611
|
-
copyDir(srcPath, destPath)
|
|
612
|
-
} else {
|
|
613
|
-
fs.copyFileSync(srcPath, destPath)
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
function parseArgs(args) {
|
|
619
|
-
const options = {
|
|
620
|
-
command: null,
|
|
621
|
-
config: null,
|
|
622
|
-
output: null,
|
|
623
|
-
port: null,
|
|
624
|
-
verbose: false,
|
|
625
|
-
quiet: false,
|
|
626
|
-
watch: false
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
let i = 0
|
|
630
|
-
while (i < args.length) {
|
|
631
|
-
const arg = args[i]
|
|
632
|
-
|
|
633
|
-
if (arg === '-c' || arg === '--config') {
|
|
634
|
-
options.config = args[++i]
|
|
635
|
-
} else if (arg === '-o' || arg === '--output') {
|
|
636
|
-
options.output = args[++i]
|
|
637
|
-
} else if (arg === '-p' || arg === '--port') {
|
|
638
|
-
options.port = parseInt(args[++i], 10)
|
|
639
|
-
} else if (arg === '-v' || arg === '--verbose') {
|
|
640
|
-
options.verbose = true
|
|
641
|
-
} else if (arg === '-q' || arg === '--quiet') {
|
|
642
|
-
options.quiet = true
|
|
643
|
-
} else if (arg === '-w' || arg === '--watch') {
|
|
644
|
-
options.watch = true
|
|
645
|
-
} else if (arg === '--no-color') {
|
|
646
|
-
for (const key in COLORS) {
|
|
647
|
-
COLORS[key] = ''
|
|
648
|
-
}
|
|
649
|
-
} else if (!arg.startsWith('-')) {
|
|
650
|
-
if (!options.command) {
|
|
651
|
-
options.command = arg
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
i++
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
return options
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
async function main() {
|
|
662
|
-
const args = process.argv.slice(2)
|
|
663
|
-
const options = parseArgs(args)
|
|
664
|
-
|
|
665
|
-
if (options.watch && !options.command) {
|
|
666
|
-
options.command = 'dev'
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
switch (options.command) {
|
|
670
|
-
case 'init':
|
|
671
|
-
await cmdInit()
|
|
672
|
-
break
|
|
673
|
-
case 'build':
|
|
674
|
-
await cmdBuild(options)
|
|
675
|
-
break
|
|
676
|
-
case 'dev':
|
|
677
|
-
case 'watch':
|
|
678
|
-
await cmdDev(options)
|
|
679
|
-
break
|
|
680
|
-
case 'check':
|
|
681
|
-
await cmdCheck(options)
|
|
682
|
-
break
|
|
683
|
-
case 'version':
|
|
684
|
-
case '-V':
|
|
685
|
-
case '--version':
|
|
686
|
-
showVersion()
|
|
687
|
-
break
|
|
688
|
-
case 'help':
|
|
689
|
-
case '-h':
|
|
690
|
-
case '--help':
|
|
691
|
-
default:
|
|
692
|
-
showHelp()
|
|
693
|
-
break
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
main().catch(err => {
|
|
698
|
-
logError(err.message)
|
|
699
|
-
process.exit(1)
|
|
700
|
-
})
|