Passed
Push — master ( e62da4...21834f )
by Guillaume
05:30
created

TailwindCSS::instructionEntries()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 8
c 2
b 0
f 0
dl 0
loc 14
ccs 0
cts 9
cp 0
rs 10
cc 2
nc 2
nop 2
crap 6
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->removeUnwantedJavaScript($crawler);
164
        $this->updateCSS($crawler);
165
        $this->insertDashTableOfContents($crawler);
166
167
        return $crawler->saveHTML();
168
    }
169
170
    protected function removeNavbarAndHeader(HtmlPageCrawler $crawler)
171
    {
172
        $crawler->filter('body > div:first-child')->remove();
173
    }
174
175
    protected function removeLeftSidebar(HtmlPageCrawler $crawler)
176
    {
177
        $crawler->filter('#sidebar')->remove();
178
    }
179
180
    protected function removeRightSidebar(HtmlPageCrawler $crawler)
181
    {
182
        $crawler->filter('#app div.flex > div.hidden')->remove();
183
    }
184
185
    protected function removeTailwindUIAlert(HtmlPageCrawler $crawler)
186
    {
187
        $crawler->filter('body > div.transition.transform.fixed.z-100')->remove();
188
    }
189
190
    protected function removeUnwantedJavaScript(HtmlPageCrawler $crawler)
191
    {
192
        $crawler->filter('script[src*=analytics]')->remove();
193
        $crawler->filter('script[src*=docsearch]')->remove();
194
        $crawler->filter('script[src*=gtag]')->remove();
195
        $crawler->filterXPath("//script[text()[contains(.,'docsearch')]]")->remove();
196
        $crawler->filterXPath("//script[text()[contains(.,'gtag')]]")->remove();
197
        $crawler->filter('script[src*=jquery]')
198
            ->removeAttribute('integrity')
199
            ->removeAttribute('crossorigin');
200
    }
201
202
    protected function updateCSS(HtmlPageCrawler $crawler)
203
    {
204
        $this->updateTopPadding($crawler);
205
        $this->updateHeader($crawler);
206
        $this->updateContainerWidth($crawler);
207
        $this->updateBottomPadding($crawler);
208
    }
209
210
    protected function updateTopPadding(HtmlPageCrawler $crawler)
211
    {
212
        $crawler->filter('#app > div')
213
            ->removeClass('pt-12')
214
            ->removeClass('pt-24')
215
            ->removeClass('pb-16')
216
            ->removeClass('lg:pt-28')
217
            ->removeClass('lg:pt-12')
218
        ;
219
    }
220
221
    protected function updateHeader(HtmlPageCrawler $crawler)
222
    {
223
        $crawler->filter('#app > div > div.markdown')
224
            ->removeClass('lg:ml-0')
225
            ->removeClass('lg:mr-auto')
226
            ->removeClass('xl:mx-0')
227
            ->removeClass('xl:w-3/4')
228
            ->removeClass('max-w-3xl')
229
            ->removeClass('xl:px-12')
230
        ;
231
    }
232
233
    protected function updateContainerWidth(HtmlPageCrawler $crawler)
234
    {
235
        $crawler->filter('body > div:first-child')
236
            ->removeClass('max-w-screen-xl');
237
238
        $crawler->filter('#content-wrapper')
239
            ->removeClass('lg:static')
240
            ->removeClass('lg:max-h-full')
241
            ->removeClass('lg:overflow-visible')
242
            ->removeClass('lg:w-3/4')
243
            ->removeClass('xl:w-4/5');
244
245
        $crawler->filter('#app > div > div.flex > div.markdown')
246
            ->removeClass('xl:p-12')
247
            ->removeClass('max-w-3xl')
248
            ->removeClass('lg:ml-0')
249
            ->removeClass('lg:mr-auto')
250
            ->removeClass('xl:w-3/4')
251
            ->removeClass('xl:px-12')
252
            ->removeClass('xl:mx-0');
253
    }
254
255
    protected function updateBottomPadding(HtmlPageCrawler $crawler)
256
    {
257
        $crawler->filter('body')
258
            ->addClass('pb-8');
259
    }
260
261
    protected function insertDashTableOfContents(HtmlPageCrawler $crawler)
262
    {
263
        $crawler->filter('h1')
264
            ->before('<a name="//apple_ref/cpp/Section/Top" class="dashAnchor"></a>');
265
266
        $crawler->filter('h2, h3')->each(function (HtmlPageCrawler $node) {
267
            $node->prepend(
268
                '<a id="' . Str::slug($node->text()) . '" name="//apple_ref/cpp/Section/' . rawurlencode($this->cleanAnchorText($node->text())) . '" class="dashAnchor"></a>'
269
            );
270
        });
271
    }
272
273
    protected function cleanAnchorText($anchorText)
274
    {
275
        return trim(preg_replace('/\s+/', ' ', $anchorText));
276
    }
277
}
278