Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
50.00% covered (danger)
50.00%
22 / 44
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
LintLogger
50.00% covered (danger)
50.00%
22 / 44
0.00% covered (danger)
0.00%
0 / 3
48.00
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 convertDSROffsets
91.67% covered (success)
91.67%
22 / 24
0.00% covered (danger)
0.00%
0 / 1
9.05
 logLintOutput
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\Logger;
5
6use Wikimedia\Assert\UnreachableException;
7use Wikimedia\Parsoid\Config\Env;
8use Wikimedia\Parsoid\Utils\Timing;
9use Wikimedia\Parsoid\Utils\TokenUtils;
10
11/**
12 * Logger backend for linter.
13 * This backend filters out logging messages with Logtype "lint/*" and
14 * logs them (console, external service).
15 */
16class LintLogger {
17
18    /** @var Env */
19    private $env;
20
21    /**
22     * @param Env $env
23     */
24    public function __construct( Env $env ) {
25        $this->env = $env;
26    }
27
28    /**
29     * Convert DSR offsets in collected lints
30     *
31     * Linter offsets should always be ucs2 if the lint viewer is client-side JavaScript.
32     * But, added conversion args in case callers wants some other conversion for other
33     * use cases.
34     *
35     * @param Env $env
36     * @param array &$lints
37     * @param string $from
38     * @param string $to
39     */
40    public static function convertDSROffsets(
41        Env $env, array &$lints, string $from = 'byte', string $to = 'ucs2'
42    ): void {
43        $metrics = $env->getSiteConfig()->metrics();
44        $timer = null;
45        if ( $metrics ) {
46            $timer = Timing::start( $metrics );
47        }
48
49        // Accumulate offsets + convert widths to pseudo-offsets
50        $offsets = [];
51        foreach ( $lints as &$lint ) {
52            $dsr = &$lint['dsr'];
53            $offsets[] = &$dsr[0];
54            $offsets[] = &$dsr[1];
55
56            // dsr[2] is a width. Convert it to an offset pointer.
57            if ( ( $dsr[2] ?? 0 ) > 1 ) { // widths 0,1,null are fine
58                $dsr[2] = $dsr[0] + $dsr[2];
59                $offsets[] = &$dsr[2];
60            }
61
62            // dsr[3] is a width. Convert it to an offset pointer.
63            if ( ( $dsr[3] ?? 0 ) > 1 ) { // widths 0,1,null are fine
64                $dsr[3] = $dsr[1] - $dsr[3];
65                $offsets[] = &$dsr[3];
66            }
67        }
68
69        TokenUtils::convertOffsets( $env->topFrame->getSrcText(), $from, $to, $offsets );
70
71        // Undo the conversions of dsr[2], dsr[3]
72        foreach ( $lints as &$lint ) {
73            $dsr = &$lint['dsr'];
74            if ( ( $dsr[2] ?? 0 ) > 1 ) { // widths 0,1,null are fine
75                $dsr[2] = $dsr[2] - $dsr[0];
76            }
77            if ( ( $dsr[3] ?? 0 ) > 1 ) { // widths 0,1,null are fine
78                $dsr[3] = $dsr[1] - $dsr[3];
79            }
80        }
81
82        if ( $metrics ) {
83            $timer->end( "lint.offsetconversion" );
84        }
85    }
86
87    /**
88     *
89     */
90    public function logLintOutput() {
91        $env = $this->env;
92
93        // We only want to send to the MW API if this was a request to parse
94        // the full page.
95        if ( !$env->logLinterData ) {
96            return;
97        }
98
99        $pageConfig = $env->getPageConfig();
100
101        // Skip linting if we cannot lint it
102        if ( !$pageConfig->hasLintableContentModel() ) {
103            return;
104        }
105
106        $linting = $env->getSiteConfig()->linting();
107        $enabledBuffer = null;
108
109        if ( $linting === true ) {
110            $enabledBuffer = $env->getLints(); // Everything is enabled
111        } elseif ( is_array( $linting ) ) {
112            $enabledBuffer = array_filter( $env->getLints(), static function ( $item ) use ( &$linting ) {
113                return in_array( $item['type'], $linting, true );
114            } );
115        } else {
116            throw new UnreachableException( 'Why are we here? Linting is disabled.' );
117        }
118
119        // Convert offsets to ucs2
120        $offsetType = $env->getCurrentOffsetType();
121        if ( $offsetType !== 'ucs2' ) {
122            self::convertDSROffsets( $env, $enabledBuffer, $offsetType, 'ucs2' );
123        }
124
125        $env->getDataAccess()->logLinterData( $pageConfig, $enabledBuffer );
126    }
127
128}