ether-code 0.8.2 → 0.8.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.
- package/cli/ether.js +1 -1
- package/generators/php-generator.js +59 -21
- package/package.json +1 -1
- package/parsers/ether-parser-php.js +81 -15
- package/parsers/ether-parser.js +15 -5
package/cli/ether.js
CHANGED
|
@@ -101,6 +101,8 @@ class PHPGenerator {
|
|
|
101
101
|
|
|
102
102
|
const generators = {
|
|
103
103
|
'Program': () => this.generateProgram(node),
|
|
104
|
+
'DeclareStatement': () => this.generateDeclareStatement(node),
|
|
105
|
+
'NamespaceDeclaration': () => this.generateNamespaceDeclaration(node),
|
|
104
106
|
'FunctionDeclaration': () => this.generateFunctionDeclaration(node),
|
|
105
107
|
'ClassDeclaration': () => this.generateClassDeclaration(node),
|
|
106
108
|
'InterfaceDeclaration': () => this.generateInterfaceDeclaration(node),
|
|
@@ -110,6 +112,7 @@ class PHPGenerator {
|
|
|
110
112
|
'PropertyDeclaration': () => this.generatePropertyDeclaration(node),
|
|
111
113
|
'VariableDeclaration': () => this.generateVariableDeclaration(node),
|
|
112
114
|
'ConstantDeclaration': () => this.generateConstantDeclaration(node),
|
|
115
|
+
'DefineDeclaration': () => this.generateDefineDeclaration(node),
|
|
113
116
|
'IfStatement': () => this.generateIfStatement(node),
|
|
114
117
|
'ForStatement': () => this.generateForStatement(node),
|
|
115
118
|
'ForEachStatement': () => this.generateForEachStatement(node),
|
|
@@ -176,6 +179,33 @@ class PHPGenerator {
|
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
181
|
|
|
182
|
+
generateDeclareStatement(node) {
|
|
183
|
+
const directives = (node.directives || []).map(d => {
|
|
184
|
+
const name = this.safeString(d.name)
|
|
185
|
+
const value = this.generateNode(d.value)
|
|
186
|
+
return `${name}=${value}`
|
|
187
|
+
}).join(', ')
|
|
188
|
+
|
|
189
|
+
this.writeLine(`declare(${directives});`)
|
|
190
|
+
this.writeLine('')
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
generateNamespaceDeclaration(node) {
|
|
194
|
+
const name = this.safeString(node.name)
|
|
195
|
+
this.writeLine(`namespace ${name};`)
|
|
196
|
+
this.writeLine('')
|
|
197
|
+
|
|
198
|
+
if (node.body) {
|
|
199
|
+
this.generateNode(node.body)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
generateDefineDeclaration(node) {
|
|
204
|
+
const name = this.safeString(node.name)
|
|
205
|
+
const value = this.generateNode(node.value)
|
|
206
|
+
this.writeLine(`define('${name}', ${value});`)
|
|
207
|
+
}
|
|
208
|
+
|
|
179
209
|
generateFunctionDeclaration(node) {
|
|
180
210
|
const name = this.safeString(node.name || node.id?.name || 'anonymous')
|
|
181
211
|
const translatedName = this.translate(name)
|
|
@@ -465,7 +495,7 @@ class PHPGenerator {
|
|
|
465
495
|
generateVariableDeclaration(node) {
|
|
466
496
|
for (const decl of node.declarations || [node]) {
|
|
467
497
|
const name = this.safeString(decl.name || decl.id?.name || decl.id)
|
|
468
|
-
const varName = '$' +
|
|
498
|
+
const varName = '$' + name
|
|
469
499
|
|
|
470
500
|
if (decl.init !== undefined) {
|
|
471
501
|
const value = this.generateNode(decl.init)
|
|
@@ -640,7 +670,8 @@ class PHPGenerator {
|
|
|
640
670
|
}
|
|
641
671
|
|
|
642
672
|
generateEchoStatement(node) {
|
|
643
|
-
const
|
|
673
|
+
const exprs = node.expressions || node.arguments || [node.argument]
|
|
674
|
+
const args = exprs.filter(Boolean).map(a => this.generateNode(a)).join(', ')
|
|
644
675
|
this.writeLine(`echo ${args};`)
|
|
645
676
|
}
|
|
646
677
|
|
|
@@ -656,10 +687,19 @@ class PHPGenerator {
|
|
|
656
687
|
}
|
|
657
688
|
|
|
658
689
|
generateUseStatement(node) {
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
690
|
+
const typePrefix = node.useType === 'function' ? 'function ' : (node.useType === 'const' ? 'const ' : '')
|
|
691
|
+
|
|
692
|
+
if (node.imports && node.imports.length > 0) {
|
|
693
|
+
for (const imp of node.imports) {
|
|
694
|
+
const path = this.safeString(imp.path)
|
|
695
|
+
const alias = imp.alias ? ' as ' + imp.alias : ''
|
|
696
|
+
this.writeLine(`use ${typePrefix}${path}${alias};`)
|
|
697
|
+
}
|
|
698
|
+
} else {
|
|
699
|
+
const name = this.safeString(node.name || node.source)
|
|
700
|
+
const alias = node.alias ? ' as ' + node.alias : ''
|
|
701
|
+
this.writeLine(`use ${typePrefix}${name}${alias};`)
|
|
702
|
+
}
|
|
663
703
|
}
|
|
664
704
|
|
|
665
705
|
generateIncludeStatement(node) {
|
|
@@ -878,43 +918,41 @@ class PHPGenerator {
|
|
|
878
918
|
if (!node) return '$var'
|
|
879
919
|
|
|
880
920
|
const name = this.safeString(node.name || node.id?.name || node)
|
|
881
|
-
const
|
|
882
|
-
const translatedStr = String(translated)
|
|
921
|
+
const nameStr = String(name)
|
|
883
922
|
|
|
884
|
-
if (
|
|
885
|
-
return '$' +
|
|
923
|
+
if (nameStr.startsWith('$')) return nameStr
|
|
924
|
+
return '$' + nameStr
|
|
886
925
|
}
|
|
887
926
|
|
|
888
927
|
generateIdentifier(node) {
|
|
889
928
|
if (!node) return '$var'
|
|
890
929
|
|
|
891
930
|
const name = this.safeString(node.name || node.id?.name || node)
|
|
892
|
-
const
|
|
893
|
-
const translatedStr = String(translated)
|
|
931
|
+
const nameStr = String(name)
|
|
894
932
|
|
|
895
|
-
if (
|
|
933
|
+
if (nameStr.startsWith('$')) return nameStr
|
|
896
934
|
|
|
897
935
|
const keywords = [
|
|
898
936
|
'true', 'false', 'null',
|
|
899
937
|
'self', 'parent', 'static',
|
|
900
938
|
'this', '$this'
|
|
901
939
|
]
|
|
902
|
-
if (keywords.includes(
|
|
903
|
-
if (
|
|
904
|
-
return
|
|
940
|
+
if (keywords.includes(nameStr.toLowerCase())) {
|
|
941
|
+
if (nameStr.toLowerCase() === 'this') return '$this'
|
|
942
|
+
return nameStr
|
|
905
943
|
}
|
|
906
944
|
|
|
907
|
-
if (/^[A-Z]/.test(
|
|
945
|
+
if (/^[A-Z]/.test(nameStr)) return nameStr
|
|
908
946
|
|
|
909
|
-
if (
|
|
947
|
+
if (nameStr.includes('(') || nameStr.includes('::')) return nameStr
|
|
910
948
|
|
|
911
949
|
const superglobals = ['_GET', '_POST', '_SERVER', '_SESSION', '_COOKIE', '_FILES', '_REQUEST', '_ENV', 'GLOBALS']
|
|
912
|
-
const upper =
|
|
913
|
-
if (superglobals.includes(
|
|
950
|
+
const upper = nameStr.toUpperCase()
|
|
951
|
+
if (superglobals.includes(nameStr) || superglobals.includes(upper)) {
|
|
914
952
|
return '$' + upper
|
|
915
953
|
}
|
|
916
954
|
|
|
917
|
-
return '$' +
|
|
955
|
+
return '$' + nameStr
|
|
918
956
|
}
|
|
919
957
|
|
|
920
958
|
generateLiteral(node) {
|
package/package.json
CHANGED
|
@@ -226,6 +226,12 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
226
226
|
this.phpModifiers = ['statique', 'static', 'final', 'finale', 'abstrait', 'abstraite', 'abstract', 'readonly', 'lecture seule']
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
safeStr(val) {
|
|
230
|
+
if (typeof val === 'string') return val
|
|
231
|
+
if (val && typeof val === 'object') return String(val.name || val.value || '')
|
|
232
|
+
return String(val || '')
|
|
233
|
+
}
|
|
234
|
+
|
|
229
235
|
translatePHP(word) {
|
|
230
236
|
if (!word) return word
|
|
231
237
|
const lower = this.normalizeAccents(String(word))
|
|
@@ -272,6 +278,10 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
272
278
|
|
|
273
279
|
const value = token.value != null ? this.normalizeAccents(String(token.value).toLowerCase()) : ''
|
|
274
280
|
|
|
281
|
+
if (this.isDeclare(value)) {
|
|
282
|
+
return this.parseDeclare(lang)
|
|
283
|
+
}
|
|
284
|
+
|
|
275
285
|
if (this.isNamespace(value)) {
|
|
276
286
|
return this.parseNamespace(lang)
|
|
277
287
|
}
|
|
@@ -365,7 +375,17 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
365
375
|
}
|
|
366
376
|
|
|
367
377
|
isNamespace(value) {
|
|
368
|
-
|
|
378
|
+
if (value === 'namespace') return true
|
|
379
|
+
if (value === 'espace') {
|
|
380
|
+
const next1 = this.peek(1)
|
|
381
|
+
const next2 = this.peek(2)
|
|
382
|
+
if (next1 && next2) {
|
|
383
|
+
const val1 = this.normalizeAccents(String(next1.value).toLowerCase())
|
|
384
|
+
const val2 = this.normalizeAccents(String(next2.value).toLowerCase())
|
|
385
|
+
if (val1 === 'de' && val2 === 'noms') return true
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return false
|
|
369
389
|
}
|
|
370
390
|
|
|
371
391
|
isUse(value) {
|
|
@@ -463,8 +483,54 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
463
483
|
return value === 'match'
|
|
464
484
|
}
|
|
465
485
|
|
|
466
|
-
|
|
486
|
+
isDeclare(value) {
|
|
487
|
+
return ['declare', 'declarer', 'déclarer'].includes(value)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
parseDeclare(lang) {
|
|
467
491
|
this.advance()
|
|
492
|
+
|
|
493
|
+
const directives = []
|
|
494
|
+
|
|
495
|
+
if (this.match(TokenType.LPAREN)) {
|
|
496
|
+
do {
|
|
497
|
+
const nameToken = this.current()
|
|
498
|
+
const name = nameToken ? this.safeStr(nameToken.value) : ''
|
|
499
|
+
this.advance()
|
|
500
|
+
|
|
501
|
+
this.match(TokenType.EQUALS)
|
|
502
|
+
|
|
503
|
+
const value = this.parseExpression(lang)
|
|
504
|
+
directives.push({ name, value })
|
|
505
|
+
} while (this.match(TokenType.COMMA))
|
|
506
|
+
|
|
507
|
+
this.match(TokenType.RPAREN)
|
|
508
|
+
} else {
|
|
509
|
+
const nameToken = this.current()
|
|
510
|
+
const name = nameToken ? this.safeStr(nameToken.value) : ''
|
|
511
|
+
this.advance()
|
|
512
|
+
|
|
513
|
+
this.match(TokenType.EQUALS)
|
|
514
|
+
|
|
515
|
+
const value = this.parseExpression(lang)
|
|
516
|
+
directives.push({ name, value })
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return {
|
|
520
|
+
type: 'DeclareStatement',
|
|
521
|
+
directives: directives
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
parseNamespace(lang) {
|
|
526
|
+
const first = this.advance()
|
|
527
|
+
const firstVal = this.normalizeAccents(String(first.value).toLowerCase())
|
|
528
|
+
|
|
529
|
+
if (firstVal === 'espace') {
|
|
530
|
+
this.advance()
|
|
531
|
+
this.advance()
|
|
532
|
+
}
|
|
533
|
+
|
|
468
534
|
const name = this.parseNamespacePath(lang)
|
|
469
535
|
this.skipNewlines()
|
|
470
536
|
|
|
@@ -736,7 +802,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
736
802
|
}
|
|
737
803
|
|
|
738
804
|
const nameToken = this.current()
|
|
739
|
-
let name = nameToken ? nameToken.value : 'property'
|
|
805
|
+
let name = this.safeStr(nameToken ? nameToken.value : 'property')
|
|
740
806
|
|
|
741
807
|
if (name.startsWith('$')) {
|
|
742
808
|
name = name.substring(1)
|
|
@@ -1047,7 +1113,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1047
1113
|
}
|
|
1048
1114
|
|
|
1049
1115
|
const varToken = this.current()
|
|
1050
|
-
let varName = varToken ? varToken.value : ''
|
|
1116
|
+
let varName = this.safeStr(varToken ? varToken.value : '')
|
|
1051
1117
|
if (varName.startsWith('$')) {
|
|
1052
1118
|
varName = varName.substring(1)
|
|
1053
1119
|
}
|
|
@@ -1126,7 +1192,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1126
1192
|
const nameToken = this.current()
|
|
1127
1193
|
if (!nameToken) return null
|
|
1128
1194
|
|
|
1129
|
-
let name = nameToken.value
|
|
1195
|
+
let name = this.safeStr(nameToken.value)
|
|
1130
1196
|
if (name.startsWith('$')) {
|
|
1131
1197
|
name = name.substring(1)
|
|
1132
1198
|
}
|
|
@@ -1218,7 +1284,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1218
1284
|
}
|
|
1219
1285
|
|
|
1220
1286
|
const nameToken = this.current()
|
|
1221
|
-
let name = nameToken ? nameToken.value : 'variable'
|
|
1287
|
+
let name = this.safeStr(nameToken ? nameToken.value : 'variable')
|
|
1222
1288
|
if (name.startsWith('$')) {
|
|
1223
1289
|
name = name.substring(1)
|
|
1224
1290
|
}
|
|
@@ -1372,7 +1438,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1372
1438
|
}
|
|
1373
1439
|
|
|
1374
1440
|
const firstVar = this.current()
|
|
1375
|
-
let firstName = firstVar ? firstVar.value : 'item'
|
|
1441
|
+
let firstName = this.safeStr(firstVar ? firstVar.value : 'item')
|
|
1376
1442
|
if (firstName.startsWith('$')) firstName = firstName.substring(1)
|
|
1377
1443
|
this.advance()
|
|
1378
1444
|
|
|
@@ -1384,7 +1450,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1384
1450
|
}
|
|
1385
1451
|
|
|
1386
1452
|
const valueVar = this.current()
|
|
1387
|
-
value = valueVar ? valueVar.value : 'value'
|
|
1453
|
+
let value = this.safeStr(valueVar ? valueVar.value : 'value')
|
|
1388
1454
|
if (value.startsWith('$')) value = value.substring(1)
|
|
1389
1455
|
this.advance()
|
|
1390
1456
|
} else {
|
|
@@ -1632,7 +1698,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1632
1698
|
do {
|
|
1633
1699
|
const typeToken = this.current()
|
|
1634
1700
|
if (typeToken && typeToken.type === TokenType.IDENTIFIER) {
|
|
1635
|
-
const typeName = typeToken.value
|
|
1701
|
+
const typeName = this.safeStr(typeToken.value)
|
|
1636
1702
|
if (typeName.startsWith('$')) {
|
|
1637
1703
|
param = typeName.substring(1)
|
|
1638
1704
|
} else {
|
|
@@ -1645,7 +1711,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1645
1711
|
if (!param) {
|
|
1646
1712
|
const paramToken = this.current()
|
|
1647
1713
|
if (paramToken && paramToken.type === TokenType.IDENTIFIER) {
|
|
1648
|
-
param = paramToken.value
|
|
1714
|
+
param = this.safeStr(paramToken.value)
|
|
1649
1715
|
if (param.startsWith('$')) param = param.substring(1)
|
|
1650
1716
|
this.advance()
|
|
1651
1717
|
}
|
|
@@ -1759,7 +1825,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
1759
1825
|
const variables = []
|
|
1760
1826
|
do {
|
|
1761
1827
|
const varToken = this.current()
|
|
1762
|
-
let varName = varToken ? varToken.value : ''
|
|
1828
|
+
let varName = this.safeStr(varToken ? varToken.value : '')
|
|
1763
1829
|
if (varName.startsWith('$')) varName = varName.substring(1)
|
|
1764
1830
|
this.advance()
|
|
1765
1831
|
variables.push(varName)
|
|
@@ -2209,11 +2275,11 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
2209
2275
|
|
|
2210
2276
|
if (token.type === TokenType.STRING) {
|
|
2211
2277
|
this.advance()
|
|
2212
|
-
let value = token.value
|
|
2278
|
+
let value = this.safeStr(token.value)
|
|
2213
2279
|
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
2214
2280
|
value = value.slice(1, -1)
|
|
2215
2281
|
}
|
|
2216
|
-
const isDouble = token.value.startsWith('"')
|
|
2282
|
+
const isDouble = value.startsWith('"') || this.safeStr(token.value).startsWith('"')
|
|
2217
2283
|
return { type: 'StringLiteral', value, doubleQuoted: isDouble }
|
|
2218
2284
|
}
|
|
2219
2285
|
|
|
@@ -2223,7 +2289,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
2223
2289
|
}
|
|
2224
2290
|
|
|
2225
2291
|
if (token.type === TokenType.IDENTIFIER) {
|
|
2226
|
-
const value = token.value
|
|
2292
|
+
const value = this.safeStr(token.value)
|
|
2227
2293
|
const valueLower = this.normalizeAccents(value.toLowerCase())
|
|
2228
2294
|
|
|
2229
2295
|
if (valueLower === 'vrai' || valueLower === 'true') {
|
|
@@ -2285,7 +2351,7 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
2285
2351
|
|
|
2286
2352
|
if (token.type === TokenType.VARIABLE) {
|
|
2287
2353
|
this.advance()
|
|
2288
|
-
let name = token.value
|
|
2354
|
+
let name = this.safeStr(token.value)
|
|
2289
2355
|
if (name.startsWith('$')) name = name.substring(1)
|
|
2290
2356
|
return { type: 'Variable', name }
|
|
2291
2357
|
}
|
package/parsers/ether-parser.js
CHANGED
|
@@ -30,13 +30,23 @@ class EtherParser {
|
|
|
30
30
|
if (!this.parsers[lang]) {
|
|
31
31
|
switch (lang) {
|
|
32
32
|
case 'js':
|
|
33
|
+
this.parsers[lang] = new EtherParserJS(this.options)
|
|
34
|
+
break
|
|
33
35
|
case 'ts':
|
|
36
|
+
this.parsers[lang] = new EtherParserJS(this.options)
|
|
37
|
+
break
|
|
34
38
|
case 'react':
|
|
39
|
+
this.parsers[lang] = new EtherParserJS(this.options)
|
|
40
|
+
break
|
|
35
41
|
case 'node':
|
|
42
|
+
this.parsers[lang] = new EtherParserJS(this.options)
|
|
43
|
+
break
|
|
36
44
|
case 'php':
|
|
37
45
|
this.parsers[lang] = new EtherParserPHP(this.options)
|
|
38
46
|
break
|
|
39
47
|
case 'python':
|
|
48
|
+
this.parsers[lang] = new EtherParserJS(this.options)
|
|
49
|
+
break
|
|
40
50
|
case 'ruby':
|
|
41
51
|
this.parsers[lang] = new EtherParserJS(this.options)
|
|
42
52
|
break
|
|
@@ -53,15 +63,13 @@ class EtherParser {
|
|
|
53
63
|
this.parsers[lang] = new EtherParserGraphQL(this.options)
|
|
54
64
|
break
|
|
55
65
|
default:
|
|
56
|
-
this.parsers[lang] = new
|
|
66
|
+
this.parsers[lang] = new EtherParserHTML(this.options)
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
69
|
return this.parsers[lang]
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
detectTargetLanguage(source) {
|
|
63
|
-
const lower = source.toLowerCase()
|
|
64
|
-
|
|
65
73
|
const targetMatch = source.match(/\/\/\s*cible\s*:\s*(\w+)/i)
|
|
66
74
|
if (targetMatch) {
|
|
67
75
|
const target = targetMatch[1].toLowerCase()
|
|
@@ -83,6 +91,8 @@ class EtherParser {
|
|
|
83
91
|
}
|
|
84
92
|
}
|
|
85
93
|
|
|
94
|
+
const lower = source.toLowerCase()
|
|
95
|
+
|
|
86
96
|
if (/^\s*(document|page|<!doctype|<html|tete|corps|entete|navigation|section|article)/m.test(lower)) {
|
|
87
97
|
return 'html'
|
|
88
98
|
}
|
|
@@ -133,7 +143,7 @@ class EtherParser {
|
|
|
133
143
|
return 'js'
|
|
134
144
|
}
|
|
135
145
|
|
|
136
|
-
return '
|
|
146
|
+
return 'html'
|
|
137
147
|
}
|
|
138
148
|
|
|
139
149
|
parse(source, targetLang = null) {
|
|
@@ -145,4 +155,4 @@ class EtherParser {
|
|
|
145
155
|
}
|
|
146
156
|
}
|
|
147
157
|
|
|
148
|
-
module.exports = { EtherParser, TokenType }
|
|
158
|
+
module.exports = { EtherParser, TokenType }
|