Test Failed
Push — master ( 518815...685a33 )
by Guillaume
07:49 queued 02:37
created

TailwindCSS::removeUnwantedCSS()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace App\Docsets;
4
5
use Illuminate\Support\Str;
6
use Wa72\HtmlPageDom\HtmlPage;
7
use Illuminate\Support\Collection;
8
use Wa72\HtmlPageDom\HtmlPageCrawler;
9
use Illuminate\Support\Facades\Storage;
10
11
class TailwindCSS extends BaseDocset
12
{
13
    public const CODE = 'tailwindcss';
14
    public const NAME = 'Tailwind CSS';
15
    public const URL = 'tailwindcss.com';
16
    public const INDEX = 'docs/installation.html';
17
    public const PLAYGROUND = 'https://codesandbox.io/s/github/lbogdan/tailwindcss-playground';
18
    public const ICON_16 = 'favicon-16x16.png';
19
    public const ICON_32 = 'favicon-32x32.png';
20
    public const EXTERNAL_DOMAINS = [
21
        'refactoring-ui.nyc3.cdn.digitaloceanspaces.com',
22
        'jsdelivr.net',
23
        'code.jquery.com',
24
        'rsms.me',
25
        'googleapis.com',
26
        // 'images.unsplash.com'
27
    ];
28
29
    public function entries(string $file): Collection
30
    {
31
        $crawler = HtmlPageCrawler::create(Storage::get($file));
32
33
        $entries = collect();
34
35
        $entries = $entries->merge($this->environmentEntries($crawler, $file));
36
        $entries = $entries->merge($this->instructionEntries($crawler, $file));
37
        $entries = $entries->merge($this->sampleEntries($crawler, $file));
38
        $entries = $entries->merge($this->resourceEntries($crawler, $file));
39
        $entries = $entries->merge($this->guideEntries($crawler, $file));
40
        $entries = $entries->merge($this->sectionEntries($crawler, $file));
41
42
        return $entries;
43
    }
44
45
    protected function environmentEntries(HtmlPageCrawler $crawler, string $file)
46
    {
47
        $entries = collect();
48
49
        if (basename($file) === 'community.html') {
50
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
51
                $entries->push([
52
                    'name' => $this->cleanAnchorText($node->text()),
53
                    'type' => 'Environment',
54
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
55
                ]);
56
            });
57
58
            return $entries;
59
        }
60
    }
61
62
    protected function instructionEntries(HtmlPageCrawler $crawler, string $file)
63
    {
64
        $entries = collect();
65
66
        if (basename($file) === 'screencasts.html') {
67
            $crawler->filter('span.relative')->each(function (HtmlPageCrawler $node) use ($entries) {
68
                $entries->push([
69
                    'name' => $this->cleanAnchorText($node->text()),
70
                    'type' => 'Instruction',
71
                    'path' => $this->url() . '/' . $node->parents()->first()->attr('href'),
72
                ]);
73
            });
74
75
            return $entries;
76
        }
77
    }
78
79
    protected function sampleEntries(HtmlPageCrawler $crawler, string $file)
80
    {
81
        $entries = collect();
82
83
        if (basename($file) === 'components.html') {
84
            $crawler->filter('span.relative')->each(function (HtmlPageCrawler $node) use ($entries) {
85
                $entries->push([
86
                    'name' => $this->cleanAnchorText($node->text()),
87
                    'type' => 'Sample',
88
                    'path' => $this->url() . '/' . $node->parents()->first()->attr('href'),
89
                ]);
90
            });
91
92
            return $entries;
93
        }
94
    }
95
96
    protected function resourceEntries(HtmlPageCrawler $crawler, string $file)
97
    {
98
        $entries = collect();
99
100
        if (basename($file) === 'resources.html') {
101
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
102
                $entries->push([
103
                    'name' => $this->cleanAnchorText($node->text()),
104
                    'type' => 'Resource',
105
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
106
                ]);
107
            });
108
109
            $crawler->filter('h3')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
110
                $entries->push([
111
                    'name' => $this->cleanAnchorText($node->text()),
112
                    'type' => 'Section',
113
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
114
                ]);
115
            });
116
117
            return $entries;
118
        }
119
    }
120
121
    protected function guideEntries(HtmlPageCrawler $crawler, string $file)
122
    {
123
        $pageTitle = (new HtmlPage(Storage::get($file)))->getTitle();
124
125
        $entries = collect();
126
127
        if ($pageTitle === 'Installation - Tailwind CSS') {
128
            $crawler->filter('#navWrapper li a')->each(function (HtmlPageCrawler $node) use ($entries) {
129
                $entries->push([
130
                    'name' => trim($node->text()),
131
                    'type' => 'Guide',
132
                    'path' => $this->url() . '/docs/' . $node->attr('href'),
133
                ]);
134
            });
135
        }
136
137
        return $entries;
138
    }
139
140
    protected function sectionEntries(HtmlPageCrawler $crawler, string $file)
141
    {
142
        $entries = collect();
143
144
        $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
145
            $entries->push([
146
                'name' => $this->cleanAnchorText($node->text()),
147
                'type' => 'Section',
148
                'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
149
            ]);
150
        });
151
152
        return $entries;
153
    }
154
155
    public function format(string $html): string
156
    {
157
        $crawler = HtmlPageCrawler::create($html);
158
159
        $this->removeNavbarAndHeader($crawler);
160
        $this->removeLeftSidebar($crawler);
161
        $this->removeRightSidebar($crawler);
162
        $this->removeTailwindUIAlert($crawler);
163
        $this->removeUnwantedCSS($crawler);
164
        $this->removeUnwantedJavaScript($crawler);
165
        $this->updateCSS($crawler);
166
        $this->insertDashTableOfContents($crawler);
167
168
        return $crawler->saveHTML();
169
    }
170
171
    protected function removeNavbarAndHeader(HtmlPageCrawler $crawler)
172
    {
173
        $crawler->filter('body > div:first-child')->remove();
174
    }
175
176
    protected function removeLeftSidebar(HtmlPageCrawler $crawler)
177
    {
178
        $crawler->filter('#sidebar')->remove();
179
    }
180
181
    protected function removeRightSidebar(HtmlPageCrawler $crawler)
182
    {
183
        $crawler->filter('#app div.flex > div.hidden')->remove();
184
    }
185
186
    protected function removeTailwindUIAlert(HtmlPageCrawler $crawler)
187
    {
188
        $crawler->filter('body > div.transition.transform.fixed.z-100')->remove();
189
    }
190
191
    protected function removeUnwantedCSS(HtmlPageCrawler $crawler)
192
    {
193
        $crawler->filter('link[href*="docsearch.min.css"]')->remove();
194
    }
195
196
    protected function removeUnwantedJavaScript(HtmlPageCrawler $crawler)
197
    {
198
        $crawler->filter('script[src*=analytics]')->remove();
199
        $crawler->filter('script[src*=docsearch]')->remove();
200
        $crawler->filter('script[src*=gtag]')->remove();
201
        $crawler->filterXPath("//script[text()[contains(.,'docsearch')]]")->remove();
202
        $crawler->filterXPath("//script[text()[contains(.,'gtag')]]")->remove();
203
        $crawler->filter('script[src*=jquery]')
204
            ->removeAttribute('integrity')
205
            ->removeAttribute('crossorigin');
206
    }
207
208
    protected function updateCSS(HtmlPageCrawler $crawler)
209
    {
210
        $this->updateTopPadding($crawler);
211
        $this->updateHeader($crawler);
212
        $this->updateContainerWidth($crawler);
213
        $this->updateBottomPadding($crawler);
214
    }
215
216
    protected function updateTopPadding(HtmlPageCrawler $crawler)
217
    {
218
        $crawler->filter('#app > div')
219
            ->removeClass('pt-12')
220
            ->removeClass('pt-24')
221
            ->removeClass('pb-16')
222
            ->removeClass('lg:pt-28')
223
            ->removeClass('lg:pt-12')
224
        ;
225
    }
226
227
    protected function updateHeader(HtmlPageCrawler $crawler)
228
    {
229
        $crawler->filter('#app > div > div.markdown')
230
            ->removeClass('lg:ml-0')
231
            ->removeClass('lg:mr-auto')
232
            ->removeClass('xl:mx-0')
233
            ->removeClass('xl:w-3/4')
234
            ->removeClass('max-w-3xl')
235
            ->removeClass('xl:px-12')
236
        ;
237
    }
238
239
    protected function updateContainerWidth(HtmlPageCrawler $crawler)
240
    {
241
        $crawler->filter('body > div:first-child')
242
            ->removeClass('max-w-screen-xl');
243
244
        $crawler->filter('#content-wrapper')
245
            ->removeClass('lg:static')
246
            ->removeClass('lg:max-h-full')
247
            ->removeClass('lg:overflow-visible')
248
            ->removeClass('lg:w-3/4')
249
            ->removeClass('xl:w-4/5');
250
251
        $crawler->filter('#app > div > div.flex > div.markdown')
252
            ->removeClass('xl:p-12')
253
            ->removeClass('max-w-3xl')
254
            ->removeClass('lg:ml-0')
255
            ->removeClass('lg:mr-auto')
256
            ->removeClass('xl:w-3/4')
257
            ->removeClass('xl:px-12')
258
            ->removeClass('xl:mx-0');
259
    }
260
261
    protected function updateBottomPadding(HtmlPageCrawler $crawler)
262
    {
263
        $crawler->filter('body')
264
            ->addClass('pb-8');
265
    }
266
267
    protected function insertDashTableOfContents(HtmlPageCrawler $crawler)
268
    {
269
        $crawler->filter('h1')
270
            ->before('<a name="//apple_ref/cpp/Section/Top" class="dashAnchor"></a>');
271
272
        $crawler->filter('h2, h3')->each(function (HtmlPageCrawler $node) {
273
            $node->prepend(
274
                '<a id="' . Str::slug($node->text()) . '" name="//apple_ref/cpp/Section/' . rawurlencode($this->cleanAnchorText($node->text())) . '" class="dashAnchor"></a>'
275
            );
276
        });
277
    }
278
279
    protected function cleanAnchorText($anchorText)
280
    {
281
        return trim(preg_replace('/\s+/', ' ', $anchorText));
282
    }
283
}
284