Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.27% covered (success)
93.27%
97 / 104
92.31% covered (success)
92.31%
12 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZType
93.27% covered (success)
93.27%
97 / 104
92.31% covered (success)
92.31%
12 / 13
34.35
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 getDefinition
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
1
 isValid
74.07% covered (warning)
74.07%
20 / 27
0.00% covered (danger)
0.00%
0 / 1
17.42
 getTypeId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTypeKeys
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTypeValidator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEqualityFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getRendererFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getParserFunction
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getDeserialisers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSerialisers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isEnumType
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getZKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * WikiLambda ZType
4 *
5 * @file
6 * @ingroup Extensions
7 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
8 * @license MIT
9 */
10
11namespace MediaWiki\Extension\WikiLambda\ZObjects;
12
13use MediaWiki\Extension\WikiLambda\Registry\ZTypeRegistry;
14
15class ZType extends ZObject {
16
17    /**
18     * Construct a ZType instance given the identity ZReference, a ZTypedList of ZKeys,
19     * and a ZReference to the type validator
20     *
21     * @param ZObject $identity
22     * @param ZObject $keys
23     * @param ZObject $validator
24     * @param ?ZObject $equality
25     * @param ?ZObject $renderer
26     * @param ?ZObject $parser
27     * @param ?ZTypedList $deserialisers
28     * @param ?ZTypedList $serialisers
29     */
30    public function __construct(
31        $identity, $keys, $validator,
32        ?ZObject $equality = null,
33        ?ZObject $renderer = null, ?ZObject $parser = null,
34        ?ZTypedList $deserialisers = null, ?ZTypedList $serialisers = null
35    ) {
36        $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ] = $identity;
37        $this->data[ ZTypeRegistry::Z_TYPE_KEYS ] = $keys;
38        $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ] = $validator;
39        $this->data[ ZTypeRegistry::Z_TYPE_EQUALITY ] = $equality ?? false;
40        $this->data[ ZTypeRegistry::Z_TYPE_RENDERER ] = $renderer ?? false;
41        $this->data[ ZTypeRegistry::Z_TYPE_PARSER ] = $parser ?? false;
42        $this->data[ ZTypeRegistry::Z_TYPE_DESERIALISERS ] = $deserialisers ??
43            new ZTypedList( ZTypedList::buildType( new ZReference( ZTypeRegistry::Z_DESERIALISER ) )
44        );
45        $this->data[ ZTypeRegistry::Z_TYPE_SERIALISERS ] = $serialisers ??
46            new ZTypedList( ZTypedList::buildType( new ZReference( ZTypeRegistry::Z_SERIALISER ) )
47        );
48    }
49
50    /**
51     * @inheritDoc
52     */
53    public static function getDefinition(): array {
54        return [
55            'type' => [
56                'type' => ZTypeRegistry::Z_REFERENCE,
57                'value' => ZTypeRegistry::Z_TYPE,
58            ],
59            'keys' => [
60                ZTypeRegistry::Z_TYPE_IDENTITY => [
61                    // NOTE: Allows Z0.
62                    'type' => ZTypeRegistry::BUILTIN_REFERENCE_NULLABLE,
63                ],
64                ZTypeRegistry::Z_TYPE_KEYS => [
65                    // TODO (T362257): Walk the array of ZKeys.
66                    'type' => ZTypeRegistry::HACK_ARRAY_Z_KEY,
67                    'required' => true,
68                ],
69                ZTypeRegistry::Z_TYPE_VALIDATOR => [
70                    // NOTE: Allows Z0 until we support ZFunctions.
71                    'type' => ZTypeRegistry::BUILTIN_REFERENCE_NULLABLE,
72                ],
73                ZTypeRegistry::Z_TYPE_EQUALITY => [
74                    'type' => ZTypeRegistry::Z_FUNCTION,
75                    'required' => false,
76                ],
77                ZTypeRegistry::Z_TYPE_RENDERER => [
78                    'type' => ZTypeRegistry::Z_FUNCTION,
79                    'required' => false,
80                ],
81                ZTypeRegistry::Z_TYPE_PARSER => [
82                    'type' => ZTypeRegistry::Z_FUNCTION,
83                    'required' => false,
84                ],
85                ZTypeRegistry::Z_TYPE_DESERIALISERS => [
86                    'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST,
87                    'required' => false,
88                ],
89                ZTypeRegistry::Z_TYPE_SERIALISERS => [
90                    'type' => ZTypeRegistry::Z_FUNCTION_TYPED_LIST,
91                    'required' => false,
92                ],
93            ],
94        ];
95    }
96
97    /**
98     * @inheritDoc
99     */
100    public function isValid(): bool {
101        // Identity must be set to a valid ZReference (or special case of 'Z0')
102        if ( !isset( $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ] ) ) {
103            return false;
104        }
105        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ] instanceof ZReference ) ) {
106            return false;
107        }
108        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ]->isValid() ) ) {
109            return false;
110        }
111
112        // Key map must be set to an array or ZTypedList of zero or more ZKeys, all valid
113        if ( !isset( $this->data[ ZTypeRegistry::Z_TYPE_KEYS ] ) ) {
114            return false;
115        }
116        $keys = $this->data[ ZTypeRegistry::Z_TYPE_KEYS ];
117        if ( !is_array( $keys ) ) {
118            if ( $keys instanceof ZTypedList ) {
119                if ( $keys->getElementType()->getZValue() !== ZTypeRegistry::Z_KEY ) {
120                    return false;
121                }
122                $keys = $keys->getAsArray();
123            } else {
124                return false;
125            }
126        }
127        foreach ( $keys as $key ) {
128            if ( !( $key instanceof ZKey ) ) {
129                return false;
130            }
131            if ( !$key->isValid() ) {
132                return false;
133            }
134        }
135
136        // Validator must be set to a valid ZKey reference
137        if ( !isset( $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ] ) ) {
138            return false;
139        }
140        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ] instanceof ZReference ) ) {
141            return false;
142        }
143        if ( !( $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ]->isValid() ) ) {
144            return false;
145        }
146        // TODO (T362242): Actually check that the validator is a ZFunction that applies to us.
147
148        // TODO (T362243): Check the equality, renderer, parser, and type converter keys.
149
150        return true;
151    }
152
153    /**
154     * Get the representation of th ZType Zid
155     *
156     * @return ZReference|ZFunctionCall
157     */
158    public function getTypeId() {
159        return $this->data[ ZTypeRegistry::Z_TYPE_IDENTITY ];
160    }
161
162    /**
163     * Get a list with the set of ZKeys for this ZType
164     *
165     * @return ZTypedList
166     */
167    public function getTypeKeys() {
168        return $this->data[ ZTypeRegistry::Z_TYPE_KEYS ];
169    }
170
171    /**
172     * Get the string representation of the ZReference to this ZType's validator function
173     *
174     * @return string
175     */
176    public function getTypeValidator() {
177        return $this->data[ ZTypeRegistry::Z_TYPE_VALIDATOR ]->getZValue();
178    }
179
180    /**
181     * Get the string representation of the ZReference to this ZType's equality function,
182     * or false if there is none.
183     *
184     * @return string|false
185     */
186    public function getEqualityFunction() {
187        return $this->data[ ZTypeRegistry::Z_TYPE_EQUALITY ] ?
188            $this->data[ ZTypeRegistry::Z_TYPE_EQUALITY ]->getZValue() :
189            false;
190    }
191
192    /**
193     * Get the string representation of the ZReference to this ZType's rendering function,
194     * or false if there is none.
195     *
196     * @return string|false
197     */
198    public function getRendererFunction() {
199        return $this->data[ ZTypeRegistry::Z_TYPE_RENDERER ] ?
200            $this->data[ ZTypeRegistry::Z_TYPE_RENDERER ]->getZValue() :
201            false;
202    }
203
204    /**
205     * Get the string representation of the ZReference to this ZType's parsing function,
206     * or false if there is none.
207     *
208     * @return string|false
209     */
210    public function getParserFunction() {
211        return $this->data[ ZTypeRegistry::Z_TYPE_PARSER ] ?
212            $this->data[ ZTypeRegistry::Z_TYPE_PARSER ]->getZValue() :
213            false;
214    }
215
216    /**
217     * Get the ZList of this ZType's deserialisers
218     *
219     * @return ZTypedList
220     */
221    public function getDeserialisers() {
222        return $this->data[ ZTypeRegistry::Z_TYPE_DESERIALISERS ];
223    }
224
225    /**
226     * Get the ZList of this ZType's serialisers
227     *
228     * @return ZTypedList
229     */
230    public function getSerialisers() {
231        return $this->data[ ZTypeRegistry::Z_TYPE_SERIALISERS ];
232    }
233
234    /**
235     * Return whether the type has an identity key but is not
236     * one of the non-enum reserved types with identity key:
237     * * Type/Z4
238     * * Function/Z8
239     * * Deserialiser/Z46
240     * * Serialiser/Z64
241     *
242     * @return bool
243     */
244    public function isEnumType() {
245        $typeId = $this->getTypeId()->getZValue();
246
247        if ( in_array( $typeId, ZTypeRegistry::EXCLUDE_TYPES_FROM_ENUMS ) ) {
248            // Type has identity key but excluded from enum; return false
249            return false;
250        }
251
252        $keys = $this->getTypeKeys()->getAsArray();
253        foreach ( $keys as $key ) {
254            if ( $key->getIsIdentity() ) {
255                return true;
256            }
257        }
258        return false;
259    }
260
261    /**
262     * Get the ZKey of a given key reference from the set of ZKeys of this ZType or
263     * null if the ZKey is not available.
264     *
265     * @param string $key
266     * @return ZKey|null
267     */
268    public function getZKey( $key ) {
269        $keys = $this->getTypeKeys()->getAsArray();
270        foreach ( $keys as $zkey ) {
271            if ( $zkey->getKeyId() === $key ) {
272                return $zkey;
273            }
274        }
275        return null;
276    }
277}