aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-15 20:07:54 +0900
committernsfisis <nsfisis@gmail.com>2026-05-16 10:00:39 +0900
commit0716a8d2496bbfd4a7e6de503fc7e336b0aee66f (patch)
treebf75e9a258199d33824e40282561844c03775fc1
parent4b4bacdbced5c4af5bfbb2b5a2615b1c3d73c038 (diff)
downloadphp-shirabe-0716a8d2496bbfd4a7e6de503fc7e336b0aee66f.tar.gz
php-shirabe-0716a8d2496bbfd4a7e6de503fc7e336b0aee66f.tar.zst
php-shirabe-0716a8d2496bbfd4a7e6de503fc7e336b0aee66f.zip
feat(port): port JsonFormatter.php
-rw-r--r--crates/shirabe-php-shim/src/lib.rs8
-rw-r--r--crates/shirabe/src/json/json_formatter.rs106
2 files changed, 114 insertions, 0 deletions
diff --git a/crates/shirabe-php-shim/src/lib.rs b/crates/shirabe-php-shim/src/lib.rs
index 56bfcc4..e85f665 100644
--- a/crates/shirabe-php-shim/src/lib.rs
+++ b/crates/shirabe-php-shim/src/lib.rs
@@ -390,6 +390,14 @@ pub fn class_exists(name: &str) -> bool {
todo!()
}
+pub fn function_exists(name: &str) -> bool {
+ todo!()
+}
+
+pub fn mb_convert_encoding(string: Vec<u8>, to_encoding: &str, from_encoding: &str) -> String {
+ todo!()
+}
+
pub fn touch(path: &str) -> bool {
todo!()
}
diff --git a/crates/shirabe/src/json/json_formatter.rs b/crates/shirabe/src/json/json_formatter.rs
index 3d4d79c..a88bfff 100644
--- a/crates/shirabe/src/json/json_formatter.rs
+++ b/crates/shirabe/src/json/json_formatter.rs
@@ -1 +1,107 @@
//! ref: composer/src/Composer/Json/JsonFormatter.php
+
+use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_php_shim::{function_exists, mb_convert_encoding, pack, PhpMixed};
+
+pub struct JsonFormatter;
+
+impl JsonFormatter {
+ /**
+ * This code is based on the function found at:
+ * http://recursive-design.com/blog/2008/03/11/format-json-with-php/
+ *
+ * Originally licensed under MIT by Dave Perrett <mail@recursive-design.com>
+ */
+ pub fn format(json: String, unescape_unicode: bool, unescape_slashes: bool) -> String {
+ let mut result = String::new();
+ let mut pos: usize = 0;
+ let indent_str = " ";
+ let new_line = "\n";
+ let mut out_of_quotes = true;
+ let mut buffer = String::new();
+ let mut noescape = true;
+
+ let chars: Vec<char> = json.chars().collect();
+ let str_len = chars.len();
+
+ for i in 0..str_len {
+ let char_ = chars[i];
+
+ if char_ == '"' && noescape {
+ out_of_quotes = !out_of_quotes;
+ }
+
+ if !out_of_quotes {
+ buffer.push(char_);
+ noescape = if char_ == '\\' { !noescape } else { true };
+ continue;
+ }
+ if !buffer.is_empty() {
+ if unescape_slashes {
+ buffer = buffer.replace("\\/", "/");
+ }
+
+ if unescape_unicode && function_exists("mb_convert_encoding") {
+ buffer = Preg::replace_callback(
+ r"/(\\+)u([0-9a-f]{4})/i",
+ |matches: &[String]| -> String {
+ let l = matches[1].len();
+
+ if l % 2 != 0 {
+ let code = i64::from_str_radix(&matches[2], 16).unwrap_or(0);
+ if code >= 0xD800 && code <= 0xDFFF {
+ return matches[0].clone();
+ }
+
+ return "\\".repeat(l - 1)
+ + &mb_convert_encoding(
+ pack("H*", &[PhpMixed::String(matches[2].clone())]),
+ "UTF-8",
+ "UCS-2BE",
+ );
+ }
+
+ matches[0].clone()
+ },
+ &buffer,
+ );
+ }
+
+ result.push_str(&buffer);
+ result.push(char_);
+ buffer = String::new();
+ continue;
+ }
+
+ let mut char_str = char_.to_string();
+
+ if char_ == ':' {
+ char_str.push(' ');
+ } else if char_ == '}' || char_ == ']' {
+ pos -= 1;
+ let prev_char = if i > 0 { chars[i - 1] } else { '\0' };
+
+ if prev_char != '{' && prev_char != '[' {
+ result.push_str(new_line);
+ result.push_str(&indent_str.repeat(pos));
+ } else {
+ result = result.trim_end().to_string();
+ }
+ }
+
+ result.push_str(&char_str);
+
+ if char_ == ',' || char_ == '{' || char_ == '[' {
+ result.push_str(new_line);
+
+ if char_ == '{' || char_ == '[' {
+ pos += 1;
+ }
+
+ result.push_str(&indent_str.repeat(pos));
+ }
+ }
+
+ result
+ }
+}