Passed
Push — master ( 4866cf...ce402a )
by Guillaume
15:33 queued 13:33
created

TailwindCSS::entries()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 11
ccs 7
cts 7
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->resourceEntries($crawler, $file));
57 16
        $entries = $entries->union($this->guideEntries($crawler, $file));
58 16
        $entries = $entries->union($this->sectionEntries($crawler, $file));
59
60 16
        return $entries;
61
    }
62
63 16
    protected function resourceEntries(HtmlPageCrawler $crawler, string $file)
64
    {
65 16
        $entries = collect();
66
67 16
        if (Str::contains($file, "{$this->url()}/resources.html")) {
68 16
            $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
69 16
                $entries->push([
70 16
                    'name' => $this->cleanAnchorText($node->text()),
71 16
                    'type' => 'Resource',
72 16
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
73
                ]);
74 16
            });
75
76 16
            $crawler->filter('h3')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
77 16
                $entries->push([
78 16
                    'name' => $this->cleanAnchorText($node->text()),
79 16
                    'type' => 'Section',
80 16
                    'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
81
                ]);
82 16
            });
83
84 16
            return $entries;
85
        }
86 16
    }
87
88 16
    protected function guideEntries(HtmlPageCrawler $crawler, string $file)
89
    {
90 16
        $entries = collect();
91
92 16
        if (Str::contains($file, "{$this->url()}/docs.html")) {
93 8
            $crawler->filter('nav#nav li.mt-8 a')->each(function (HtmlPageCrawler $node) use ($entries) {
94 8
                if (! Str::contains($node->text(), 'Release Notes')) {
95 8
                    $entries->push([
96 8
                        'name' => trim($node->text()),
97 8
                        'type' => 'Guide',
98 8
                        'path' => $this->url() . '/' . $node->attr('href'),
99
                    ]);
100
                }
101 8
            });
102
        }
103
104 16
        return $entries;
105
    }
106
107 16
    protected function sectionEntries(HtmlPageCrawler $crawler, string $file)
108
    {
109 16
        $entries = collect();
110
111 16
        $crawler->filter('h2')->each(function (HtmlPageCrawler $node) use ($entries, $file) {
112 16
            $entries->push([
113 16
                'name' => $this->cleanAnchorText($node->text()),
114 16
                'type' => 'Section',
115 16
                'path' => Str::after($file . '#' . Str::slug($node->text()), $this->innerDirectory()),
116
            ]);
117 16
        });
118
119 16
        return $entries;
120
    }
121
122 16
    public function format(string $file): string
123
    {
124 16
        $crawler = HtmlPageCrawler::create(Storage::get($file));
125
126 16
        $this->removeTopbar($crawler);
127 16
        $this->removeLeftSidebar($crawler);
128 16
        $this->removeRightSidebar($crawler);
129 16
        $this->removeBottomMenuButton($crawler);
130
131 16
        $this->updateContainerWidth($crawler);
132 16
        $this->updateBottomPadding($crawler);
133
134 16
        $this->ignoreDarkModeForSomeColors($crawler);
135
136 16
        $this->removeUnwantedJavaScript($crawler);
137
138 16
        $this->insertOnlineRedirection($crawler, $file);
139 16
        $this->insertDashTableOfContents($crawler, $file);
140
141 16
        return $crawler->saveHTML();
142
    }
143
144 16
    protected function removeTopbar(HtmlPageCrawler $crawler)
145
    {
146 16
        $crawler->filter('div.sticky.top-0')->remove();
147 16
    }
148
149 16
    protected function removeLeftSidebar(HtmlPageCrawler $crawler)
150
    {
151 16
        $crawler->filter('#sidebar')->remove();
152 16
    }
153
154 16
    protected function removeRightSidebar(HtmlPageCrawler $crawler)
155
    {
156 16
        $crawler->filter('#content-wrapper div.hidden.flex-none.w-64')->remove();
157 16
    }
158
159 16
    protected function removeBottomMenuButton(HtmlPageCrawler $crawler)
160
    {
161 16
        $crawler->filter('#__next > button[type=button]')->remove();
162 16
    }
163
164 16
    protected function updateContainerWidth(HtmlPageCrawler $crawler)
165
    {
166 16
        $crawler->filter('#content-wrapper')->addClass('px-4');
167 16
    }
168
169 16
    protected function updateBottomPadding(HtmlPageCrawler $crawler)
170
    {
171 16
        $crawler->filter('#content-wrapper > div')
172 16
            ->removeClass('pb-24')
173 16
            ->addClass('pb-10')
174
        ;
175 16
    }
176
177 16
    protected function ignoreDarkModeForSomeColors(HtmlPageCrawler $crawler)
178
    {
179 16
        $this->ignoreDarkModeForDefaultColorPaletteSection($crawler);
180 16
        $this->ignoreDarkModeForVariousColorTables($crawler);
181 16
    }
182
183 16
    protected function ignoreDarkModeForDefaultColorPaletteSection(HtmlPageCrawler $crawler)
184
    {
185 16
        $crawler->filter('div.h-10.w-full.rounded.ring-1.ring-inset')->addClass('dash-ignore-dark-mode');
186 16
    }
187
188 16
    protected function ignoreDarkModeForVariousColorTables(HtmlPageCrawler $crawler)
189
    {
190 16
        $crawler->filter('h2 + div td:last-child')->addClass('dash-ignore-dark-mode');
191 16
    }
192
193 16
    protected function removeUnwantedJavaScript(HtmlPageCrawler $crawler)
194
    {
195 16
        $crawler->filter('script')->remove();
196 16
    }
197
198 16
    protected function insertOnlineRedirection(HtmlPageCrawler $crawler, string $file)
199
    {
200 16
        $onlineUrl = Str::substr(Str::after($file, $this->innerDirectory()), 1, -5);
201
202 16
        $crawler->filter('html')->prepend("<!-- Online page at https://$onlineUrl -->");
203 16
    }
204
205 16
    protected function insertDashTableOfContents(HtmlPageCrawler $crawler, string $file)
206
    {
207 16
        if (! Str::contains($file, "{$this->url()}/docs.html")) {
208 16
            $crawler->filter('body')
209 16
                ->before('<a name="//apple_ref/cpp/Section/Top" class="dashAnchor"></a>');
210
211 16
            $crawler->filter('h2, h3')->each(function (HtmlPageCrawler $node) {
212 16
                $node->prepend(
213 16
                    '<a id="' . Str::slug($node->text()) . '" name="//apple_ref/cpp/Section/' . rawurlencode($this->cleanAnchorText($node->text())) . '" class="dashAnchor"></a>'
214
                );
215 16
            });
216
        }
217 16
    }
218
219 24
    protected function cleanAnchorText($anchorText)
220
    {
221 24
        return trim(preg_replace('/\s+/', ' ', $anchorText));
222
    }
223
}
224