Passed
Push — master ( a6b786...0b84f7 )
by Guillaume
13:57 queued 06:04
created

TailwindCSS::updateCSS()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 5
cts 5
cp 1
crap 1
rs 10
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
        ]);
29
30
        system(
31
            "echo; wget tailwindcss.com/docs \
32
                --mirror \
33
                --trust-server-names \
34
                --reject-regex='{$toIgnore}' \
35
                --page-requisites \
36
                --adjust-extension \
37
                --convert-links \
38
                --span-hosts \
39
                --domains={$this->externalDomains()} \
40
                --directory-prefix=storage/{$this->downloadedDirectory()} \
41
                -e robots=off \
42
                --quiet \
43
                --show-progress",
44
            $result
45
        );
46
47
        return $result === 0;
48
    }
49
50 16
    public function entries(string $file): Collection
51
    {
52 16
        $crawler = HtmlPageCrawler::create(Storage::get($file));
53
54 16
        $entries = collect();
55
56 16
        $entries = $entries->union($this->environmentEntries($crawler, $file));
57 16
        $entries = $entries->union($this->instructionEntries($crawler, $file));
58 16
        $entries = $entries->union($this->sampleEntries($crawler, $file));
59 16
        $entries = $entries->union($this->resourceEntries($crawler, $file));
60 16
        $entries = $entries->union($this->guideEntries($crawler, $file));
61 16
        $entries = $entries->union($this->sectionEntries($crawler, $file));
62
63 16
        return $entries;
64
    }
65
66 16
    protected function environmentEntries(HtmlPageCrawler $crawler, string $file)
67
    {
68 16
        $entries = collect();
69
70 16
        if (Str::contains($file, "{$this->url()}/community.html")) {
71 8
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
72 8
                $entries->push([
73 8
                    'name' => $this->cleanAnchorText($node->text()),
74 8
                    'type' => 'Environment',
75 8
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
76
                ]);
77 8
            });
78
79 8
            return $entries;
80
        }
81 16
    }
82
83 16
    protected function instructionEntries(HtmlPageCrawler $crawler, string $file)
84
    {
85 16
        $entries = collect();
86
87 16
        if (Str::contains($file, "{$this->url()}/course.html")) {
88 8
            $crawler->filter('span.relative')->each(function (HtmlPageCrawler $node) use ($entries) {
89 8
                $entries->push([
90 8
                    'name' => $this->cleanAnchorText($node->text()),
91 8
                    'type' => 'Instruction',
92 8
                    'path' => $this->url() . '/' . $node->parents()->first()->attr('href'),
93
                ]);
94 8
            });
95
96 8
            return $entries;
97
        }
98 16
    }
99
100 16
    protected function sampleEntries(HtmlPageCrawler $crawler, string $file)
101
    {
102 16
        $entries = collect();
103
104 16
        if (Str::contains($file, "{$this->url()}/components/")) {
105 16
            $crawler->filter('span.relative')->each(function (HtmlPageCrawler $node) use ($entries) {
106 16
                $entries->push([
107 16
                    'name' => $this->cleanAnchorText($node->text()),
108 16
                    'type' => 'Sample',
109 16
                    'path' => $this->url() . '/components/' . $node->parents()->first()->attr('href'),
110
                ]);
111 16
            });
112
113 16
            return $entries;
114
        }
115 16
    }
116
117 16
    protected function resourceEntries(HtmlPageCrawler $crawler, string $file)
118
    {
119 16
        $entries = collect();
120
121 16
        if (Str::contains($file, "{$this->url()}/resources.html")) {
122 16
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
123 16
                $entries->push([
124 16
                    'name' => $this->cleanAnchorText($node->text()),
125 16
                    'type' => 'Resource',
126 16
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
127
                ]);
128 16
            });
129
130 16
            $crawler->filter('h3')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
131 16
                $entries->push([
132 16
                    'name' => $this->cleanAnchorText($node->text()),
133 16
                    'type' => 'Section',
134 16
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
135
                ]);
136 16
            });
137
138 16
            return $entries;
139
        }
140 16
    }
141
142 16
    protected function guideEntries(HtmlPageCrawler $crawler, string $file)
143
    {
144 16
        $entries = collect();
145
146 16
        if (Str::contains($file, "{$this->url()}/docs.html")) {
147 8
            $crawler->filter('nav#nav li.mt-8 a')->each(function (HtmlPageCrawler $node) use ($entries) {
148 8
                if (! Str::contains($node->text(), 'Release Notes')) {
149 8
                    $entries->push([
150 8
                        'name' => trim($node->text()),
151 8
                        'type' => 'Guide',
152 8
                        'path' => $this->url() . '/' . $node->attr('href'),
153
                    ]);
154
                }
155 8
            });
156
        }
157
158 16
        return $entries;
159
    }
160
161 16
    protected function sectionEntries(HtmlPageCrawler $crawler, string $file)
162
    {
163 16
        $entries = collect();
164
165 16
        $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
166 16
            $entries->push([
167 16
                'name' => $this->cleanAnchorText($node->text()),
168 16
                'type' => 'Section',
169 16
                'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
170
            ]);
171 16
        });
172
173 16
        return $entries;
174
    }
175
176 16
    public function format(string $file): string
177
    {
178 16
        $crawler = HtmlPageCrawler::create(Storage::get($file));
179
180 16
        $this->removeTopbar($crawler);
181 16
        $this->removeLeftSidebar($crawler);
182 16
        $this->removeRightSidebar($crawler);
183 16
        $this->removeBottomMenuButton($crawler);
184
185 16
        $this->updateContainerWidth($crawler);
186 16
        $this->updateBottomPadding($crawler);
187
188 16
        $this->ignoreDarkModeForSomeColors($crawler);
189
190 16
        $this->removeUnwantedJavaScript($crawler);
191
192 16
        $this->insertOnlineRedirection($crawler, $file);
193 16
        $this->insertDashTableOfContents($crawler, $file);
194
195 16
        return $crawler->saveHTML();
196
    }
197
198 16
    protected function removeTopbar(HtmlPageCrawler $crawler)
199
    {
200 16
        $crawler->filter('div.sticky.top-0')->remove();
201 16
    }
202
203 16
    protected function removeLeftSidebar(HtmlPageCrawler $crawler)
204
    {
205 16
        $crawler->filter('#sidebar')->remove();
206 16
    }
207
208 16
    protected function removeRightSidebar(HtmlPageCrawler $crawler)
209
    {
210 16
        $crawler->filter('#content-wrapper div.hidden.flex-none.w-64')->remove();
211 16
    }
212
213 16
    protected function removeBottomMenuButton(HtmlPageCrawler $crawler)
214
    {
215 16
        $crawler->filter('#__next > button[type=button]')->remove();
216 16
    }
217
218 16
    protected function updateContainerWidth(HtmlPageCrawler $crawler)
219
    {
220 16
        $crawler->filter('#content-wrapper')->addClass('px-4');
221 16
    }
222
223 16
    protected function updateBottomPadding(HtmlPageCrawler $crawler)
224
    {
225 16
        $crawler->filter('#content-wrapper > div')
226 16
            ->removeClass('pb-24')
227 16
            ->addClass('pb-10')
228
        ;
229 16
    }
230
231 16
    protected function ignoreDarkModeForSomeColors(HtmlPageCrawler $crawler)
232
    {
233 16
        $this->ignoreDarkModeForDefaultColorPaletteSection($crawler);
234 16
        $this->ignoreDarkModeForVariousColorTables($crawler);
235 16
    }
236
237 16
    protected function ignoreDarkModeForDefaultColorPaletteSection(HtmlPageCrawler $crawler)
238
    {
239 16
        $crawler->filter('div.h-10.w-full.rounded.ring-1.ring-inset')->addClass('dash-ignore-dark-mode');
240 16
    }
241
242 16
    protected function ignoreDarkModeForVariousColorTables(HtmlPageCrawler $crawler)
243
    {
244 16
        $crawler->filter('h2 + div td:last-child')->addClass('dash-ignore-dark-mode');
245 16
    }
246
247 16
    protected function removeUnwantedJavaScript(HtmlPageCrawler $crawler)
248
    {
249 16
        $crawler->filter('script')->remove();
250 16
    }
251
252 16
    protected function insertOnlineRedirection(HtmlPageCrawler $crawler, string $file)
253
    {
254 16
        $onlineUrl = Str::substr(Str::after($file, $this->innerDirectory()), 1, -5);
255
256 16
        $crawler->filter('html')->prepend("<!-- Online page at https://$onlineUrl -->");
257 16
    }
258
259 16
    protected function insertDashTableOfContents(HtmlPageCrawler $crawler, string $file)
260
    {
261 16
        if (! Str::contains($file, "{$this->url()}/docs.html")) {
262 16
            $crawler->filter('body')
263 16
                ->before('<a name="//apple_ref/cpp/Section/Top" class="dashAnchor"></a>');
264
265 16
            $crawler->filter('h2, h3')->each(function (HtmlPageCrawler $node) {
266 16
                $node->prepend(
267 16
                    '<a id="' . Str::slug($node->text()) . '" name="//apple_ref/cpp/Section/' . rawurlencode($this->cleanAnchorText($node->text())) . '" class="dashAnchor"></a>'
268
                );
269 16
            });
270
        }
271 16
    }
272
273 24
    protected function cleanAnchorText($anchorText)
274
    {
275 24
        return trim(preg_replace('/\s+/', ' ', $anchorText));
276
    }
277
}
278