Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
KV
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 6
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 lookupKV
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
 lookup
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 keyOffset
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 valueOffset
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 jsonSerialize
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2// phpcs:disable MediaWiki.Commenting.FunctionComment.DefaultNullTypeParam -- T218324, T218816
3declare( strict_types = 1 );
4
5namespace Wikimedia\Parsoid\Tokens;
6
7/**
8 * Represents a Key-value pair.
9 */
10class KV implements \JsonSerializable {
11    /**
12     * Commonly a string, but where the key might be templated,
13     * this can be an array of tokens even.
14     *
15     * @var string|Token|array<Token|string>
16     */
17    public $k;
18
19    /** @var string|Token|array<Token|string>|KV[] */
20    public $v;
21
22    /** Wikitext source offsets */
23    public ?KVSourceRange $srcOffsets;
24
25    /** Wikitext source */
26    public ?string $ksrc;
27
28    /** Wikitext source */
29    public ?string $vsrc;
30
31    /**
32     * @param string|Token|array<Token|string> $k
33     *     Commonly a string, but where the key might be templated,
34     *     this can be an array of tokens even.
35     * @param string|Token|array<Token|string>|KV[] $v
36     *     The value: string, token, of an array of tokens
37     * @param ?KVSourceRange $srcOffsets wikitext source offsets
38     * @param ?string $ksrc
39     * @param ?string $vsrc
40     */
41    public function __construct(
42        $k, $v, ?KVSourceRange $srcOffsets = null, ?string $ksrc = null,
43        ?string $vsrc = null
44    ) {
45        $this->k = $k;
46        $this->v = $v;
47        $this->srcOffsets = $srcOffsets;
48        $this->ksrc = $ksrc;
49        $this->vsrc = $vsrc;
50    }
51
52    /**
53     * BUG: When there are multiple matching attributes, Sanitizer lets the last one win
54     * whereas this method is letting the first one win. This can introduce subtle bugs!
55     *
56     * Lookup a string key in a KV array and return the first matching KV object
57     *
58     * @param KV[]|null $kvs
59     * @param string $key
60     * @return ?KV
61     */
62    public static function lookupKV( ?array $kvs, string $key ): ?KV {
63        if ( $kvs === null ) {
64            return null;
65        }
66
67        foreach ( $kvs as $kv ) {
68            // PORT-FIXME: JS trim() will remove non-ASCII spaces (such as NBSP) too,
69            // while PHP's won't. Does that matter?
70            if ( is_string( $kv->k ) && trim( $kv->k ) === $key ) {
71                return $kv;
72            }
73        }
74
75        return null;
76    }
77
78    /**
79     * Lookup a string key (first occurrence) in a KV array
80     * and return the value of the KV object
81     *
82     * @param KV[]|null $kvs
83     * @param string $key
84     * @return string|Token|array<Token|string>|null
85     */
86    public static function lookup( ?array $kvs, string $key ) {
87        $kv = self::lookupKV( $kvs, $key );
88        // PORT_FIXME: Potential bug lurking here ... if $kv->v is an array
89        // this will return a copy, which if modified will not reflect
90        // in the original KV object.
91        return $kv->v ?? null;
92    }
93
94    /**
95     * Return the key portion of the KV's source offsets, or else null
96     * if no source offsets are known.
97     * @return SourceRange|null
98     */
99    public function keyOffset(): ?SourceRange {
100        // @phan-suppress-next-line PhanCoalescingNeverNull $this->srcOffsets is nullable
101        return $this->srcOffsets->key ?? null;
102    }
103
104    /**
105     * Return the value portion of the KV's source offsets, or else null
106     * if no source offsets are known.
107     * @return SourceRange|null
108     */
109    public function valueOffset(): ?SourceRange {
110        // @phan-suppress-next-line PhanCoalescingNeverNull $this->srcOffsets is nullable
111        return $this->srcOffsets->value ?? null;
112    }
113
114    /**
115     * @inheritDoc
116     */
117    public function jsonSerialize(): array {
118        $ret = [ "k" => $this->k, "v" => $this->v ];
119        if ( $this->srcOffsets ) {
120            $ret["srcOffsets"] = $this->srcOffsets;
121        }
122        if ( isset( $this->ksrc ) ) {
123            $ret["ksrc"] = $this->ksrc;
124        }
125        if ( isset( $this->vsrc ) ) {
126            $ret["vsrc"] = $this->vsrc;
127        }
128        return $ret;
129    }
130}