Passed
Push — master ( 6d057f...c84633 )
by Guillaume
34:14 queued 17:15
created

TailwindCSS::guideEntries()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 2
b 0
f 0
nc 2
nop 2
dl 0
loc 21
ccs 13
cts 13
cp 1
crap 3
rs 9.8666
1
<?php
2
3
namespace App\Docsets;
4
5
use Godbout\DashDocsetBuilder\Docsets\BaseDocset;
6
use Illuminate\Support\Collection;
7
use Illuminate\Support\Facades\Storage;
8
use Illuminate\Support\Str;
9
use Wa72\HtmlPageDom\HtmlPageCrawler;
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://play.tailwindcss.com/';
18
    public const ICON_16 = 'favicon-16x16.png';
19
    public const ICON_32 = 'favicon-32x32.png';
20
    public const EXTERNAL_DOMAINS = [
21
    ];
22
23
24
    public function grab(): bool
25
    {
26
        $toIgnore = implode('|', [
27
            'blog.tailwindcss.com',
28
            'v1.tailwindcss.com',
29
            'v2.tailwindcss.com'
30
        ]);
31
32
        system(
33
            "echo; wget tailwindcss.com/docs \
34
                --mirror \
35
                --trust-server-names \
36
                --reject-regex='{$toIgnore}' \
37
                --page-requisites \
38
                --adjust-extension \
39
                --convert-links \
40
                --span-hosts \
41
                --domains={$this->externalDomains()} \
42
                --directory-prefix=storage/{$this->downloadedDirectory()} \
43
                -e robots=off \
44
                --quiet \
45
                --show-progress",
46
            $result
47
        );
48
49
        return $result === 0;
50
    }
51
52 16
    public function entries(string $file): Collection
53
    {
54 16
        $crawler = HtmlPageCrawler::create(Storage::get($file));
55
56 16
        $entries = collect();
57
58 16
        $entries = $entries->union($this->resourceEntries($crawler, $file));
59 16
        $entries = $entries->union($this->guideEntries($crawler, $file));
60 16
        $entries = $entries->union($this->sectionEntries($crawler, $file));
61
62 16
        return $entries;
63
    }
64
65 16
    protected function resourceEntries(HtmlPageCrawler $crawler, string $file)
66
    {
67 16
        $entries = collect();
68
69 16
        if (Str::contains($file, "{$this->url()}/resources.html")) {
70 16
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
71 16
                $entries->push([
0 ignored issues
show
Bug introduced by
array('name' => $this->c...his->innerDirectory())) of type array<string,string> is incompatible with the type Illuminate\Support\TValue expected by parameter $values of Illuminate\Support\Collection::push(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

71
                $entries->push(/** @scrutinizer ignore-type */ [
Loading history...
72 16
                    'name' => $this->cleanAnchorText($node->text()),
73 8
                    'type' => 'Resource',
74 16
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
75
                ]);
76 8
            });
77
78 16
            $crawler->filter('h3')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
79 16
                $entries->push([
0 ignored issues
show
Bug introduced by
array('name' => $this->c...his->innerDirectory())) of type array<string,string> is incompatible with the type Illuminate\Support\TValue expected by parameter $values of Illuminate\Support\Collection::push(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

79
                $entries->push(/** @scrutinizer ignore-type */ [
Loading history...
80 16
                    'name' => $this->cleanAnchorText($node->text()),
81 8
                    'type' => 'Section',
82 16
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
83
                ]);
84 8
            });
85
86 16
            return $entries;
87
        }
88 8
    }
89
90 16
    protected function guideEntries(HtmlPageCrawler $crawler, string $file)
91
    {
92 16
        $entries = collect();
93
94 16
        if (Str::contains($file, "{$this->url()}/docs.html")) {
95 8
            $itemsToIgnore = collect(['Release Notes', 'Typography', 'Forms', 'Aspect Ratio', 'Line Clamp']);
0 ignored issues
show
Bug introduced by
array('Release Notes', '...t Ratio', 'Line Clamp') of type array<integer,string> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            $itemsToIgnore = collect(/** @scrutinizer ignore-type */ ['Release Notes', 'Typography', 'Forms', 'Aspect Ratio', 'Line Clamp']);
Loading history...
96
97
            $crawler
98 8
                ->filter('nav#nav li.mt-8 a')
99 8
                ->each(function (HtmlPageCrawler $node) use ($entries, $itemsToIgnore) {
100 8
                    if (! $itemsToIgnore->contains($node->text())) {
101 8
                        $entries->push([
0 ignored issues
show
Bug introduced by
array('name' => trim($no... . $node->attr('href')) of type array<string,string> is incompatible with the type Illuminate\Support\TValue expected by parameter $values of Illuminate\Support\Collection::push(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
                        $entries->push(/** @scrutinizer ignore-type */ [
Loading history...
102 8
                            'name' => trim($node->text()),
103 4
                            'type' => 'Guide',
104 8
                            'path' => $this->url() . '/' . $node->attr('href'),
105
                        ]);
106
                    }
107 4
                });
108
        }
109
110 16
        return $entries;
111
    }
112
113 16
    protected function sectionEntries(HtmlPageCrawler $crawler, string $file)
114
    {
115 16
        $entries = collect();
116
117 16
        $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
118 16
            $entries->push([
0 ignored issues
show
Bug introduced by
array('name' => $this->c...his->innerDirectory())) of type array<string,string> is incompatible with the type Illuminate\Support\TValue expected by parameter $values of Illuminate\Support\Collection::push(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
            $entries->push(/** @scrutinizer ignore-type */ [
Loading history...
119 16
                'name' => $this->cleanAnchorText($node->text()),
120 8
                'type' => 'Section',
121 16
                'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
122
            ]);
123 8
        });
124
125 16
        return $entries;
126
    }
127
128 16
    public function format(string $file): string
129
    {
130 16
        $crawler = HtmlPageCrawler::create(Storage::get($file));
131
132 16
        $this->removeTopbar($crawler);
133 16
        $this->removeLeftSidebar($crawler);
134 16
        $this->removeRightSidebar($crawler);
135 16
        $this->removeClassesOverflow($crawler);
136
137 16
        $this->updateContainerWidth($crawler);
138 16
        $this->tweakFooter($crawler);
139
140 16
        $this->removeDarkModeInHTMLTag($crawler);
141 16
        $this->ignoreDarkModeForSomeColors($crawler);
142
143 16
        $this->removeUnwantedJavaScript($crawler);
144
145 16
        $this->insertOnlineRedirection($crawler, $file);
146 16
        $this->insertDashTableOfContents($crawler, $file);
147
148 16
        return $crawler->saveHTML();
149
    }
150
151 16
    protected function removeTopbar(HtmlPageCrawler $crawler)
152
    {
153 16
        $crawler->filter('div.sticky.top-0')->remove();
154 8
    }
155
156 16
    protected function removeLeftSidebar(HtmlPageCrawler $crawler)
157
    {
158 16
        $crawler->filter('div.hidden.fixed.z-20.inset-0.overflow-y-auto')->remove();
159 8
    }
160
161 16
    protected function removeRightSidebar(HtmlPageCrawler $crawler)
162
    {
163 16
        $crawler->filter('div.fixed.z-20.bottom-0.py-10.px-8.overflow-y-auto.hidden')->remove();
164 8
    }
165
166 16
    protected function removeClassesOverflow(HtmlPageCrawler $crawler)
167
    {
168 16
        $crawler->filter('#class-reference + div')
169 16
            ->removeClass('overflow-hidden')
170 16
            ->removeClass('lg:overflow-auto')
171 16
            ->addClass('overflow-auto')
172
        ;
173
174 16
        $crawler->filter('#class-reference ~ div:nth-of-type(2)')
175 16
            ->remove()
176
        ;
177 8
    }
178
179 16
    protected function updateContainerWidth(HtmlPageCrawler $crawler)
180
    {
181 16
        $crawler->filter('div.max-w-8xl.mx-auto.px-4 > div:first-child')
182 16
            ->removeClass('lg:pl-[19.5rem]')
183
        ;
184 16
        $crawler->filter('div.max-w-3xl.mx-auto.pt-10')
185 16
            ->removeClass('max-w-3xl')
186 16
            ->removeClass('mx-auto')
187 16
            ->removeClass('xl:max-w-none')
188 16
            ->removeClass('xl:mr-[15.5rem]')
189 16
            ->removeClass('xl:pr-16')
190
        ;
191 8
    }
192
193 16
    protected function tweakFooter(HtmlPageCrawler $crawler)
194
    {
195 16
        $crawler->filter('footer div:first-child')
196 16
            ->removeClass('mb-10')
197 16
            ->addClass('pb-10')
198
        ;
199
200 16
        $crawler->filter('footer div:last-child')
201 16
            ->remove()
202
        ;
203 8
    }
204
205 16
    protected function removeDarkModeInHTMLTag(HtmlPageCrawler $crawler)
206
    {
207 16
        $crawler->filter('html')
208 16
            ->removeClass('dark')
209
        ;
210 8
    }
211
212 16
    protected function ignoreDarkModeForSomeColors(HtmlPageCrawler $crawler)
213
    {
214 16
        $this->ignoreDarkModeForDefaultColorPaletteSection($crawler);
215 16
        $this->ignoreDarkModeForVariousColorTables($crawler);
216 8
    }
217
218 16
    protected function ignoreDarkModeForDefaultColorPaletteSection(HtmlPageCrawler $crawler)
219
    {
220 16
        $crawler->filter('div.h-10.w-full.rounded.ring-1.ring-inset')->addClass('dash-ignore-dark-mode');
221 8
    }
222
223 16
    protected function ignoreDarkModeForVariousColorTables(HtmlPageCrawler $crawler)
224
    {
225 16
        $crawler->filter('h2 + div td:last-child')->addClass('dash-ignore-dark-mode');
226 8
    }
227
228 16
    protected function removeUnwantedJavaScript(HtmlPageCrawler $crawler)
229
    {
230 16
        $crawler->filter('script')->remove();
231 8
    }
232
233 16
    protected function insertOnlineRedirection(HtmlPageCrawler $crawler, string $file)
234
    {
235 16
        $onlineUrl = Str::substr(Str::after($file, $this->innerDirectory()), 1, -5);
236
237 16
        $crawler->filter('html')->prepend("<!-- Online page at https://$onlineUrl -->");
238 8
    }
239
240 16
    protected function insertDashTableOfContents(HtmlPageCrawler $crawler, string $file)
241
    {
242 16
        if (! Str::contains($file, "{$this->url()}/docs.html")) {
243 16
            $crawler->filter('body')
244 16
                ->before('<a name="//apple_ref/cpp/Section/Top" class="dashAnchor"></a>');
245
246 16
            $crawler->filter('h2, h3')->each(function (HtmlPageCrawler $node) {
247 16
                $node->prepend(
248 16
                    '<a id="' . Str::slug($node->text()) . '" name="//apple_ref/cpp/Section/' . rawurlencode($this->cleanAnchorText($node->text())) . '" class="dashAnchor"></a>'
249
                );
250 8
            });
251
        }
252 8
    }
253
254 24
    protected function cleanAnchorText($anchorText)
255
    {
256 24
        return trim(preg_replace('/\s+/', ' ', $anchorText));
257
    }
258
}
259