ether-code 0.9.4 → 0.9.6
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 +203 -32
- package/package.json +1 -1
- package/parsers/ether-parser-php.js +0 -1
package/cli/ether.js
CHANGED
|
@@ -134,7 +134,6 @@ class PHPGenerator {
|
|
|
134
134
|
'formater nombre': 'number_format',
|
|
135
135
|
'date': 'date',
|
|
136
136
|
'temps': 'time',
|
|
137
|
-
'maintenant': 'time',
|
|
138
137
|
'creer date': 'mktime',
|
|
139
138
|
'date vers temps': 'strtotime',
|
|
140
139
|
'formater date': 'date_format',
|
|
@@ -305,23 +304,60 @@ class PHPGenerator {
|
|
|
305
304
|
return this.keywordMap[normalized] || word
|
|
306
305
|
}
|
|
307
306
|
|
|
307
|
+
translateMethodName(word) {
|
|
308
|
+
if (!word) return word
|
|
309
|
+
const normalized = this.normalizeAccents(word)
|
|
310
|
+
const magicMethods = {
|
|
311
|
+
'constructeur': '__construct',
|
|
312
|
+
'destructeur': '__destruct',
|
|
313
|
+
'obtenir': '__get',
|
|
314
|
+
'definir': '__set',
|
|
315
|
+
'appeler': '__call',
|
|
316
|
+
'vers chaine': '__toString',
|
|
317
|
+
'invoquer': '__invoke',
|
|
318
|
+
'cloner': '__clone',
|
|
319
|
+
'serialiser': '__serialize',
|
|
320
|
+
'deserialiser': '__unserialize',
|
|
321
|
+
'deboguer': '__debugInfo'
|
|
322
|
+
}
|
|
323
|
+
return magicMethods[normalized] || word
|
|
324
|
+
}
|
|
325
|
+
|
|
308
326
|
extractTypeName(typeNode) {
|
|
309
327
|
if (!typeNode) return ''
|
|
310
|
-
if (typeof typeNode === 'string')
|
|
328
|
+
if (typeof typeNode === 'string') {
|
|
329
|
+
const translated = this.translateKeyword(typeNode)
|
|
330
|
+
return this.prefixGlobalClass(translated)
|
|
331
|
+
}
|
|
311
332
|
if (typeNode.type === 'TypeHint') {
|
|
312
|
-
const types = (typeNode.types || []).map(t =>
|
|
333
|
+
const types = (typeNode.types || []).map(t => {
|
|
334
|
+
const translated = this.translateKeyword(t)
|
|
335
|
+
return this.prefixGlobalClass(translated)
|
|
336
|
+
})
|
|
313
337
|
const result = types.join('|')
|
|
314
338
|
return typeNode.nullable ? '?' + result : result
|
|
315
339
|
}
|
|
316
|
-
if (typeNode.name)
|
|
317
|
-
|
|
318
|
-
|
|
340
|
+
if (typeNode.name) {
|
|
341
|
+
const translated = this.translateKeyword(typeNode.name)
|
|
342
|
+
return this.prefixGlobalClass(translated)
|
|
343
|
+
}
|
|
344
|
+
if (typeNode.type === 'Identifier') {
|
|
345
|
+
const translated = this.translateKeyword(typeNode.name || typeNode.value || '')
|
|
346
|
+
return this.prefixGlobalClass(translated)
|
|
347
|
+
}
|
|
348
|
+
if (typeNode.value) {
|
|
349
|
+
const translated = this.translateKeyword(typeNode.value)
|
|
350
|
+
return this.prefixGlobalClass(translated)
|
|
351
|
+
}
|
|
319
352
|
return ''
|
|
320
353
|
}
|
|
321
354
|
|
|
322
355
|
generate(ast) {
|
|
323
356
|
this.output = ''
|
|
324
357
|
this.indent = 0
|
|
358
|
+
this.closureVariables = new Set()
|
|
359
|
+
|
|
360
|
+
this.collectClosureVariables(ast)
|
|
325
361
|
|
|
326
362
|
if (ast.phpTag !== false) {
|
|
327
363
|
this.output = '<?php\n'
|
|
@@ -346,6 +382,32 @@ class PHPGenerator {
|
|
|
346
382
|
return this.output.trim()
|
|
347
383
|
}
|
|
348
384
|
|
|
385
|
+
collectClosureVariables(ast) {
|
|
386
|
+
const nodes = Array.isArray(ast) ? ast : (ast?.body || [ast])
|
|
387
|
+
|
|
388
|
+
for (const node of nodes) {
|
|
389
|
+
if (!node) continue
|
|
390
|
+
|
|
391
|
+
if (node.type === 'VariableDeclaration') {
|
|
392
|
+
const init = node.init || node.value
|
|
393
|
+
if (init && (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression' || init.type === 'ClosureExpression')) {
|
|
394
|
+
const name = node.name || node.id?.name
|
|
395
|
+
if (name) this.closureVariables.add(name)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (node.body) {
|
|
400
|
+
this.collectClosureVariables(node.body)
|
|
401
|
+
}
|
|
402
|
+
if (node.consequent) {
|
|
403
|
+
this.collectClosureVariables(Array.isArray(node.consequent) ? node.consequent : [node.consequent])
|
|
404
|
+
}
|
|
405
|
+
if (node.alternate) {
|
|
406
|
+
this.collectClosureVariables(Array.isArray(node.alternate) ? node.alternate : [node.alternate])
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
349
411
|
generateNode(node) {
|
|
350
412
|
if (!node) return ''
|
|
351
413
|
|
|
@@ -381,6 +443,8 @@ class PHPGenerator {
|
|
|
381
443
|
return this.generateForStatement(node)
|
|
382
444
|
case 'ForEachStatement':
|
|
383
445
|
return this.generateForEachStatement(node)
|
|
446
|
+
case 'ForeachStatement':
|
|
447
|
+
return this.generateForEachStatement(node)
|
|
384
448
|
case 'WhileStatement':
|
|
385
449
|
return this.generateWhileStatement(node)
|
|
386
450
|
case 'DoWhileStatement':
|
|
@@ -615,7 +679,7 @@ class PHPGenerator {
|
|
|
615
679
|
generateClassMember(node) {
|
|
616
680
|
if (!node) return
|
|
617
681
|
|
|
618
|
-
if (node.type === 'UseTraitStatement') {
|
|
682
|
+
if (node.type === 'UseTraitStatement' || node.type === 'TraitUse') {
|
|
619
683
|
this.writeLine(`use ${node.traits.join(', ')};`)
|
|
620
684
|
return
|
|
621
685
|
}
|
|
@@ -634,7 +698,7 @@ class PHPGenerator {
|
|
|
634
698
|
this.writeLine(`${visibility} ${isStatic}${isReadonly}${typeHint}${name}${value};`)
|
|
635
699
|
} else if (node.type === 'Method' || node.kind === 'method' || node.type === 'MethodDeclaration') {
|
|
636
700
|
const name = node.name || node.key?.name || ''
|
|
637
|
-
const translatedName = this.
|
|
701
|
+
const translatedName = this.translateMethodName(name)
|
|
638
702
|
const params = (node.params || []).map(p => this.generateParam(p)).join(', ')
|
|
639
703
|
let returnType = ''
|
|
640
704
|
|
|
@@ -688,7 +752,7 @@ class PHPGenerator {
|
|
|
688
752
|
|
|
689
753
|
const visibility = 'public'
|
|
690
754
|
const name = node.name || node.key?.name || ''
|
|
691
|
-
const translatedName = this.
|
|
755
|
+
const translatedName = this.translateMethodName(name)
|
|
692
756
|
const params = (node.params || []).map(p => this.generateParam(p)).join(', ')
|
|
693
757
|
let returnType = ''
|
|
694
758
|
|
|
@@ -871,21 +935,26 @@ class PHPGenerator {
|
|
|
871
935
|
this.generateBody(node.block)
|
|
872
936
|
this.indent--
|
|
873
937
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const
|
|
877
|
-
|
|
938
|
+
const catches = node.catches || (node.handler ? [node.handler] : [])
|
|
939
|
+
for (const catchClause of catches) {
|
|
940
|
+
const types = catchClause.types || []
|
|
941
|
+
let exceptionType = types.length > 0
|
|
942
|
+
? types.map(t => this.prefixGlobalClass(t)).join('|')
|
|
943
|
+
: this.prefixGlobalClass(catchClause.exceptionType || catchClause.type || 'Exception')
|
|
944
|
+
const param = catchClause.param
|
|
945
|
+
? this.generateVariable(catchClause.param)
|
|
878
946
|
: '$e'
|
|
879
947
|
this.writeLine(`} catch (${exceptionType} ${param}) {`)
|
|
880
948
|
this.indent++
|
|
881
|
-
this.generateBody(
|
|
949
|
+
this.generateBody(catchClause.body)
|
|
882
950
|
this.indent--
|
|
883
951
|
}
|
|
884
952
|
|
|
885
|
-
|
|
953
|
+
const finallyBlock = node.finally || node.finalizer
|
|
954
|
+
if (finallyBlock) {
|
|
886
955
|
this.writeLine('} finally {')
|
|
887
956
|
this.indent++
|
|
888
|
-
this.generateBody(
|
|
957
|
+
this.generateBody(finallyBlock)
|
|
889
958
|
this.indent--
|
|
890
959
|
}
|
|
891
960
|
|
|
@@ -893,6 +962,31 @@ class PHPGenerator {
|
|
|
893
962
|
return ''
|
|
894
963
|
}
|
|
895
964
|
|
|
965
|
+
prefixGlobalClass(name) {
|
|
966
|
+
const phpGlobalClasses = [
|
|
967
|
+
'Exception', 'Error', 'TypeError', 'ValueError', 'ArgumentCountError',
|
|
968
|
+
'ArithmeticError', 'DivisionByZeroError', 'ParseError', 'AssertionError',
|
|
969
|
+
'CompileError', 'UnhandledMatchError', 'FiberError',
|
|
970
|
+
'ErrorException', 'BadFunctionCallException', 'BadMethodCallException',
|
|
971
|
+
'DomainException', 'InvalidArgumentException', 'LengthException',
|
|
972
|
+
'LogicException', 'OutOfBoundsException', 'OutOfRangeException',
|
|
973
|
+
'OverflowException', 'RangeException', 'RuntimeException',
|
|
974
|
+
'UnderflowException', 'UnexpectedValueException',
|
|
975
|
+
'PDOException', 'JsonException', 'IntlException',
|
|
976
|
+
'Generator', 'Iterator', 'IteratorAggregate', 'Traversable',
|
|
977
|
+
'ArrayAccess', 'Countable', 'Serializable', 'Stringable',
|
|
978
|
+
'DateTime', 'DateTimeImmutable', 'DateTimeInterface', 'DateInterval', 'DatePeriod',
|
|
979
|
+
'PDO', 'PDOStatement', 'Closure', 'stdClass', 'WeakReference', 'WeakMap',
|
|
980
|
+
'SplFileInfo', 'SplFileObject', 'SplTempFileObject',
|
|
981
|
+
'ArrayObject', 'ArrayIterator', 'RecursiveArrayIterator',
|
|
982
|
+
'Fiber', 'ReflectionClass', 'ReflectionMethod', 'ReflectionProperty'
|
|
983
|
+
]
|
|
984
|
+
if (phpGlobalClasses.includes(name) && !name.startsWith('\\')) {
|
|
985
|
+
return '\\' + name
|
|
986
|
+
}
|
|
987
|
+
return name
|
|
988
|
+
}
|
|
989
|
+
|
|
896
990
|
generateReturnStatement(node) {
|
|
897
991
|
if (node.argument) {
|
|
898
992
|
const arg = this.generateNode(node.argument)
|
|
@@ -932,19 +1026,82 @@ class PHPGenerator {
|
|
|
932
1026
|
|
|
933
1027
|
generateCallExpression(node) {
|
|
934
1028
|
let callee
|
|
1029
|
+
let originalName = ''
|
|
935
1030
|
|
|
936
1031
|
if (typeof node.callee === 'string') {
|
|
937
|
-
|
|
1032
|
+
originalName = node.callee
|
|
1033
|
+
if (this.closureVariables && this.closureVariables.has(node.callee)) {
|
|
1034
|
+
callee = '$' + node.callee
|
|
1035
|
+
} else {
|
|
1036
|
+
callee = this.translateFunction(node.callee)
|
|
1037
|
+
}
|
|
938
1038
|
} else if (node.callee.type === 'Identifier') {
|
|
939
|
-
|
|
1039
|
+
originalName = node.callee.name
|
|
1040
|
+
if (this.closureVariables && this.closureVariables.has(node.callee.name)) {
|
|
1041
|
+
callee = '$' + node.callee.name
|
|
1042
|
+
} else {
|
|
1043
|
+
callee = this.translateFunction(node.callee.name)
|
|
1044
|
+
}
|
|
1045
|
+
} else if (node.callee.type === 'Variable') {
|
|
1046
|
+
callee = this.generateVariable(node.callee)
|
|
940
1047
|
} else if (node.callee.type === 'MemberExpression' || node.callee.type === 'StaticMemberExpression') {
|
|
941
1048
|
callee = this.generateNode(node.callee)
|
|
942
1049
|
} else {
|
|
943
1050
|
callee = this.generateNode(node.callee)
|
|
944
1051
|
}
|
|
945
1052
|
|
|
946
|
-
|
|
947
|
-
|
|
1053
|
+
let args = (node.arguments || []).map(a => this.generateNode(a))
|
|
1054
|
+
|
|
1055
|
+
args = this.reorderArguments(callee, args, originalName)
|
|
1056
|
+
args = this.addDefaultArguments(callee, args)
|
|
1057
|
+
|
|
1058
|
+
return `${callee}(${args.join(', ')})`
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
reorderArguments(func, args, originalName) {
|
|
1062
|
+
const normalized = this.normalizeAccents(originalName)
|
|
1063
|
+
|
|
1064
|
+
if ((func === 'str_replace' || normalized === 'remplacer') && args.length === 3) {
|
|
1065
|
+
return [args[1], args[2], args[0]]
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
if ((func === 'array_map' || normalized === 'mapper' || normalized === 'mapper tableau' || normalized === 'transformer') && args.length === 2) {
|
|
1069
|
+
return [args[1], args[0]]
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return args
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
addDefaultArguments(func, args) {
|
|
1076
|
+
if (func === 'password_hash' && args.length === 1) {
|
|
1077
|
+
return [...args, 'PASSWORD_DEFAULT']
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
return args
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
isNativeFunction(name) {
|
|
1084
|
+
const natives = [
|
|
1085
|
+
'echo', 'print', 'var_dump', 'print_r', 'die', 'exit',
|
|
1086
|
+
'strlen', 'substr', 'strpos', 'str_replace', 'strtoupper', 'strtolower',
|
|
1087
|
+
'trim', 'ltrim', 'rtrim', 'explode', 'implode', 'sprintf', 'printf',
|
|
1088
|
+
'count', 'array_push', 'array_pop', 'array_shift', 'array_unshift',
|
|
1089
|
+
'array_merge', 'array_filter', 'array_map', 'array_reduce', 'array_keys',
|
|
1090
|
+
'array_values', 'array_sum', 'array_unique', 'array_reverse', 'sort',
|
|
1091
|
+
'in_array', 'array_key_exists', 'array_search',
|
|
1092
|
+
'is_array', 'is_string', 'is_int', 'is_float', 'is_bool', 'is_null',
|
|
1093
|
+
'is_numeric', 'is_object', 'is_callable', 'isset', 'empty', 'gettype',
|
|
1094
|
+
'intval', 'floatval', 'strval', 'boolval', 'settype',
|
|
1095
|
+
'abs', 'ceil', 'floor', 'round', 'sqrt', 'pow', 'rand', 'max', 'min', 'pi',
|
|
1096
|
+
'date', 'time', 'strtotime', 'mktime',
|
|
1097
|
+
'file_exists', 'file_get_contents', 'file_put_contents', 'fopen', 'fclose', 'fread', 'fwrite',
|
|
1098
|
+
'json_encode', 'json_decode', 'preg_match', 'preg_match_all', 'preg_replace',
|
|
1099
|
+
'header', 'session_start', 'session_destroy', 'password_hash', 'password_verify',
|
|
1100
|
+
'include', 'include_once', 'require', 'require_once',
|
|
1101
|
+
'class_exists', 'function_exists', 'method_exists', 'defined', 'define', 'constant',
|
|
1102
|
+
'new', 'throw'
|
|
1103
|
+
]
|
|
1104
|
+
return natives.includes(name)
|
|
948
1105
|
}
|
|
949
1106
|
|
|
950
1107
|
generateMemberExpression(node) {
|
|
@@ -952,9 +1109,9 @@ class PHPGenerator {
|
|
|
952
1109
|
let property
|
|
953
1110
|
|
|
954
1111
|
if (typeof node.property === 'string') {
|
|
955
|
-
property = node.property
|
|
1112
|
+
property = this.translateMemberProperty(node.property)
|
|
956
1113
|
} else if (node.property.type === 'Identifier') {
|
|
957
|
-
property = this.
|
|
1114
|
+
property = this.translateMemberProperty(node.property.name)
|
|
958
1115
|
} else {
|
|
959
1116
|
property = this.generateNode(node.property)
|
|
960
1117
|
}
|
|
@@ -967,6 +1124,26 @@ class PHPGenerator {
|
|
|
967
1124
|
return `${object}${operator}${property}`
|
|
968
1125
|
}
|
|
969
1126
|
|
|
1127
|
+
translateMemberProperty(name) {
|
|
1128
|
+
const translations = {
|
|
1129
|
+
'valeur': 'value',
|
|
1130
|
+
'nom': 'name',
|
|
1131
|
+
'message': 'message',
|
|
1132
|
+
'code': 'code',
|
|
1133
|
+
'fichier': 'file',
|
|
1134
|
+
'ligne': 'line',
|
|
1135
|
+
'precedent': 'previous',
|
|
1136
|
+
'trace': 'trace',
|
|
1137
|
+
'formater': 'format',
|
|
1138
|
+
'ajouter': 'add',
|
|
1139
|
+
'modifier': 'modify',
|
|
1140
|
+
'obtenir': 'get',
|
|
1141
|
+
'definir': 'set'
|
|
1142
|
+
}
|
|
1143
|
+
const normalized = this.normalizeAccents(name)
|
|
1144
|
+
return translations[normalized] || name
|
|
1145
|
+
}
|
|
1146
|
+
|
|
970
1147
|
generateStaticMemberExpression(node) {
|
|
971
1148
|
const cls = node.class?.name || this.generateNode(node.class)
|
|
972
1149
|
let member = node.member?.name || this.generateNode(node.member)
|
|
@@ -1060,12 +1237,6 @@ class PHPGenerator {
|
|
|
1060
1237
|
const name = node.name || node
|
|
1061
1238
|
if (typeof name !== 'string') return '$var'
|
|
1062
1239
|
|
|
1063
|
-
const normalized = this.normalizeAccents(name)
|
|
1064
|
-
|
|
1065
|
-
if (this.functionMap[normalized]) {
|
|
1066
|
-
return this.functionMap[normalized]
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
1240
|
const translated = this.translateKeyword(name)
|
|
1070
1241
|
|
|
1071
1242
|
if (translated.startsWith('$')) return translated
|
|
@@ -1073,11 +1244,11 @@ class PHPGenerator {
|
|
|
1073
1244
|
return translated
|
|
1074
1245
|
}
|
|
1075
1246
|
if (/^[A-Z]/.test(translated)) return translated
|
|
1076
|
-
if (
|
|
1247
|
+
if (!name.startsWith('$')) {
|
|
1077
1248
|
return '$' + name
|
|
1078
1249
|
}
|
|
1079
1250
|
|
|
1080
|
-
return
|
|
1251
|
+
return name
|
|
1081
1252
|
}
|
|
1082
1253
|
|
|
1083
1254
|
generateVariable(node) {
|
|
@@ -1110,9 +1281,9 @@ class PHPGenerator {
|
|
|
1110
1281
|
generateNewExpression(node) {
|
|
1111
1282
|
let callee
|
|
1112
1283
|
if (typeof node.callee === 'string') {
|
|
1113
|
-
callee = node.callee
|
|
1284
|
+
callee = this.prefixGlobalClass(node.callee)
|
|
1114
1285
|
} else if (node.callee.type === 'Identifier') {
|
|
1115
|
-
callee = node.callee.name
|
|
1286
|
+
callee = this.prefixGlobalClass(node.callee.name)
|
|
1116
1287
|
} else {
|
|
1117
1288
|
callee = this.generateNode(node.callee)
|
|
1118
1289
|
}
|
package/package.json
CHANGED
|
@@ -159,7 +159,6 @@ class EtherParserPHP extends EtherParserBase {
|
|
|
159
159
|
'json decoder': 'json_decode',
|
|
160
160
|
'date': 'date',
|
|
161
161
|
'temps': 'time',
|
|
162
|
-
'maintenant': 'time',
|
|
163
162
|
'demarrer session': 'session_start',
|
|
164
163
|
'detruire session': 'session_destroy',
|
|
165
164
|
'definir cookie': 'setcookie',
|