Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ResourceLoaderData
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 7
380
0.00% covered (danger)
0.00%
0 / 1
 getLocalData
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getContentLanguageMessages
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getTermsOfUseMessages
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getTermsOfUseMessagesParsed
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getTermsOfUseMessagesVersion
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 addOptionalDependencies
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 makeTestModule
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2/**
3 * Utilities for ResourceLoader modules used by DiscussionTools.
4 *
5 * @file
6 * @ingroup Extensions
7 * @license MIT
8 */
9
10namespace MediaWiki\Extension\DiscussionTools;
11
12use Config;
13use ExtensionRegistry;
14use MediaWiki\MediaWikiServices;
15use MediaWiki\ResourceLoader as RL;
16use MessageLocalizer;
17use Title;
18
19class ResourceLoaderData {
20    /**
21     * Used for the 'ext.discussionTools.init' module and the test module.
22     *
23     * We need all of this data *in content language*. Some of it is already available in JS, but only
24     * in client language, so it's useless for us (e.g. digit transform table, month name messages).
25     *
26     * @param RL\Context $context
27     * @param Config $config
28     * @param string|null $langCode
29     * @return array
30     */
31    public static function getLocalData(
32        RL\Context $context, Config $config, ?string $langCode = null
33    ): array {
34        $services = MediaWikiServices::getInstance();
35
36        if ( $langCode === null ) {
37            $langData = $services->getService( 'DiscussionTools.LanguageData' );
38        } else {
39            $langData = new LanguageData(
40                $services->getMainConfig(),
41                $services->getLanguageFactory()->getLanguage( $langCode ),
42                $services->getLanguageConverterFactory(),
43                $services->getSpecialPageFactory()
44            );
45        }
46
47        return $langData->getLocalData();
48    }
49
50    /**
51     * Return messages in content language, for use in a ResourceLoader module.
52     *
53     * @param RL\Context $context
54     * @param Config $config
55     * @param array $messagesKeys
56     * @return array
57     */
58    public static function getContentLanguageMessages(
59        RL\Context $context, Config $config, array $messagesKeys = []
60    ): array {
61        return array_combine(
62            $messagesKeys,
63            array_map( static function ( $key ) {
64                return wfMessage( $key )->inContentLanguage()->text();
65            }, $messagesKeys )
66        );
67    }
68
69    /**
70     * Return information about terms-of-use messages.
71     *
72     * @param MessageLocalizer $context
73     * @param Config $config
74     * @return array[] Map from internal name to array of parameters for MessageLocalizer::msg()
75     * @phan-return non-empty-array[]
76     */
77    private static function getTermsOfUseMessages(
78        MessageLocalizer $context, Config $config
79    ): array {
80        $messages = [
81            'reply' => [ 'discussiontools-replywidget-terms-click',
82                $context->msg( 'discussiontools-replywidget-reply' )->text() ],
83            'newtopic' => [ 'discussiontools-replywidget-terms-click',
84                $context->msg( 'discussiontools-replywidget-newtopic' )->text() ],
85        ];
86
87        $hookContainer = MediaWikiServices::getInstance()->getHookContainer();
88        $hookContainer->run( 'DiscussionToolsTermsOfUseMessages', [ &$messages, $context, $config ] );
89
90        return $messages;
91    }
92
93    /**
94     * Return parsed terms-of-use messages, for use in a ResourceLoader module.
95     *
96     * @param MessageLocalizer $context
97     * @param Config $config
98     * @return array
99     */
100    public static function getTermsOfUseMessagesParsed(
101        MessageLocalizer $context, Config $config
102    ): array {
103        $messages = static::getTermsOfUseMessages( $context, $config );
104        foreach ( $messages as &$msg ) {
105            $msg = $context->msg( ...$msg )->parse();
106        }
107        return $messages;
108    }
109
110    /**
111     * Return information about terms-of-use messages, for use in a ResourceLoader module as
112     * 'versionCallback'. This is to avoid calling the parser from version invalidation code.
113     *
114     * @param MessageLocalizer $context
115     * @param Config $config
116     * @return array
117     */
118    public static function getTermsOfUseMessagesVersion(
119        MessageLocalizer $context, Config $config
120    ): array {
121        $messages = static::getTermsOfUseMessages( $context, $config );
122        foreach ( $messages as &$msg ) {
123            $message = $context->msg( ...$msg );
124            $msg = [
125                // Include the text of the message, in case the canonical translation changes
126                $message->plain(),
127                // Include the page touched time, in case the on-wiki override is invalidated
128                Title::makeTitle( NS_MEDIAWIKI, ucfirst( $message->getKey() ) )->getTouched(),
129            ];
130        }
131        return $messages;
132    }
133
134    /**
135     * Add optional dependencies to a ResourceLoader module definition depending on loaded extensions.
136     *
137     * @param array $info
138     * @return RL\Module
139     */
140    public static function addOptionalDependencies( array $info ): RL\Module {
141        $extensionRegistry = ExtensionRegistry::getInstance();
142
143        foreach ( $info['optionalDependencies'] as $ext => $deps ) {
144            if ( $extensionRegistry->isLoaded( $ext ) ) {
145                $info['dependencies'] = array_merge( $info['dependencies'], (array)$deps );
146            }
147        }
148
149        $class = $info['class'] ?? RL\FileModule::class;
150        return new $class( $info );
151    }
152
153    /**
154     * Generate the test module that includes all of the test data, based on the JSON files defining
155     * test cases.
156     *
157     * @param array $info
158     * @return RL\Module
159     */
160    public static function makeTestModule( array $info ): RL\Module {
161        $keys = [ 'config', 'data', 'dom', 'expected' ];
162        foreach ( $info['testData'] as $path ) {
163            $info['packageFiles'][] = $path;
164            $localPath = $info['localBasePath'] . '/' . $path;
165            $data = json_decode( file_get_contents( $localPath ), true );
166            foreach ( $data as $case ) {
167                foreach ( $case as $key => $val ) {
168                    if ( in_array( $key, $keys ) && is_string( $val ) ) {
169                        if ( str_ends_with( $val, '.json' ) ) {
170                            $info['packageFiles'][] = substr( $val, strlen( '../' ) );
171                        } elseif ( str_ends_with( $val, '.html' ) ) {
172                            $info['packageFiles'][] = [
173                                'name' => $val,
174                                'type' => 'data',
175                                'callback' => static function () use ( $info, $val ) {
176                                    $localPath = $info['localBasePath'] . '/' . $val;
177                                    return file_get_contents( $localPath );
178                                },
179                                'versionCallback' => static function () use ( $val ) {
180                                    return new RL\FilePath( $val );
181                                },
182                            ];
183                        }
184                    }
185                }
186            }
187        }
188        $class = $info['class'] ?? RL\FileModule::class;
189        return new $class( $info );
190    }
191}