Passed
Push — v1 ( 270350...b42adf )
by Andrew
09:36 queued 04:37
created

ManifestHelper::filenameWithoutHash()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Vite plugin for Craft CMS 3.x
4
 *
5
 * Allows the use of the Vite.js next generation frontend tooling with Craft CMS
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2021 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
10
11
namespace nystudio107\pluginvite\helpers;
12
13
use Craft;
14
use craft\helpers\Json as JsonHelper;
15
16
17
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
18
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
19
 * @package   Vite
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
20
 * @since     1.0.5
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
21
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
22
class ManifestHelper
23
{
24
    // Constants
25
    // =========================================================================
26
27
    const LEGACY_EXTENSION = '-legacy.';
28
29
    // Protected Static Properties
30
    // =========================================================================
31
32
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
33
     * @var array|null
34
     */
35
    protected static $manifest;
36
37
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
38
     * @var array|null
39
     */
40
    protected static $assetFiles;
41
42
    // Public Static Methods
43
    // =========================================================================
44
45
    /**
46
     * Fetch and memoize the manifest file
47
     *
48
     * @param string $manifestPath
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
49
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
50
    public static function fetchManifest(string $manifestPath)
51
    {
52
        // Grab the manifest
53
        $pathOrUrl = (string)Craft::parseEnv($manifestPath);
54
        $manifest = FileHelper::fetch($pathOrUrl, [JsonHelper::class, 'decodeIfJson']);
55
        // If no manifest file is found, log it
56
        if ($manifest === null) {
57
            Craft::error('Manifest not found at ' . $manifestPath, __METHOD__);
58
        }
59
        // Ensure we're dealing with an array
60
        self::$manifest = (array)$manifest;
61
    }
62
63
    /**
64
     * Return an array of tags from the manifest, for both modern and legacy builds
65
     *
66
     * @param string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
67
     * @param bool $asyncCss
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
68
     * @param array $scriptTagAttrs
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
69
     * @param array $cssTagAttrs
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
70
     *
71
     * @return array
72
     */
73
    public static function manifestTags(string $path, bool $asyncCss = true, array $scriptTagAttrs = [], array $cssTagAttrs = []): array
74
    {
75
        // Get the modern tags for this $path
76
        return self::extractManifestTags($path, $asyncCss, $scriptTagAttrs, $cssTagAttrs);
77
    }
78
79
    /**
80
     * Return an array of tags from the manifest, for both modern and legacy builds
81
     *
82
     * @param string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
83
     * @param bool $asyncCss
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
84
     * @param array $scriptTagAttrs
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
85
     * @param array $cssTagAttrs
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
86
     *
87
     * @return array
88
     */
89
    public static function legacyManifestTags(string $path, bool $asyncCss = true, array $scriptTagAttrs = [], array $cssTagAttrs = []): array
90
    {
91
        // Get the legacy tags for this $path
92
        $parts = pathinfo($path);
93
        $legacyPath = $parts['dirname']
94
            . '/'
95
            . $parts['filename']
96
            . self::LEGACY_EXTENSION
97
            . $parts['extension'];
98
99
        return self::extractManifestTags($legacyPath, $asyncCss, $scriptTagAttrs, $cssTagAttrs, true);
100
    }
101
102
    /**
103
     * Return an array of data describing the  script, module link, and CSS link tags for the
104
     * script from the manifest.json file
105
     *
106
     * @param string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
107
     * @param bool $asyncCss
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
108
     * @param array $scriptTagAttrs
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
109
     * @param array $cssTagAttrs
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
110
     * @param bool $legacy
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
111
     *
112
     * @return array
113
     */
114
    public static function extractManifestTags(string $path, bool $asyncCss = true, array $scriptTagAttrs = [], array $cssTagAttrs = [], bool $legacy = false): array
115
    {
116
        if (self::$manifest === null) {
117
            return [];
118
        }
119
        $tags = [];
120
        // Set the async CSS args
121
        $asyncCssOptions = [];
122
        if ($asyncCss) {
123
            $asyncCssOptions = [
124
                'media' => 'print',
125
                'onload' => "this.media='all'",
126
            ];
127
        }
128
        // Set the script args
129
        $scriptOptions = [
130
            'type' => 'module',
131
            'crossorigin' => true,
132
        ];
133
        if ($legacy) {
134
            $scriptOptions = [
135
                'nomodule' => true,
136
            ];
137
        }
138
        // Iterate through the manifest
139
        foreach (self::$manifest as $manifestKey => $entry) {
140
            // If it's not an entry, skip it
141
            if (!isset($entry['isEntry']) || !$entry['isEntry']) {
142
                continue;
143
            }
144
            // If there's no file, skip it
145
            if (!isset($entry['file'])) {
146
                continue;
147
            }
148
            // If the $path isn't in the $manifestKey, skip it
149
            if (strpos($manifestKey, $path) === false) {
150
                continue;
151
            }
152
            // Include the entry script
153
            $tagOptions = array_merge($scriptOptions, $scriptTagAttrs);
154
            $tags[$manifestKey] = [
155
                'type' => 'file',
156
                'url' => $entry['file'],
157
                'options' => $tagOptions
158
            ];
159
            // Include any imports
160
            $importFiles = [];
161
            // Only include import tags for the non-legacy scripts
162
            if (!$legacy) {
163
                self::extractImportFiles(self::$manifest, $manifestKey, $importFiles);
164
                foreach ($importFiles as $importFile) {
165
                    $tags[$importFile] = [
166
                        'crossorigin' => $tagOptions['crossorigin'] ?? true,
167
                        'type' => 'import',
168
                        'url' => $importFile,
169
                    ];
170
                }
171
            }
172
            // Include any CSS tags
173
            $cssFiles = [];
174
            self::extractCssFiles(self::$manifest, $manifestKey, $cssFiles);
175
            foreach ($cssFiles as $cssFile) {
176
                $tags[$cssFile] = [
177
                    'type' => 'css',
178
                    'url' => $cssFile,
179
                    'options' => array_merge([
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
180
                        'rel' => 'stylesheet',
181
                    ], $asyncCssOptions, $cssTagAttrs)
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
182
                ];
183
            }
184
        }
185
186
        return $tags;
187
    }
188
189
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $path should have a doc-comment as per coding-style.
Loading history...
190
     * Extract an entry file URL from all of the entries in the manifest
191
     *
192
     * @return string
193
     */
194
    public static function extractEntry(string $path): string
195
    {
196
        foreach (self::$manifest as $entryKey => $entry) {
197
            if (strpos($entryKey, $path) !== false) {
198
                return $entry['file'] ?? '';
199
            }
200
            // Check CSS
201
            $styles = $entry['css'] ?? [];
202
            foreach ($styles as $style) {
203
                $styleKey = self::filenameWithoutHash($style);
204
                if (strpos($styleKey, $path) !== false) {
205
                    return $style;
206
                }
207
            }
208
            // Check assets
209
            $assets = $entry['assets'] ?? [];
210
            foreach ($assets as $asset) {
211
                $assetKey = self::filenameWithoutHash($asset);
212
                if (strpos($assetKey, $path) !== false) {
213
                    return $asset;
214
                    }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 16 spaces, found 20
Loading history...
Coding Style introduced by
Line indented incorrectly; expected 16 spaces, found 20
Loading history...
215
                }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 12 spaces, found 16
Loading history...
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
216
            }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 8 spaces, found 12
Loading history...
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
217
218
        return '';
219
    }
220
221
    /**
222
     * Extract any asset files from all of the entries in the manifest
223
     *
224
     * @return array
225
     */
226
    public static function extractAssetFiles(): array
227
    {
228
        // Used the memoized version if available
229
        if (self::$assetFiles !== null) {
230
            return self::$assetFiles;
231
        }
232
        $assetFiles = [];
233
        foreach (self::$manifest as $entry) {
234
            $assets = $entry['assets'] ?? [];
235
            foreach ($assets as $asset) {
236
                $assetKey = self::filenameWithoutHash($asset);
237
                $assetFiles[$assetKey] = $asset;
238
            }
239
        }
240
        self::$assetFiles = $assetFiles;
241
242
        return $assetFiles;
243
    }
244
245
    // Protected Static Methods
246
    // =========================================================================
247
248
    /**
249
     * Return a file name from the passed in $path, with any version hash removed from it
250
     *
251
     * @param string $path
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
252
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
253
     */
254
    protected static function filenameWithoutHash(string $path): string
255
    {
256
        // Get just the file name
257
        $filenameParts = explode('/', $path);
258
        $filename = end($filenameParts);
259
        // If there is a version hash, remove it
260
        $filenameParts = explode('.', $filename);
261
        $dotSegments = count($filenameParts);
262
        if ($dotSegments > 2) {
263
            unset($filenameParts[$dotSegments - 2]);
264
            $filename = implode('.', $filenameParts);
265
        }
266
267
        return (string)$filename;
268
    }
269
270
    /**
271
     * Extract any import files from entries recursively
272
     *
273
     * @param array $manifest
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
274
     * @param string $manifestKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
275
     * @param array $importFiles
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
276
     *
277
     * @return array
278
     */
279
    protected static function extractImportFiles(array $manifest, string $manifestKey, array &$importFiles): array
280
    {
281
        $entry = $manifest[$manifestKey] ?? null;
282
        if (!$entry) {
283
            return [];
284
        }
285
286
        $imports = $entry['imports'] ?? [];
287
        foreach ($imports as $import) {
288
            $importFiles[] = $manifest[$import]['file'];
289
            self::extractImportFiles($manifest, $import, $importFiles);
290
        }
291
292
        return $importFiles;
293
    }
294
295
    /**
296
     * Extract any CSS files from entries recursively
297
     *
298
     * @param array $manifest
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
299
     * @param string $manifestKey
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
300
     * @param array $cssFiles
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
301
     *
302
     * @return array
303
     */
304
    protected static function extractCssFiles(array $manifest, string $manifestKey, array &$cssFiles): array
305
    {
306
        $entry = $manifest[$manifestKey] ?? null;
307
        if (!$entry) {
308
            return [];
309
        }
310
        $cssFiles = array_merge($cssFiles, $entry['css'] ?? []);
311
        $imports = $entry['imports'] ?? [];
312
        foreach ($imports as $import) {
313
            self::extractCssFiles($manifest, $import, $cssFiles);
314
        }
315
316
        return $cssFiles;
317
    }
318
}
319