ether-code 0.6.2 → 0.6.4

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.
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs')
2
2
 
3
3
  class HTMLGenerator {
4
- constructor(i18nPath = null) {
4
+ constructor(i18nPath = null, options = {}) {
5
5
  this.i18n = null
6
6
  this.indent = 0
7
7
  this.output = ''
@@ -12,6 +12,12 @@ class HTMLGenerator {
12
12
  'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
13
13
  'link', 'meta', 'param', 'source', 'track', 'wbr'
14
14
  ]
15
+ this.multiWordTags = []
16
+ this.multiWordAttrs = []
17
+
18
+ this.parser = options.parser || null
19
+ this.jsGenerator = options.jsGenerator || null
20
+ this.cssGenerator = options.cssGenerator || null
15
21
 
16
22
  if (i18nPath) {
17
23
  this.loadI18n(i18nPath)
@@ -28,86 +34,154 @@ class HTMLGenerator {
28
34
  this.tagMap = {}
29
35
  this.attrMap = {}
30
36
  this.eventMap = {}
37
+ this.multiWordTags = []
38
+ this.multiWordAttrs = []
31
39
 
32
40
  if (!this.i18n) return
33
41
 
34
- const addToMap = (map, section, targetKey = 'html') => {
42
+ const addToTagMap = (section) => {
35
43
  if (!section) return
36
44
  for (const [key, translations] of Object.entries(section)) {
37
- if (translations && translations.fr && translations[targetKey]) {
38
- map[translations.fr.toLowerCase()] = translations[targetKey]
45
+ if (translations && translations.fr && translations.html) {
46
+ const frTerm = translations.fr.toLowerCase()
47
+ this.tagMap[frTerm] = translations.html
48
+ if (frTerm.includes(' ')) {
49
+ this.multiWordTags.push(frTerm)
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ const addToAttrMap = (section) => {
56
+ if (!section) return
57
+ for (const [key, translations] of Object.entries(section)) {
58
+ if (translations && translations.fr && translations.html) {
59
+ const frTerm = translations.fr.toLowerCase()
60
+ this.attrMap[frTerm] = translations.html
61
+ if (frTerm.includes(' ')) {
62
+ this.multiWordAttrs.push(frTerm)
63
+ }
39
64
  }
40
65
  }
41
66
  }
42
67
 
43
- addToMap(this.tagMap, this.i18n.rootElements)
44
- addToMap(this.tagMap, this.i18n.metadata)
45
- addToMap(this.tagMap, this.i18n.semanticSections)
46
- addToMap(this.tagMap, this.i18n.headings)
47
- addToMap(this.tagMap, this.i18n.textContent)
48
- addToMap(this.tagMap, this.i18n.inlineSemantics)
49
- addToMap(this.tagMap, this.i18n.lists)
50
- addToMap(this.tagMap, this.i18n.textFormatting)
51
- addToMap(this.tagMap, this.i18n.codeAndData)
52
- addToMap(this.tagMap, this.i18n.images)
53
- addToMap(this.tagMap, this.i18n.media)
54
- addToMap(this.tagMap, this.i18n.embeddedContent)
55
- addToMap(this.tagMap, this.i18n.graphics)
56
- addToMap(this.tagMap, this.i18n.tableStructure)
57
- addToMap(this.tagMap, this.i18n.formStructure)
58
- addToMap(this.tagMap, this.i18n.formInputs)
59
- addToMap(this.tagMap, this.i18n.interactive)
60
- addToMap(this.tagMap, this.i18n.genericContainers)
61
-
62
- addToMap(this.attrMap, this.i18n.globalAttributes)
63
- addToMap(this.attrMap, this.i18n.linkAttributes)
64
- addToMap(this.attrMap, this.i18n.imageAttributes)
65
- addToMap(this.attrMap, this.i18n.formAttributes)
66
- addToMap(this.attrMap, this.i18n.inputAttributes)
67
- addToMap(this.attrMap, this.i18n.textareaAttributes)
68
- addToMap(this.attrMap, this.i18n.mediaAttributes)
69
- addToMap(this.attrMap, this.i18n.tableAttributes)
70
- addToMap(this.attrMap, this.i18n.metaAttributes)
71
- addToMap(this.attrMap, this.i18n.ariaStates)
72
- addToMap(this.attrMap, this.i18n.ariaProperties)
73
-
74
- addToMap(this.eventMap, this.i18n.windowEvents)
75
- addToMap(this.eventMap, this.i18n.mouseEvents)
76
- addToMap(this.eventMap, this.i18n.keyboardEvents)
77
- addToMap(this.eventMap, this.i18n.formEvents)
78
- addToMap(this.eventMap, this.i18n.mediaEvents)
79
- addToMap(this.eventMap, this.i18n.dragEvents)
80
- addToMap(this.eventMap, this.i18n.clipboardEvents)
81
- addToMap(this.eventMap, this.i18n.touchEvents)
82
- addToMap(this.eventMap, this.i18n.pointerEvents)
68
+ addToTagMap(this.i18n.rootElements)
69
+ addToTagMap(this.i18n.metadata)
70
+ addToTagMap(this.i18n.semanticSections)
71
+ addToTagMap(this.i18n.headings)
72
+ addToTagMap(this.i18n.textContent)
73
+ addToTagMap(this.i18n.inlineSemantics)
74
+ addToTagMap(this.i18n.lists)
75
+ addToTagMap(this.i18n.textFormatting)
76
+ addToTagMap(this.i18n.codeAndData)
77
+ addToTagMap(this.i18n.editAnnotations)
78
+ addToTagMap(this.i18n.asianText)
79
+ addToTagMap(this.i18n.bidirectional)
80
+ addToTagMap(this.i18n.otherInline)
81
+ addToTagMap(this.i18n.images)
82
+ addToTagMap(this.i18n.audioVideo)
83
+ addToTagMap(this.i18n.embeddedContent)
84
+ addToTagMap(this.i18n.graphics)
85
+ addToTagMap(this.i18n.tableStructure)
86
+ addToTagMap(this.i18n.formStructure)
87
+ addToTagMap(this.i18n.formInputs)
88
+ addToTagMap(this.i18n.interactive)
89
+ addToTagMap(this.i18n.scripting)
90
+ addToTagMap(this.i18n.genericContainers)
91
+
92
+ addToAttrMap(this.i18n.globalAttributes)
93
+ addToAttrMap(this.i18n.linkAttributes)
94
+ addToAttrMap(this.i18n.imageAttributes)
95
+ addToAttrMap(this.i18n.formAttributes)
96
+ addToAttrMap(this.i18n.inputAttributes)
97
+ addToAttrMap(this.i18n.textareaAttributes)
98
+ addToAttrMap(this.i18n.mediaAttributes)
99
+ addToAttrMap(this.i18n.tableAttributes)
100
+ addToAttrMap(this.i18n.metaAttributes)
101
+ addToAttrMap(this.i18n.iframeAttributes)
102
+ addToAttrMap(this.i18n.scriptAttributes)
103
+ addToAttrMap(this.i18n.objectAttributes)
104
+ addToAttrMap(this.i18n.areaAttributes)
105
+ addToAttrMap(this.i18n.ariaStates)
106
+ addToAttrMap(this.i18n.ariaProperties)
107
+
108
+ addToAttrMap(this.i18n.windowEvents)
109
+ addToAttrMap(this.i18n.mouseEvents)
110
+ addToAttrMap(this.i18n.keyboardEvents)
111
+ addToAttrMap(this.i18n.formEvents)
112
+ addToAttrMap(this.i18n.mediaEvents)
113
+ addToAttrMap(this.i18n.dragEvents)
114
+ addToAttrMap(this.i18n.clipboardEvents)
115
+ addToAttrMap(this.i18n.touchEvents)
116
+ addToAttrMap(this.i18n.pointerEvents)
117
+ addToAttrMap(this.i18n.focusEvents)
118
+ addToAttrMap(this.i18n.animationEvents)
119
+
120
+ this.multiWordTags.sort((a, b) => b.length - a.length)
121
+ this.multiWordAttrs.sort((a, b) => b.length - a.length)
83
122
  }
84
123
 
85
124
  translateTag(tag) {
86
125
  const lower = tag.toLowerCase()
87
126
  const withSpaces = lower.replace(/-/g, ' ')
88
- let result = this.tagMap[lower] || this.tagMap[withSpaces] || this.translateGenericTag(tag)
127
+
128
+ let result = this.tagMap[lower] || this.tagMap[withSpaces]
129
+
130
+ if (!result) {
131
+ for (const multiWord of this.multiWordTags) {
132
+ if (lower === multiWord || withSpaces === multiWord) {
133
+ result = this.tagMap[multiWord]
134
+ break
135
+ }
136
+ }
137
+ }
138
+
139
+ if (!result) {
140
+ result = this.translateGenericTag(tag)
141
+ }
142
+
89
143
  result = result.replace(/^<|>$/g, '').trim()
90
144
  return result
91
145
  }
92
146
 
93
147
  translateAttribute(attr) {
94
148
  const lower = attr.toLowerCase()
95
- return this.attrMap[lower] || this.eventMap[lower] || this.translateGenericAttr(attr)
149
+
150
+ let result = this.attrMap[lower]
151
+
152
+ if (!result) {
153
+ for (const multiWord of this.multiWordAttrs) {
154
+ if (lower === multiWord) {
155
+ result = this.attrMap[multiWord]
156
+ break
157
+ }
158
+ }
159
+ }
160
+
161
+ if (!result) {
162
+ result = this.translateGenericAttr(attr)
163
+ }
164
+
165
+ return result
96
166
  }
97
167
 
98
168
  translateGenericTag(tag) {
99
169
  const translations = {
100
170
  'document': 'html',
171
+ 'tête': 'head',
101
172
  'tete': 'head',
102
173
  'corps': 'body',
103
174
  'titre': 'title',
175
+ 'méta': 'meta',
104
176
  'meta': 'meta',
105
177
  'lien': 'a',
106
178
  'liaison': 'link',
107
179
  'style': 'style',
108
180
  'script': 'script',
181
+ 'base': 'base',
182
+ 'entête': 'header',
109
183
  'entete': 'header',
110
- 'piedpage': 'footer',
184
+ 'pied de page': 'footer',
111
185
  'pied': 'footer',
112
186
  'navigation': 'nav',
113
187
  'nav': 'nav',
@@ -115,106 +189,165 @@ class HTMLGenerator {
115
189
  'section': 'section',
116
190
  'article': 'article',
117
191
  'aside': 'aside',
192
+ 'côté': 'aside',
118
193
  'cote': 'aside',
119
194
  'recherche': 'search',
120
195
  'adresse': 'address',
121
- 'titre1': 'h1',
122
- 'titre2': 'h2',
123
- 'titre3': 'h3',
124
- 'titre4': 'h4',
125
- 'titre5': 'h5',
126
- 'titre6': 'h6',
196
+ 'groupe titres': 'hgroup',
197
+ 'titre 1': 'h1',
198
+ 'titre 2': 'h2',
199
+ 'titre 3': 'h3',
200
+ 'titre 4': 'h4',
201
+ 'titre 5': 'h5',
202
+ 'titre 6': 'h6',
127
203
  'paragraphe': 'p',
128
204
  'division': 'div',
129
205
  'div': 'div',
206
+ 'étendue': 'span',
207
+ 'etendue': 'span',
130
208
  'span': 'span',
131
- 'portee': 'span',
132
209
  'image': 'img',
210
+ 'image réactive': 'picture',
211
+ 'image reactive': 'picture',
133
212
  'figure': 'figure',
134
- 'legende': 'figcaption',
135
- 'liste': 'ul',
213
+ 'légende figure': 'figcaption',
214
+ 'legende figure': 'figcaption',
215
+ 'liste ordonnée': 'ol',
136
216
  'liste ordonnee': 'ol',
217
+ 'liste non ordonnée': 'ul',
137
218
  'liste non ordonnee': 'ul',
138
- 'element': 'li',
219
+ 'liste': 'ul',
220
+ 'élément liste': 'li',
139
221
  'element liste': 'li',
140
- 'definition': 'dl',
222
+ 'élément': 'li',
223
+ 'element': 'li',
224
+ 'liste description': 'dl',
141
225
  'terme': 'dt',
142
- 'description': 'dd',
226
+ 'définition': 'dd',
227
+ 'definition': 'dd',
228
+ 'menu': 'menu',
143
229
  'tableau': 'table',
144
- 'ligne': 'tr',
145
- 'cellule': 'td',
146
- 'entete cellule': 'th',
230
+ 'légende tableau': 'caption',
231
+ 'legende tableau': 'caption',
232
+ 'entête tableau': 'thead',
147
233
  'entete tableau': 'thead',
148
234
  'corps tableau': 'tbody',
149
235
  'pied tableau': 'tfoot',
236
+ 'groupe colonnes': 'colgroup',
237
+ 'colonne': 'col',
238
+ 'ligne': 'tr',
239
+ 'cellule entête': 'th',
240
+ 'cellule entete': 'th',
241
+ 'cellule': 'td',
150
242
  'formulaire': 'form',
243
+ 'ensemble champs': 'fieldset',
244
+ 'groupe champs': 'fieldset',
245
+ 'légende': 'legend',
246
+ 'legende': 'legend',
247
+ 'legende groupe': 'legend',
248
+ 'étiquette': 'label',
151
249
  'etiquette': 'label',
250
+ 'entrée': 'input',
251
+ 'entree': 'input',
152
252
  'champ': 'input',
153
253
  'zone texte': 'textarea',
254
+ 'sélection': 'select',
154
255
  'selection': 'select',
155
- 'option': 'option',
156
256
  'groupe options': 'optgroup',
257
+ 'option': 'option',
258
+ 'liste données': 'datalist',
259
+ 'liste donnees': 'datalist',
157
260
  'bouton': 'button',
158
- 'groupe champs': 'fieldset',
159
- 'legende groupe': 'legend',
160
- 'video': 'video',
261
+ 'résultat': 'output',
262
+ 'resultat': 'output',
263
+ 'sortie': 'output',
264
+ 'progression': 'progress',
265
+ 'mesure': 'meter',
266
+ 'metre': 'meter',
161
267
  'audio': 'audio',
268
+ 'vidéo': 'video',
269
+ 'video': 'video',
162
270
  'source': 'source',
163
271
  'piste': 'track',
272
+ 'cadre en ligne': 'iframe',
164
273
  'cadre': 'iframe',
165
- 'objet': 'object',
274
+ 'intégrer': 'embed',
166
275
  'integrer': 'embed',
276
+ 'objet': 'object',
277
+ 'canevas': 'canvas',
167
278
  'canvas': 'canvas',
168
279
  'toile': 'canvas',
169
280
  'svg': 'svg',
170
281
  'math': 'math',
171
- 'gras': 'strong',
172
- 'fort': 'strong',
173
- 'italique': 'em',
282
+ 'carte image': 'map',
283
+ 'carte': 'map',
284
+ 'zone': 'area',
285
+ 'zone cliquable': 'area',
174
286
  'emphase': 'em',
287
+ 'fort': 'strong',
288
+ 'gras': 'b',
289
+ 'petit': 'small',
290
+ 'citation': 'q',
291
+ 'citation bloc': 'blockquote',
292
+ 'citation courte': 'q',
293
+ 'référence citation': 'cite',
294
+ 'reference citation': 'cite',
295
+ 'abréviation': 'abbr',
296
+ 'abreviation': 'abbr',
297
+ 'définition': 'dfn',
298
+ 'italique': 'i',
299
+ 'souligné': 'u',
175
300
  'souligne': 'u',
301
+ 'barré': 's',
176
302
  'barre': 's',
177
- 'supprime': 'del',
178
- 'insere': 'ins',
179
- 'petit': 'small',
303
+ 'marqué': 'mark',
180
304
  'marque': 'mark',
305
+ 'indice': 'sub',
306
+ 'exposant': 'sup',
181
307
  'code': 'code',
182
- 'pre': 'pre',
183
- 'preformate': 'pre',
184
- 'citation': 'blockquote',
185
- 'citation courte': 'q',
186
- 'abreviation': 'abbr',
187
- 'temps': 'time',
188
308
  'variable': 'var',
189
- 'clavier': 'kbd',
309
+ 'sortie exemple': 'samp',
190
310
  'exemple': 'samp',
191
- 'indice': 'sub',
192
- 'exposant': 'sup',
193
- 'ligne horizontale': 'hr',
194
- 'saut ligne': 'br',
311
+ 'entrée clavier': 'kbd',
312
+ 'entree clavier': 'kbd',
313
+ 'clavier': 'kbd',
314
+ 'donnée': 'data',
315
+ 'donnee': 'data',
316
+ 'donnees': 'data',
317
+ 'temps': 'time',
318
+ 'inséré': 'ins',
319
+ 'insere': 'ins',
320
+ 'supprimé': 'del',
321
+ 'supprime': 'del',
322
+ 'ruby': 'ruby',
323
+ 'annotation ruby': 'rt',
324
+ 'parenthèses ruby': 'rp',
325
+ 'parentheses ruby': 'rp',
326
+ 'isolation bidi': 'bdi',
327
+ 'remplacement bidi': 'bdo',
328
+ 'retour ligne possible': 'wbr',
329
+ 'césure': 'wbr',
330
+ 'cesure': 'wbr',
331
+ 'wbr': 'wbr',
332
+ 'préformaté': 'pre',
333
+ 'preformate': 'pre',
334
+ 'pre': 'pre',
195
335
  'retour ligne': 'br',
336
+ 'saut ligne': 'br',
196
337
  'br': 'br',
338
+ 'ligne horizontale': 'hr',
197
339
  'hr': 'hr',
340
+ 'détails': 'details',
198
341
  'details': 'details',
342
+ 'résumé': 'summary',
199
343
  'resume': 'summary',
200
344
  'dialogue': 'dialog',
201
- 'menu': 'menu',
345
+ 'modèle': 'template',
202
346
  'modele': 'template',
203
- 'slot': 'slot',
204
347
  'emplacement': 'slot',
205
- 'donnees': 'data',
206
- 'metre': 'meter',
207
- 'progression': 'progress',
208
- 'sortie': 'output',
209
- 'carte': 'map',
210
- 'zone cliquable': 'area',
211
- 'groupe colonnes': 'colgroup',
212
- 'colonne': 'col',
213
- 'legende tableau': 'caption',
214
- 'wbr': 'wbr',
215
- 'cesure': 'wbr',
216
- 'noscript': 'noscript',
217
- 'sans script': 'noscript'
348
+ 'slot': 'slot',
349
+ 'sans script': 'noscript',
350
+ 'noscript': 'noscript'
218
351
  }
219
352
 
220
353
  const lower = tag.toLowerCase()
@@ -229,157 +362,201 @@ class HTMLGenerator {
229
362
  'titre': 'title',
230
363
  'langue': 'lang',
231
364
  'direction': 'dir',
365
+ 'caché': 'hidden',
232
366
  'cache': 'hidden',
233
367
  'tabindex': 'tabindex',
368
+ 'ordre tabulation': 'tabindex',
234
369
  'index tabulation': 'tabindex',
370
+ 'éditable': 'contenteditable',
235
371
  'editable': 'contenteditable',
236
- 'draggable': 'draggable',
372
+ 'glissable': 'draggable',
373
+ 'déplaçable': 'draggable',
237
374
  'deplacable': 'draggable',
375
+ 'inerte': 'inert',
376
+ 'popover': 'popover',
377
+ 'rôle': 'role',
238
378
  'role': 'role',
379
+ 'href': 'href',
239
380
  'adresse': 'href',
240
381
  'cible': 'target',
241
- 'nouvelle fenetre': '_blank',
382
+ 'relation': 'rel',
383
+ 'téléchargement': 'download',
384
+ 'telechargement': 'download',
242
385
  'source': 'src',
386
+ 'src': 'src',
387
+ 'srcset': 'srcset',
388
+ 'sources réactives': 'srcset',
389
+ 'sources reactives': 'srcset',
390
+ 'média': 'media',
391
+ 'media': 'media',
392
+ 'alternative': 'alt',
393
+ 'texte alternatif': 'alt',
243
394
  'alt': 'alt',
244
395
  'alternatif': 'alt',
245
- 'texte alternatif': 'alt',
246
396
  'largeur': 'width',
247
397
  'hauteur': 'height',
248
398
  'chargement': 'loading',
249
- 'paresseux': 'lazy',
399
+ 'décodage': 'decoding',
400
+ 'decodage': 'decoding',
401
+ 'tailles': 'sizes',
402
+ 'usemap': 'usemap',
403
+ 'forme': 'shape',
404
+ 'coords': 'coords',
405
+ 'coordonnées': 'coords',
406
+ 'coordonnees': 'coords',
250
407
  'action': 'action',
408
+ 'méthode': 'method',
251
409
  'methode': 'method',
410
+ 'enctype': 'enctype',
411
+ 'type encodage': 'enctype',
412
+ 'cible formulaire': 'formtarget',
413
+ 'novalidate': 'novalidate',
414
+ 'sans validation': 'novalidate',
415
+ 'autocomplétion': 'autocomplete',
416
+ 'autocompletion': 'autocomplete',
252
417
  'type': 'type',
253
418
  'nom': 'name',
254
- 'contenu': 'content',
255
419
  'valeur': 'value',
256
- 'valeur min': 'min',
257
- 'valeur max': 'max',
258
420
  'placeholder': 'placeholder',
259
421
  'indicateur': 'placeholder',
260
422
  'requis': 'required',
261
423
  'obligatoire': 'required',
424
+ 'aria-required': 'aria-required',
425
+ 'désactivé': 'disabled',
262
426
  'desactive': 'disabled',
263
427
  'lecture seule': 'readonly',
264
- 'coche': 'checked',
265
- 'selectionne': 'selected',
266
- 'multiple': 'multiple',
267
- 'minimum': 'min',
428
+ 'autofocus': 'autofocus',
429
+ 'longueur max': 'maxlength',
430
+ 'longueur min': 'minlength',
431
+ 'valeur max': 'max',
432
+ 'max': 'max',
268
433
  'maximum': 'max',
434
+ 'valeur min': 'min',
435
+ 'min': 'min',
436
+ 'minimum': 'min',
269
437
  'pas': 'step',
270
438
  'motif': 'pattern',
271
- 'longueur min': 'minlength',
272
- 'longueur max': 'maxlength',
273
- 'autocomplete': 'autocomplete',
274
- 'autofocus': 'autofocus',
275
- 'focus auto': 'autofocus',
276
- 'lignes': 'rows',
439
+ 'taille': 'size',
440
+ 'liste': 'list',
441
+ 'multiple': 'multiple',
442
+ 'accepter': 'accept',
443
+ 'accept': 'accept',
444
+ 'capture': 'capture',
445
+ 'coché': 'checked',
446
+ 'coche': 'checked',
447
+ 'sélectionné': 'selected',
448
+ 'selectionne': 'selected',
277
449
  'colonnes': 'cols',
450
+ 'cols': 'cols',
451
+ 'rangées': 'rows',
452
+ 'rangees': 'rows',
453
+ 'lignes': 'rows',
454
+ 'rows': 'rows',
455
+ 'retour à la ligne': 'wrap',
456
+ 'retour a la ligne': 'wrap',
457
+ 'contrôles': 'controls',
278
458
  'controles': 'controls',
279
459
  'lecture auto': 'autoplay',
280
460
  'boucle': 'loop',
281
461
  'muet': 'muted',
282
- 'affiche': 'poster',
462
+ 'préchargement': 'preload',
283
463
  'prechargement': 'preload',
284
- 'fusion lignes': 'rowspan',
285
- 'fusion colonnes': 'colspan',
286
- 'portee': 'scope',
287
- 'pour': 'for',
464
+ 'affiche': 'poster',
465
+ 'poster': 'poster',
466
+ 'lecture en ligne': 'playsinline',
467
+ 'kind': 'kind',
468
+ 'srclang': 'srclang',
469
+ 'étiquette': 'label',
288
470
  'etiquette': 'label',
289
- 'accept': 'accept',
290
- 'accepter': 'accept',
291
- 'enctype': 'enctype',
292
- 'encodage': 'enctype',
293
- 'rel': 'rel',
294
- 'relation': 'rel',
295
- 'media': 'media',
296
- 'type media': 'media',
471
+ 'défaut': 'default',
472
+ 'defaut': 'default',
473
+ 'allow': 'allow',
474
+ 'allowfullscreen': 'allowfullscreen',
475
+ 'plein écran': 'allowfullscreen',
476
+ 'plein ecran': 'allowfullscreen',
477
+ 'sandbox': 'sandbox',
478
+ 'données': 'data',
479
+ 'donnees': 'data',
480
+ 'portée': 'scope',
481
+ 'portee': 'scope',
482
+ 'colspan': 'colspan',
483
+ 'fusion colonnes': 'colspan',
484
+ 'rowspan': 'rowspan',
485
+ 'fusion lignes': 'rowspan',
486
+ 'étendue': 'span',
487
+ 'etendue': 'span',
488
+ 'span': 'span',
489
+ 'contenu': 'content',
490
+ 'jeu caractères': 'charset',
491
+ 'jeu caracteres': 'charset',
297
492
  'charset': 'charset',
298
- 'encodage caracteres': 'charset',
493
+ 'http-equiv': 'http-equiv',
494
+ 'équivalent http': 'http-equiv',
495
+ 'equivalent http': 'http-equiv',
496
+ 'ouvert': 'open',
497
+ 'différé': 'defer',
498
+ 'differe': 'defer',
499
+ 'defer': 'defer',
299
500
  'async': 'async',
300
501
  'asynchrone': 'async',
301
- 'defer': 'defer',
302
- 'differer': 'defer',
303
- 'crossorigin': 'crossorigin',
304
- 'origine croisee': 'crossorigin',
305
- 'integrite': 'integrity',
306
- 'referrerpolicy': 'referrerpolicy',
307
- 'politique referent': 'referrerpolicy',
308
- 'sandbox': 'sandbox',
309
- 'bac a sable': 'sandbox',
310
- 'allow': 'allow',
311
- 'autoriser': 'allow',
312
- 'donnees': 'data',
313
- 'accesskey': 'accesskey',
314
- 'touche acces': 'accesskey',
315
- 'translate': 'translate',
316
- 'traduire': 'translate',
317
- 'spellcheck': 'spellcheck',
318
- 'orthographe': 'spellcheck',
319
- 'enterkeyhint': 'enterkeyhint',
320
- 'indice entree': 'enterkeyhint',
321
- 'inputmode': 'inputmode',
322
- 'mode saisie': 'inputmode',
323
- 'is': 'is',
324
- 'est': 'is',
325
- 'part': 'part',
326
- 'partie': 'part',
327
- 'exportparts': 'exportparts',
328
- 'exporter parties': 'exportparts',
329
- 'nonce': 'nonce',
330
- 'jeton': 'nonce'
502
+ 'pour': 'for',
503
+ 'datetime': 'datetime',
504
+ 'cite': 'cite',
505
+ 'nouvelle fenêtre': '_blank',
506
+ 'nouvelle fenetre': '_blank',
507
+ 'même fenêtre': '_self',
508
+ 'meme fenetre': '_self',
509
+ 'low': 'low',
510
+ 'bas': 'low',
511
+ 'high': 'high',
512
+ 'haut': 'high',
513
+ 'optimum': 'optimum',
514
+ 'start': 'start',
515
+ 'début': 'start',
516
+ 'debut': 'start',
517
+ 'reversed': 'reversed',
518
+ 'inversé': 'reversed',
519
+ 'inverse': 'reversed',
520
+ 'aria-label': 'aria-label',
521
+ 'aria-describedby': 'aria-describedby',
522
+ 'décrit par': 'aria-describedby',
523
+ 'decrit par': 'aria-describedby',
524
+ 'aria-labelledby': 'aria-labelledby',
525
+ 'étiqueté par': 'aria-labelledby',
526
+ 'etiquete par': 'aria-labelledby',
527
+ 'aria-hidden': 'aria-hidden',
528
+ 'aria-expanded': 'aria-expanded',
529
+ 'étendu': 'aria-expanded',
530
+ 'aria-controls': 'aria-controls',
531
+ 'aria-live': 'aria-live',
532
+ 'en direct': 'aria-live',
533
+ 'aria-atomic': 'aria-atomic'
331
534
  }
332
535
 
333
536
  const lower = attr.toLowerCase()
334
537
  return translations[lower] || attr
335
538
  }
336
539
 
337
- translateInputType(type) {
338
- const types = {
339
- 'texte': 'text',
340
- 'mot de passe': 'password',
341
- 'email': 'email',
342
- 'courriel': 'email',
343
- 'nombre': 'number',
344
- 'telephone': 'tel',
345
- 'url': 'url',
346
- 'recherche': 'search',
347
- 'date': 'date',
348
- 'heure': 'time',
349
- 'datetime': 'datetime-local',
350
- 'date heure': 'datetime-local',
351
- 'mois': 'month',
352
- 'semaine': 'week',
353
- 'couleur': 'color',
354
- 'fichier': 'file',
355
- 'cache': 'hidden',
356
- 'case a cocher': 'checkbox',
357
- 'bouton radio': 'radio',
358
- 'intervalle': 'range',
359
- 'soumettre': 'submit',
360
- 'reinitialiser': 'reset',
361
- 'bouton': 'button',
362
- 'image': 'image'
363
- }
364
-
365
- const lower = type.toLowerCase()
366
- return types[lower] || type
367
- }
368
-
369
540
  generate(ast) {
370
541
  this.output = ''
371
542
  this.indent = 0
372
543
 
373
- if (Array.isArray(ast)) {
374
- for (const node of ast) {
375
- this.generateNode(node)
544
+ if (ast.type === 'Document' || ast.type === 'document' || ast.type === 'root') {
545
+ const children = ast.children || []
546
+
547
+ if (children.length > 0) {
548
+ const firstChild = children[0]
549
+ const firstTag = (firstChild.tag || firstChild.tagName || '').toLowerCase()
550
+ if (firstTag === 'html' || firstTag === 'document') {
551
+ this.output += '<!DOCTYPE html>\n'
552
+ }
376
553
  }
377
- } else if (ast && ast.type) {
378
- this.generateNode(ast)
379
- } else if (ast && ast.children) {
380
- for (const child of ast.children) {
554
+
555
+ for (const child of children) {
381
556
  this.generateNode(child)
382
557
  }
558
+ } else {
559
+ this.generateNode(ast)
383
560
  }
384
561
 
385
562
  return this.output.trim()
@@ -389,17 +566,13 @@ class HTMLGenerator {
389
566
  if (!node) return
390
567
 
391
568
  switch (node.type) {
392
- case 'Document':
393
- case 'document':
394
- this.output += '<!DOCTYPE html>\n'
395
- if (node.children) {
396
- for (const child of node.children) {
397
- this.generateNode(child)
398
- }
399
- }
569
+ case 'Doctype':
570
+ case 'doctype':
571
+ this.generateDoctype(node)
400
572
  break
401
573
  case 'Element':
402
574
  case 'element':
575
+ case 'tag':
403
576
  this.generateElement(node)
404
577
  break
405
578
  case 'Text':
@@ -410,15 +583,12 @@ class HTMLGenerator {
410
583
  case 'comment':
411
584
  this.generateComment(node)
412
585
  break
413
- case 'Doctype':
414
- case 'doctype':
415
- this.generateDoctype(node)
416
- break
417
586
  case 'Include':
587
+ case 'include':
418
588
  this.generateInclude(node)
419
589
  break
420
590
  default:
421
- if (node.tag || node.tagName) {
591
+ if (node.tag || node.tagName || node.name) {
422
592
  this.generateElement(node)
423
593
  } else if (node.text || node.content) {
424
594
  this.generateText(node)
@@ -437,6 +607,14 @@ class HTMLGenerator {
437
607
  }
438
608
  }
439
609
 
610
+ if (tag === 'a' && attrs.relation) {
611
+ const rel = this.translateAttribute(attrs.relation)
612
+ const linkRels = ['stylesheet', 'icon', 'preconnect', 'prefetch', 'preload', 'dns-prefetch', 'canonical', 'alternate', 'manifest', 'apple-touch-icon']
613
+ if (linkRels.some(r => rel.includes(r))) {
614
+ tag = 'link'
615
+ }
616
+ }
617
+
440
618
  const attributes = this.generateAttributes(attrs)
441
619
  const isVoid = this.voidElements.includes(tag.toLowerCase())
442
620
 
@@ -450,8 +628,18 @@ class HTMLGenerator {
450
628
  const textContent = typeof children === 'string' ? children :
451
629
  (node.text || node.textContent || null)
452
630
 
631
+ const isRawContent = (tag.toLowerCase() === 'script' || tag.toLowerCase() === 'style')
632
+
453
633
  if (textContent && !hasChildren) {
454
- this.writeLine(`<${tag}${attributes}>${this.escapeHtml(textContent)}</${tag}>`)
634
+ if (isRawContent) {
635
+ this.writeLine(`<${tag}${attributes}>`)
636
+ this.indent++
637
+ this.writeLine(textContent)
638
+ this.indent--
639
+ this.writeLine(`</${tag}>`)
640
+ } else {
641
+ this.writeLine(`<${tag}${attributes}>${this.escapeHtml(textContent)}</${tag}>`)
642
+ }
455
643
  return
456
644
  }
457
645
 
@@ -463,11 +651,33 @@ class HTMLGenerator {
463
651
  this.writeLine(`<${tag}${attributes}>`)
464
652
  this.indent++
465
653
 
466
- for (const child of children) {
467
- if (typeof child === 'string') {
468
- this.writeLine(this.escapeHtml(child))
469
- } else {
470
- this.generateNode(child)
654
+ if (isRawContent) {
655
+ let rawContent = ''
656
+ for (const child of children) {
657
+ if (typeof child === 'string') {
658
+ rawContent += child
659
+ } else if (child.type === 'Text' || child.type === 'text') {
660
+ const content = child.content || child.text || child.value || ''
661
+ if (content.trim()) {
662
+ rawContent += content
663
+ }
664
+ }
665
+ }
666
+
667
+ if (rawContent.trim()) {
668
+ const generatedCode = this.compileEmbeddedCode(rawContent.trim(), tag.toLowerCase())
669
+ const lines = generatedCode.split('\n')
670
+ for (const line of lines) {
671
+ this.writeLine(line)
672
+ }
673
+ }
674
+ } else {
675
+ for (const child of children) {
676
+ if (typeof child === 'string') {
677
+ this.writeLine(this.escapeHtml(child))
678
+ } else {
679
+ this.generateNode(child)
680
+ }
471
681
  }
472
682
  }
473
683
 
@@ -484,7 +694,7 @@ class HTMLGenerator {
484
694
  for (const [key, value] of Object.entries(attrs)) {
485
695
  let attrName = this.translateAttribute(key)
486
696
 
487
- if (attrName.startsWith('au ') || attrName.startsWith('a la ')) {
697
+ if (attrName.startsWith('au ') || attrName.startsWith('à la ') || attrName.startsWith('a la ')) {
488
698
  attrName = this.translateEvent(key)
489
699
  }
490
700
 
@@ -499,6 +709,10 @@ class HTMLGenerator {
499
709
  attrValue = this.translateInputType(value)
500
710
  }
501
711
 
712
+ if (attrName === 'target' && this.isTargetValue(value)) {
713
+ attrValue = this.translateTargetValue(value)
714
+ }
715
+
502
716
  parts.push(`${attrName}="${this.escapeAttr(attrValue)}"`)
503
717
  }
504
718
  }
@@ -512,53 +726,100 @@ class HTMLGenerator {
512
726
  'au double clic': 'ondblclick',
513
727
  'au survol': 'onmouseover',
514
728
  'au survol fin': 'onmouseout',
729
+ 'souris entrée': 'onmouseenter',
515
730
  'souris entree': 'onmouseenter',
731
+ 'entrée souris': 'onmouseenter',
732
+ 'entree souris': 'onmouseenter',
516
733
  'souris sortie': 'onmouseleave',
517
- 'souris bas': 'onmousedown',
518
- 'souris haut': 'onmouseup',
519
- 'souris mouvement': 'onmousemove',
734
+ 'sortie souris': 'onmouseleave',
735
+ 'bouton enfoncé': 'onmousedown',
736
+ 'bouton enfonce': 'onmousedown',
737
+ 'bouton relâché': 'onmouseup',
738
+ 'bouton relache': 'onmouseup',
739
+ 'mouvement souris': 'onmousemove',
520
740
  'au focus': 'onfocus',
521
- 'au focus perdu': 'onblur',
741
+ 'à la perte focus': 'onblur',
742
+ 'a la perte focus': 'onblur',
522
743
  'perte focus': 'onblur',
744
+ 'au focus perdu': 'onblur',
523
745
  'au changement': 'onchange',
746
+ 'à la saisie': 'oninput',
524
747
  'a la saisie': 'oninput',
748
+ 'touche enfoncée': 'onkeydown',
749
+ 'touche enfoncee': 'onkeydown',
525
750
  'touche bas': 'onkeydown',
751
+ 'touche relâchée': 'onkeyup',
752
+ 'touche relachee': 'onkeyup',
526
753
  'touche haut': 'onkeyup',
527
- 'touche presse': 'onkeypress',
754
+ 'à la soumission': 'onsubmit',
528
755
  'a la soumission': 'onsubmit',
756
+ 'à la réinitialisation': 'onreset',
529
757
  'a la reinitialisation': 'onreset',
530
758
  'au chargement': 'onload',
759
+ 'au déchargement': 'onunload',
760
+ 'au dechargement': 'onunload',
531
761
  'a la fermeture': 'onunload',
762
+ 'avant déchargement': 'onbeforeunload',
763
+ 'avant dechargement': 'onbeforeunload',
532
764
  'au redimensionnement': 'onresize',
765
+ 'au défilement': 'onscroll',
533
766
  'au defilement': 'onscroll',
767
+ 'à l\'erreur': 'onerror',
768
+ 'a l\'erreur': 'onerror',
534
769
  'erreur': 'onerror',
770
+ 'en ligne': 'ononline',
771
+ 'hors ligne': 'onoffline',
535
772
  'lecture': 'onplay',
536
773
  'pause': 'onpause',
537
774
  'fin': 'onended',
775
+ 'début glissement': 'ondragstart',
776
+ 'debut glissement': 'ondragstart',
538
777
  'glisser debut': 'ondragstart',
778
+ 'glissement': 'ondrag',
539
779
  'glisser': 'ondrag',
780
+ 'fin glissement': 'ondragend',
540
781
  'glisser fin': 'ondragend',
782
+ 'entrée zone': 'ondragenter',
783
+ 'entree zone': 'ondragenter',
541
784
  'glisser entree': 'ondragenter',
785
+ 'sortie zone': 'ondragleave',
542
786
  'glisser sortie': 'ondragleave',
787
+ 'survol zone': 'ondragover',
543
788
  'glisser survol': 'ondragover',
789
+ 'dépôt': 'ondrop',
790
+ 'depot': 'ondrop',
544
791
  'deposer': 'ondrop',
545
792
  'copier': 'oncopy',
546
793
  'couper': 'oncut',
547
794
  'coller': 'onpaste',
795
+ 'début toucher': 'ontouchstart',
796
+ 'debut toucher': 'ontouchstart',
548
797
  'toucher debut': 'ontouchstart',
798
+ 'mouvement toucher': 'ontouchmove',
549
799
  'toucher mouvement': 'ontouchmove',
800
+ 'fin toucher': 'ontouchend',
550
801
  'toucher fin': 'ontouchend',
802
+ 'annulation toucher': 'ontouchcancel',
551
803
  'toucher annuler': 'ontouchcancel',
552
- 'pointeur bas': 'onpointerdown',
553
- 'pointeur haut': 'onpointerup',
554
- 'pointeur mouvement': 'onpointermove',
555
- 'pointeur entree': 'onpointerenter',
556
- 'pointeur sortie': 'onpointerleave',
804
+ 'molette': 'onwheel',
557
805
  'roue': 'onwheel',
558
806
  'menu contextuel': 'oncontextmenu',
807
+ 'début animation': 'onanimationstart',
808
+ 'debut animation': 'onanimationstart',
559
809
  'animation debut': 'onanimationstart',
810
+ 'fin animation': 'onanimationend',
560
811
  'animation fin': 'onanimationend',
561
- 'transition fin': 'ontransitionend'
812
+ 'itération animation': 'onanimationiteration',
813
+ 'iteration animation': 'onanimationiteration',
814
+ 'début transition': 'ontransitionstart',
815
+ 'debut transition': 'ontransitionstart',
816
+ 'fin transition': 'ontransitionend',
817
+ 'transition fin': 'ontransitionend',
818
+ 'pointeur bas': 'onpointerdown',
819
+ 'pointeur haut': 'onpointerup',
820
+ 'pointeur mouvement': 'onpointermove',
821
+ 'pointeur entree': 'onpointerenter',
822
+ 'pointeur sortie': 'onpointerleave'
562
823
  }
563
824
 
564
825
  const lower = event.toLowerCase()
@@ -568,16 +829,70 @@ class HTMLGenerator {
568
829
  isInputType(value) {
569
830
  const types = [
570
831
  'texte', 'text', 'mot de passe', 'password', 'email', 'courriel',
571
- 'nombre', 'number', 'telephone', 'tel', 'url', 'recherche', 'search',
572
- 'date', 'heure', 'time', 'datetime', 'date heure', 'mois', 'month',
573
- 'semaine', 'week', 'couleur', 'color', 'fichier', 'file', 'cache',
574
- 'hidden', 'case a cocher', 'checkbox', 'bouton radio', 'radio',
575
- 'intervalle', 'range', 'soumettre', 'submit', 'reinitialiser', 'reset',
576
- 'bouton', 'button', 'image'
832
+ 'nombre', 'number', 'téléphone', 'telephone', 'tel', 'url',
833
+ 'recherche', 'search', 'date', 'heure', 'time', 'datetime-local',
834
+ 'date et heure locale', 'mois', 'month', 'semaine', 'week',
835
+ 'couleur', 'color', 'fichier', 'file', 'caché', 'cache', 'hidden',
836
+ 'case à cocher', 'case a cocher', 'checkbox', 'bouton radio', 'radio',
837
+ 'intervalle', 'range', 'soumettre', 'submit', 'réinitialiser',
838
+ 'reinitialiser', 'reset', 'bouton', 'button', 'image'
577
839
  ]
578
840
  return types.includes(value.toLowerCase())
579
841
  }
580
842
 
843
+ translateInputType(type) {
844
+ const types = {
845
+ 'texte': 'text',
846
+ 'mot de passe': 'password',
847
+ 'courriel': 'email',
848
+ 'nombre': 'number',
849
+ 'téléphone': 'tel',
850
+ 'telephone': 'tel',
851
+ 'recherche': 'search',
852
+ 'heure': 'time',
853
+ 'date et heure locale': 'datetime-local',
854
+ 'mois': 'month',
855
+ 'semaine': 'week',
856
+ 'couleur': 'color',
857
+ 'fichier': 'file',
858
+ 'caché': 'hidden',
859
+ 'cache': 'hidden',
860
+ 'case à cocher': 'checkbox',
861
+ 'case a cocher': 'checkbox',
862
+ 'bouton radio': 'radio',
863
+ 'intervalle': 'range',
864
+ 'soumettre': 'submit',
865
+ 'réinitialiser': 'reset',
866
+ 'reinitialiser': 'reset',
867
+ 'bouton': 'button'
868
+ }
869
+
870
+ return types[type.toLowerCase()] || type
871
+ }
872
+
873
+ isTargetValue(value) {
874
+ const targets = [
875
+ 'même fenêtre', 'meme fenetre', '_self',
876
+ 'nouvelle fenêtre', 'nouvelle fenetre', '_blank',
877
+ 'parent', '_parent',
878
+ 'haut', '_top'
879
+ ]
880
+ return targets.includes(value.toLowerCase())
881
+ }
882
+
883
+ translateTargetValue(value) {
884
+ const targets = {
885
+ 'même fenêtre': '_self',
886
+ 'meme fenetre': '_self',
887
+ 'nouvelle fenêtre': '_blank',
888
+ 'nouvelle fenetre': '_blank',
889
+ 'parent': '_parent',
890
+ 'haut': '_top'
891
+ }
892
+
893
+ return targets[value.toLowerCase()] || value
894
+ }
895
+
581
896
  generateText(node) {
582
897
  const text = node.text || node.content || node.value || ''
583
898
  if (text.trim()) {
@@ -689,6 +1004,44 @@ class HTMLGenerator {
689
1004
  }
690
1005
  }
691
1006
  }
1007
+
1008
+ compileEmbeddedCode(code, tagType) {
1009
+ const etherKeywords = [
1010
+ 'journal', 'afficher', 'variable', 'constante', 'fonction', 'si', 'sinon',
1011
+ 'pour', 'tant que', 'retourner', 'classe', 'methode', 'importer',
1012
+ 'fond', 'couleur', 'marge', 'bordure', 'police', 'largeur', 'hauteur',
1013
+ 'remplissage', 'alignement', 'affichage', 'position', 'flexbox', 'grille'
1014
+ ]
1015
+
1016
+ const lowerCode = code.toLowerCase()
1017
+ const hasEtherKeywords = etherKeywords.some(kw => lowerCode.includes(kw))
1018
+
1019
+ if (!hasEtherKeywords) {
1020
+ return code
1021
+ }
1022
+
1023
+ if (tagType === 'script' && this.parser && this.jsGenerator) {
1024
+ try {
1025
+ const ast = this.parser.parse(code, 'js')
1026
+ const generated = this.jsGenerator.generate(ast)
1027
+ return generated || code
1028
+ } catch (e) {
1029
+ return code
1030
+ }
1031
+ }
1032
+
1033
+ if (tagType === 'style' && this.parser && this.cssGenerator) {
1034
+ try {
1035
+ const ast = this.parser.parse(code, 'css')
1036
+ const generated = this.cssGenerator.generate(ast)
1037
+ return generated || code
1038
+ } catch (e) {
1039
+ return code
1040
+ }
1041
+ }
1042
+
1043
+ return code
1044
+ }
692
1045
  }
693
1046
 
694
1047
  module.exports = {