locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
155 lines (154 loc) • 6.12 kB
JavaScript
import { getPhpObjectEntry } from "../_helpers/_phpRuntimeState.js";
import { toPhpArrayObject } from "../_helpers/_phpTypes.js";
import { echo } from "../strings/echo.js";
export function var_export(mixedExpression, boolReturn, idtLevel = 2) {
// discuss at: https://locutus.io/php/var_export/
// original by: Philip Peterson
// improved by: johnrembo
// improved by: Brett Zamir (https://brett-zamir.me)
// input by: Brian Tafoya (https://www.premasolutions.com/)
// input by: Hans Henrik (https://hanshenrik.tk/)
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: simivar (https://github.com/simivar)
// bugfixed by: simivar (https://github.com/simivar)
// bugfixed by: simivar (https://github.com/simivar)
// example 1: var_export(null)
// returns 1: null
// example 2: var_export({0: 'Kevin', 1: 'van', 2: 'Zonneveld'}, true)
// returns 2: "array (\n 0 => 'Kevin',\n 1 => 'van',\n 2 => 'Zonneveld',\n)"
// example 3: var data = 'Kevin'
// example 3: var_export(data, true)
// returns 3: "'Kevin'"
// example 4: var_export({0: 'Kevin', 1: 'van', 'lastName': 'Zonneveld'}, true)
// returns 4: "array (\n 0 => 'Kevin',\n 1 => 'van',\n 'lastName' => 'Zonneveld',\n)"
// example 5: var_export([], true)
// returns 5: "array (\n)"
// example 6: var_export({ test: [ 'a', 'b' ] }, true)
// returns 6: "array (\n 'test' => \n array (\n 0 => 'a',\n 1 => 'b',\n ),\n)"
let retstr = '';
let iret = '';
let value = '';
let cnt = 0;
const x = [];
// We use the last argument (not part of PHP) to pass in
// our indentation level
let innerIndent = '';
let outerIndent = '';
const getFuncName = function (fn) {
const name = /\W*function\s+([\w$]+)\s*\(/.exec(fn.toString());
if (!name) {
return '(Anonymous)';
}
return name[1] ?? '(Anonymous)';
};
const _isNormalInteger = function (input) {
const number = Math.floor(Number(input));
return number !== Infinity && String(number) === input && number >= 0;
};
const _makeIndent = function (indentLevel) {
return new Array(Math.max(indentLevel, 0) + 1).join(' ');
};
const __getType = function (inp) {
let i = 0;
let match = null;
let cons = '';
const types = ['boolean', 'number', 'string', 'array'];
const jsType = typeof inp;
let type = jsType === 'boolean' ||
jsType === 'number' ||
jsType === 'string' ||
jsType === 'function' ||
jsType === 'undefined' ||
jsType === 'object'
? jsType
: null;
if (type === 'object' && typeof inp === 'object' && inp !== null) {
const constructorValue = getPhpObjectEntry(inp, 'constructor');
if (typeof constructorValue === 'function' && getFuncName(constructorValue) === 'LOCUTUS_Resource') {
return 'resource';
}
}
if (type === 'function') {
return 'function';
}
if (type === 'object' && !inp) {
// Should this be just null?
return 'null';
}
if (type === 'object' && typeof inp === 'object' && inp !== null) {
const constructorValue = getPhpObjectEntry(inp, 'constructor');
if (typeof constructorValue !== 'function') {
return 'object';
}
cons = constructorValue.toString();
match = cons.match(/(\w+)\(/);
if (match) {
cons = (match[1] ?? '').toLowerCase();
}
for (i = 0; i < types.length; i++) {
const knownType = types[i];
if (knownType && cons === knownType) {
type = knownType;
break;
}
}
}
return type;
};
const type = __getType(mixedExpression);
if (type === null) {
retstr = 'NULL';
}
else if (type === 'array' || type === 'object') {
const source = toPhpArrayObject(mixedExpression);
outerIndent = _makeIndent(idtLevel - 2);
innerIndent = _makeIndent(idtLevel);
for (const [key, entry] of Object.entries(source)) {
value = ' ';
const subtype = __getType(entry);
if (subtype === 'array' || subtype === 'object' || subtype === 'function') {
value = ' \n';
}
value += String(var_export(entry, true, idtLevel + 2));
const mappedKey = _isNormalInteger(key) ? key : `'${key}'`;
x[cnt++] = innerIndent + mappedKey + ' =>' + value;
}
if (x.length > 0) {
iret = x.join(',\n') + ',\n';
}
retstr = outerIndent + 'array (\n' + iret + outerIndent + ')';
}
else if (type === 'function') {
// PHP deprecated create_function() in 7.2 and removed it in 8.0.
// On our PHP 8.3 parity target, closures export as \Closure::__set_state(array()).
outerIndent = _makeIndent(idtLevel - 2);
retstr = outerIndent + '\\Closure::__set_state(array(\n' + outerIndent + '))';
}
else if (type === 'resource') {
// Resources treated as null for var_export
retstr = 'NULL';
}
else {
if (typeof mixedExpression === 'string') {
retstr = "'" + mixedExpression.replace(/([\\'])/g, '\\$1').replace(/\0/g, '\\0') + "'";
}
else if (mixedExpression === null) {
retstr = null;
}
else if (typeof mixedExpression === 'number') {
retstr = Number(mixedExpression);
}
else if (typeof mixedExpression === 'boolean') {
retstr = Boolean(mixedExpression);
}
else {
retstr = String(mixedExpression);
}
}
if (!boolReturn) {
echo(retstr);
return null;
}
return retstr;
}