diff options
Diffstat (limited to 'www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php')
-rw-r--r-- | www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php new file mode 100644 index 00000000..794d3821 --- /dev/null +++ b/www/wiki/extensions/Scribunto/includes/engines/LuaCommon/TextLibrary.php @@ -0,0 +1,142 @@ +<?php + +// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps +class Scribunto_LuaTextLibrary extends Scribunto_LuaLibraryBase { + // Matches Lua mw.text constants + const JSON_PRESERVE_KEYS = 1; + const JSON_TRY_FIXING = 2; + const JSON_PRETTY = 4; + + function register() { + global $wgUrlProtocols; + + $lib = [ + 'unstrip' => [ $this, 'textUnstrip' ], + 'unstripNoWiki' => [ $this, 'textUnstripNoWiki' ], + 'killMarkers' => [ $this, 'killMarkers' ], + 'getEntityTable' => [ $this, 'getEntityTable' ], + 'jsonEncode' => [ $this, 'jsonEncode' ], + 'jsonDecode' => [ $this, 'jsonDecode' ], + ]; + $opts = [ + 'comma' => wfMessage( 'comma-separator' )->inContentLanguage()->text(), + 'and' => wfMessage( 'and' )->inContentLanguage()->text() . + wfMessage( 'word-separator' )->inContentLanguage()->text(), + 'ellipsis' => wfMessage( 'ellipsis' )->inContentLanguage()->text(), + 'nowiki_protocols' => [], + ]; + + foreach ( $wgUrlProtocols as $prot ) { + if ( substr( $prot, -1 ) === ':' ) { + // To convert the protocol into a case-insensitive Lua pattern, + // we need to replace letters with a character class like [Xx] + // and insert a '%' before various punctuation. + $prot = preg_replace_callback( '/([a-zA-Z])|([()^$%.\[\]*+?-])/', function ( $m ) { + if ( $m[1] ) { + return '[' . strtoupper( $m[1] ) . strtolower( $m[1] ) . ']'; + } else { + return '%' . $m[2]; + } + }, substr( $prot, 0, -1 ) ); + $opts['nowiki_protocols']["($prot):"] = '%1:'; + } + } + + return $this->getEngine()->registerInterface( 'mw.text.lua', $lib, $opts ); + } + + function textUnstrip( $s ) { + $this->checkType( 'unstrip', 1, $s, 'string' ); + $stripState = $this->getParser()->mStripState; + return [ $stripState->killMarkers( $stripState->unstripNoWiki( $s ) ) ]; + } + + function textUnstripNoWiki( $s ) { + $this->checkType( 'unstripNoWiki', 1, $s, 'string' ); + return [ $this->getParser()->mStripState->unstripNoWiki( $s ) ]; + } + + function killMarkers( $s ) { + $this->checkType( 'killMarkers', 1, $s, 'string' ); + return [ $this->getParser()->mStripState->killMarkers( $s ) ]; + } + + function getEntityTable() { + $table = array_flip( + get_html_translation_table( HTML_ENTITIES, ENT_QUOTES | ENT_HTML5, "UTF-8" ) + ); + return [ $table ]; + } + + public function jsonEncode( $value, $flags ) { + $this->checkTypeOptional( 'mw.text.jsonEncode', 2, $flags, 'number', 0 ); + $flags = (int)$flags; + if ( !( $flags & self::JSON_PRESERVE_KEYS ) && is_array( $value ) ) { + $value = self::reindexArrays( $value, true ); + } + $ret = FormatJson::encode( $value, (bool)( $flags & self::JSON_PRETTY ), FormatJson::ALL_OK ); + if ( $ret === false ) { + throw new Scribunto_LuaError( 'mw.text.jsonEncode: Unable to encode value' ); + } + return [ $ret ]; + } + + public function jsonDecode( $s, $flags ) { + $this->checkType( 'mw.text.jsonDecode', 1, $s, 'string' ); + $this->checkTypeOptional( 'mw.text.jsonDecode', 2, $flags, 'number', 0 ); + $flags = (int)$flags; + $opts = FormatJson::FORCE_ASSOC; + if ( $flags & self::JSON_TRY_FIXING ) { + $opts |= FormatJson::TRY_FIXING; + } + $status = FormatJson::parse( $s, $opts ); + if ( !$status->isOk() ) { + throw new Scribunto_LuaError( 'mw.text.jsonDecode: ' . $status->getMessage()->text() ); + } + $val = $status->getValue(); + if ( !( $flags & self::JSON_PRESERVE_KEYS ) && is_array( $val ) ) { + $val = self::reindexArrays( $val, false ); + } + return [ $val ]; + } + + /** Recursively reindex array with integer keys to 0-based or 1-based + * @param array $arr + * @param bool $isEncoding + * @return array + */ + private static function reindexArrays( array $arr, $isEncoding ) { + if ( $isEncoding ) { + ksort( $arr, SORT_NUMERIC ); + $next = 1; + } else { + $next = 0; + } + $isSequence = true; + foreach ( $arr as $k => &$v ) { + if ( is_array( $v ) ) { + $v = self::reindexArrays( $v, $isEncoding ); + } + + if ( $isSequence ) { + if ( is_int( $k ) ) { + $isSequence = $next++ === $k; + } elseif ( $isEncoding && ctype_digit( $k ) ) { + // json_decode currently doesn't return integer keys for {} + $isSequence = $next++ === (int)$k; + } else { + $isSequence = false; + } + } + } + if ( $isSequence ) { + if ( $isEncoding ) { + return array_values( $arr ); + } else { + return $arr ? array_combine( range( 1, count( $arr ) ), $arr ) : $arr; + } + } + return $arr; + } + +} |