ether-code 0.6.9 → 0.7.1

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/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.6.9'
9
+ const VERSION = '0.7.1'
10
10
 
11
11
  const COLORS = {
12
12
  reset: '\x1b[0m',
@@ -32,11 +32,15 @@ class JSGenerator {
32
32
  return
33
33
  }
34
34
 
35
+ const normalize = (str) => {
36
+ return str.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')
37
+ }
38
+
35
39
  const addToMap = (map, section, prefix = '') => {
36
40
  if (!section) return
37
41
  for (const [key, translations] of Object.entries(section)) {
38
42
  if (translations && translations.fr && translations.en) {
39
- const frKey = translations.fr.toLowerCase()
43
+ const frKey = normalize(translations.fr)
40
44
  const enValue = translations.en
41
45
  if (prefix) {
42
46
  if (!this.contextualMap[frKey]) {
@@ -266,7 +270,9 @@ class JSGenerator {
266
270
  }
267
271
 
268
272
  buildDefaultMaps() {
269
- this.keywordMap = {
273
+ const norm = (str) => str.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')
274
+
275
+ const rawKeywords = {
270
276
  'variable': 'let',
271
277
  'constante': 'const',
272
278
  'variable globale': 'var',
@@ -377,7 +383,7 @@ class JSGenerator {
377
383
  'gabarit étiqueté': 'tagged template'
378
384
  }
379
385
 
380
- this.operatorMap = {
386
+ const rawOperators = {
381
387
  'plus': '+',
382
388
  'moins': '-',
383
389
  'fois': '*',
@@ -414,7 +420,7 @@ class JSGenerator {
414
420
  'décomposition': '...'
415
421
  }
416
422
 
417
- this.methodMap = {
423
+ const rawMethods = {
418
424
  'afficher': 'console.log',
419
425
  'journal': 'console.log',
420
426
  'erreur': 'console.error',
@@ -776,7 +782,23 @@ class JSGenerator {
776
782
  'décoder URI': 'decodeURI',
777
783
  'décoder composant URI': 'decodeURIComponent',
778
784
  'encoder URI': 'encodeURI',
779
- 'encoder composant URI': 'encodeURIComponent'
785
+ 'encoder composant URI': 'encodeURIComponent',
786
+ 'selecteur': 'querySelector',
787
+ 'selecteurs': 'querySelectorAll'
788
+ }
789
+
790
+ this.keywordMap = {}
791
+ this.operatorMap = {}
792
+ this.methodMap = {}
793
+
794
+ for (const [key, value] of Object.entries(rawKeywords)) {
795
+ this.keywordMap[norm(key)] = value
796
+ }
797
+ for (const [key, value] of Object.entries(rawOperators)) {
798
+ this.operatorMap[norm(key)] = value
799
+ }
800
+ for (const [key, value] of Object.entries(rawMethods)) {
801
+ this.methodMap[norm(key)] = value
780
802
  }
781
803
 
782
804
  this.buildConflictResolution()
@@ -795,7 +817,7 @@ class JSGenerator {
795
817
  }
796
818
 
797
819
  translateWithContext(word, explicitContext = null) {
798
- const lower = word.toLowerCase()
820
+ const lower = this.normalize(word)
799
821
  const ctx = explicitContext || this.getCurrentContext()
800
822
 
801
823
  if (this.conflicts[lower] && ctx) {
@@ -814,8 +836,12 @@ class JSGenerator {
814
836
  word
815
837
  }
816
838
 
817
- translate(word) {
818
- const lower = word.toLowerCase()
839
+ normalize(str) {
840
+ return str.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '')
841
+ }
842
+
843
+ translate(word, isMethod = false) {
844
+ const lower = this.normalize(word)
819
845
 
820
846
  if (this.keywordMap[lower]) {
821
847
  return this.keywordMap[lower]
@@ -823,13 +849,17 @@ class JSGenerator {
823
849
  if (this.operatorMap[lower]) {
824
850
  return this.operatorMap[lower]
825
851
  }
826
- if (this.methodMap[lower]) {
852
+ if (isMethod && this.methodMap[lower]) {
827
853
  return this.methodMap[lower]
828
854
  }
829
855
 
830
856
  return word
831
857
  }
832
858
 
859
+ translateMethod(word) {
860
+ return this.translate(word, true)
861
+ }
862
+
833
863
  translateOperator(op) {
834
864
  const lower = op.toLowerCase()
835
865
  return this.operatorMap[lower] || op
@@ -953,8 +983,10 @@ class JSGenerator {
953
983
  return this.generateSpreadElement(node)
954
984
  case 'RestElement':
955
985
  return this.generateRestElement(node)
986
+ case 'Parameter':
987
+ return this.generateParam(node)
956
988
  case 'Identifier':
957
- return this.translate(node.name)
989
+ return node.name
958
990
  case 'PrivateIdentifier':
959
991
  return this.generatePrivateIdentifier(node)
960
992
  case 'Literal':
@@ -1013,12 +1045,20 @@ class JSGenerator {
1013
1045
  }
1014
1046
  kind = kindTranslations[kind.toLowerCase()] || this.translate(kind)
1015
1047
 
1016
- const declarations = node.declarations || []
1017
-
1018
- for (const decl of declarations) {
1019
- const name = this.generateNode(decl.id || decl.name)
1020
- if (decl.init) {
1021
- const init = this.generateNode(decl.init)
1048
+ if (node.declarations && node.declarations.length > 0) {
1049
+ for (const decl of node.declarations) {
1050
+ const name = this.generateNode(decl.id || decl.name)
1051
+ if (decl.init) {
1052
+ const init = this.generateNode(decl.init)
1053
+ this.writeLine(`${kind} ${name} = ${init};`)
1054
+ } else {
1055
+ this.writeLine(`${kind} ${name};`)
1056
+ }
1057
+ }
1058
+ } else if (node.name) {
1059
+ const name = typeof node.name === 'string' ? node.name : this.generateNode(node.name)
1060
+ if (node.init) {
1061
+ const init = this.generateNode(node.init)
1022
1062
  this.writeLine(`${kind} ${name} = ${init};`)
1023
1063
  } else {
1024
1064
  this.writeLine(`${kind} ${name};`)
@@ -1029,8 +1069,8 @@ class JSGenerator {
1029
1069
  generateFunctionDeclaration(node) {
1030
1070
  const async = node.async ? 'async ' : ''
1031
1071
  const generator = node.generator ? '*' : ''
1032
- const name = node.id ? this.translate(node.id.name || node.id) : ''
1033
- const params = (node.params || []).map(p => this.generateNode(p)).join(', ')
1072
+ const name = node.name || (node.id ? (node.id.name || node.id) : '')
1073
+ const params = (node.params || []).map(p => this.generateParam(p)).join(', ')
1034
1074
 
1035
1075
  this.writeLine(`${async}function${generator} ${name}(${params}) {`)
1036
1076
  this.indent++
@@ -1043,8 +1083,8 @@ class JSGenerator {
1043
1083
  generateFunctionExpression(node) {
1044
1084
  const async = node.async ? 'async ' : ''
1045
1085
  const generator = node.generator ? '*' : ''
1046
- const name = node.id ? this.translate(node.id.name || node.id) : ''
1047
- const params = (node.params || []).map(p => this.generateNode(p)).join(', ')
1086
+ const name = node.name || (node.id ? (node.id.name || node.id) : '')
1087
+ const params = (node.params || []).map(p => this.generateParam(p)).join(', ')
1048
1088
 
1049
1089
  let body = ''
1050
1090
  const savedOutput = this.output
@@ -1058,6 +1098,26 @@ class JSGenerator {
1058
1098
  return `${async}function${generator} ${name}(${params}) {\n${body}\n${this.getIndent()}}`
1059
1099
  }
1060
1100
 
1101
+ generateParam(param) {
1102
+ if (!param) return ''
1103
+ if (typeof param === 'string') return param
1104
+ if (param.type === 'Identifier') return param.name
1105
+ if (param.type === 'Parameter') {
1106
+ let result = param.name
1107
+ if (param.default) {
1108
+ result += ' = ' + this.generateNode(param.default)
1109
+ }
1110
+ return result
1111
+ }
1112
+ if (param.type === 'RestElement') {
1113
+ return '...' + this.generateParam(param.argument)
1114
+ }
1115
+ if (param.type === 'AssignmentPattern') {
1116
+ return this.generateNode(param.left) + ' = ' + this.generateNode(param.right)
1117
+ }
1118
+ return param.name || this.generateNode(param)
1119
+ }
1120
+
1061
1121
  generateClassDeclaration(node) {
1062
1122
  const name = node.id ? (node.id.name || node.id) : ''
1063
1123
  const extend = node.superClass ? ` extends ${this.generateNode(node.superClass)}` : ''
@@ -1172,7 +1232,7 @@ class JSGenerator {
1172
1232
  }
1173
1233
 
1174
1234
  generateIfStatement(node) {
1175
- const test = this.generateNode(node.test)
1235
+ const test = this.generateNode(node.test || node.condition)
1176
1236
  this.writeLine(`if (${test}) {`)
1177
1237
  this.indent++
1178
1238
  this.generateNode(node.consequent)
@@ -1180,8 +1240,46 @@ class JSGenerator {
1180
1240
 
1181
1241
  if (node.alternate) {
1182
1242
  if (node.alternate.type === 'IfStatement') {
1183
- this.output = this.output.trimEnd() + ' else '
1184
- this.generateIfStatement(node.alternate)
1243
+ const altTest = this.generateNode(node.alternate.test || node.alternate.condition)
1244
+ this.writeLine(`} else if (${altTest}) {`)
1245
+ this.indent++
1246
+ this.generateNode(node.alternate.consequent)
1247
+ this.indent--
1248
+ if (node.alternate.alternate) {
1249
+ if (node.alternate.alternate.type === 'IfStatement') {
1250
+ this.generateElseIfChain(node.alternate.alternate)
1251
+ } else {
1252
+ this.writeLine('} else {')
1253
+ this.indent++
1254
+ this.generateNode(node.alternate.alternate)
1255
+ this.indent--
1256
+ this.writeLine('}')
1257
+ }
1258
+ } else {
1259
+ this.writeLine('}')
1260
+ }
1261
+ } else {
1262
+ this.writeLine('} else {')
1263
+ this.indent++
1264
+ this.generateNode(node.alternate)
1265
+ this.indent--
1266
+ this.writeLine('}')
1267
+ }
1268
+ } else {
1269
+ this.writeLine('}')
1270
+ }
1271
+ }
1272
+
1273
+ generateElseIfChain(node) {
1274
+ const test = this.generateNode(node.test || node.condition)
1275
+ this.writeLine(`} else if (${test}) {`)
1276
+ this.indent++
1277
+ this.generateNode(node.consequent)
1278
+ this.indent--
1279
+
1280
+ if (node.alternate) {
1281
+ if (node.alternate.type === 'IfStatement') {
1282
+ this.generateElseIfChain(node.alternate)
1185
1283
  } else {
1186
1284
  this.writeLine('} else {')
1187
1285
  this.indent++
@@ -1195,15 +1293,44 @@ class JSGenerator {
1195
1293
  }
1196
1294
 
1197
1295
  generateForStatement(node) {
1296
+ if (node.iterable || node.variable) {
1297
+ const varName = node.variable || 'item'
1298
+ const iterable = this.generateNode(node.iterable)
1299
+ this.writeLine(`for (const ${varName} of ${iterable}) {`)
1300
+ this.indent++
1301
+ this.generateNode(node.body)
1302
+ this.indent--
1303
+ this.writeLine('}')
1304
+ return
1305
+ }
1306
+
1307
+ if (node.start !== undefined && node.end !== undefined) {
1308
+ const varName = node.variable || 'i'
1309
+ const start = this.generateNode(node.start)
1310
+ const end = this.generateNode(node.end)
1311
+ const step = node.step ? this.generateNode(node.step) : '1'
1312
+ this.writeLine(`for (let ${varName} = ${start}; ${varName} < ${end}; ${varName} += ${step}) {`)
1313
+ this.indent++
1314
+ this.generateNode(node.body)
1315
+ this.indent--
1316
+ this.writeLine('}')
1317
+ return
1318
+ }
1319
+
1198
1320
  let init = ''
1199
1321
  if (node.init) {
1200
1322
  if (node.init.type === 'VariableDeclaration') {
1201
1323
  const kind = this.translate(node.init.kind || 'let')
1202
- const decls = node.init.declarations.map(d => {
1203
- const name = this.generateNode(d.id)
1204
- return d.init ? `${name} = ${this.generateNode(d.init)}` : name
1205
- }).join(', ')
1206
- init = `${kind} ${decls}`
1324
+ if (node.init.declarations && node.init.declarations.length > 0) {
1325
+ const decls = node.init.declarations.map(d => {
1326
+ const name = this.generateNode(d.id || d.name)
1327
+ return d.init ? `${name} = ${this.generateNode(d.init)}` : name
1328
+ }).join(', ')
1329
+ init = `${kind} ${decls}`
1330
+ } else if (node.init.name) {
1331
+ const name = node.init.name
1332
+ init = node.init.init ? `${kind} ${name} = ${this.generateNode(node.init.init)}` : `${kind} ${name}`
1333
+ }
1207
1334
  } else {
1208
1335
  init = this.generateNode(node.init)
1209
1336
  }
@@ -1221,14 +1348,26 @@ class JSGenerator {
1221
1348
  generateForOfStatement(node) {
1222
1349
  this.pushContext('loop')
1223
1350
  let left
1224
- if (node.left.type === 'VariableDeclaration') {
1225
- const kind = this.translate(node.left.kind || 'const')
1226
- const name = this.generateNode(node.left.declarations[0].id)
1227
- left = `${kind} ${name}`
1351
+ if (node.left) {
1352
+ if (node.left.type === 'VariableDeclaration') {
1353
+ const kind = this.translate(node.left.kind || 'const')
1354
+ if (node.left.declarations && node.left.declarations.length > 0) {
1355
+ const name = this.generateNode(node.left.declarations[0].id || node.left.declarations[0].name)
1356
+ left = `${kind} ${name}`
1357
+ } else if (node.left.name) {
1358
+ left = `${kind} ${node.left.name}`
1359
+ } else {
1360
+ left = `${kind} item`
1361
+ }
1362
+ } else {
1363
+ left = this.generateNode(node.left)
1364
+ }
1365
+ } else if (node.variable) {
1366
+ left = `const ${node.variable}`
1228
1367
  } else {
1229
- left = this.generateNode(node.left)
1368
+ left = 'const item'
1230
1369
  }
1231
- const right = this.generateNode(node.right)
1370
+ const right = this.generateNode(node.right || node.iterable)
1232
1371
 
1233
1372
  this.writeLine(`for (${left} of ${right}) {`)
1234
1373
  this.indent++
@@ -1241,14 +1380,26 @@ class JSGenerator {
1241
1380
  generateForInStatement(node) {
1242
1381
  this.pushContext('loop')
1243
1382
  let left
1244
- if (node.left.type === 'VariableDeclaration') {
1245
- const kind = this.translate(node.left.kind || 'const')
1246
- const name = this.generateNode(node.left.declarations[0].id)
1247
- left = `${kind} ${name}`
1383
+ if (node.left) {
1384
+ if (node.left.type === 'VariableDeclaration') {
1385
+ const kind = this.translate(node.left.kind || 'const')
1386
+ if (node.left.declarations && node.left.declarations.length > 0) {
1387
+ const name = this.generateNode(node.left.declarations[0].id || node.left.declarations[0].name)
1388
+ left = `${kind} ${name}`
1389
+ } else if (node.left.name) {
1390
+ left = `${kind} ${node.left.name}`
1391
+ } else {
1392
+ left = `${kind} key`
1393
+ }
1394
+ } else {
1395
+ left = this.generateNode(node.left)
1396
+ }
1397
+ } else if (node.variable) {
1398
+ left = `const ${node.variable}`
1248
1399
  } else {
1249
- left = this.generateNode(node.left)
1400
+ left = 'const key'
1250
1401
  }
1251
- const right = this.generateNode(node.right)
1402
+ const right = this.generateNode(node.right || node.iterable)
1252
1403
 
1253
1404
  this.writeLine(`for (${left} in ${right}) {`)
1254
1405
  this.indent++
@@ -1550,7 +1701,7 @@ class JSGenerator {
1550
1701
  return `${object}[${property}]`
1551
1702
  }
1552
1703
 
1553
- const translatedProperty = this.translate(property)
1704
+ const translatedProperty = this.translateMethod(property)
1554
1705
 
1555
1706
  if (translatedProperty.includes('.')) {
1556
1707
  const parts = translatedProperty.split('.')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ether-code",
3
- "version": "0.6.9",
3
+ "version": "0.7.1",
4
4
  "description": "Ether - Le langage intentionnel",
5
5
  "main": "cli/compiler.js",
6
6
  "bin": {