@automattic/vip 2.22.0 → 2.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -13
- package/assets/dev-env.lando.template.yml.ejs +6 -1
- package/dist/bin/vip-app-list.js +0 -12
- package/dist/bin/vip-app.js +6 -13
- package/dist/bin/vip-cache-purge-url.js +4 -19
- package/dist/bin/vip-cache.js +0 -2
- package/dist/bin/vip-config-envvar-delete.js +4 -19
- package/dist/bin/vip-config-envvar-get-all.js +6 -19
- package/dist/bin/vip-config-envvar-get.js +4 -15
- package/dist/bin/vip-config-envvar-list.js +8 -20
- package/dist/bin/vip-config-envvar-set.js +4 -23
- package/dist/bin/vip-config-envvar.js +0 -2
- package/dist/bin/vip-config-software-get.js +0 -17
- package/dist/bin/vip-config-software-update.js +6 -22
- package/dist/bin/vip-config-software.js +0 -2
- package/dist/bin/vip-config.js +0 -2
- package/dist/bin/vip-dev-env-create.js +8 -21
- package/dist/bin/vip-dev-env-destroy.js +4 -11
- package/dist/bin/vip-dev-env-exec.js +4 -14
- package/dist/bin/vip-dev-env-import-media.js +3 -8
- package/dist/bin/vip-dev-env-import-sql.js +10 -23
- package/dist/bin/vip-dev-env-import.js +0 -3
- package/dist/bin/vip-dev-env-info.js +5 -13
- package/dist/bin/vip-dev-env-list.js +4 -9
- package/dist/bin/vip-dev-env-start.js +9 -17
- package/dist/bin/vip-dev-env-stop.js +4 -11
- package/dist/bin/vip-dev-env-update.js +4 -12
- package/dist/bin/vip-dev-env.js +0 -2
- package/dist/bin/vip-import-media-abort.js +0 -18
- package/dist/bin/vip-import-media-status.js +0 -12
- package/dist/bin/vip-import-media.js +6 -23
- package/dist/bin/vip-import-sql-status.js +0 -12
- package/dist/bin/vip-import-sql.js +33 -99
- package/dist/bin/vip-import-validate-files.js +21 -42
- package/dist/bin/vip-import-validate-sql.js +0 -8
- package/dist/bin/vip-import.js +0 -3
- package/dist/bin/vip-logs.js +20 -50
- package/dist/bin/vip-search-replace.js +8 -14
- package/dist/bin/vip-sync.js +2 -25
- package/dist/bin/vip-validate-preflight.js +467 -0
- package/dist/bin/vip-validate.js +19 -0
- package/dist/bin/vip-whoami.js +2 -14
- package/dist/bin/vip-wp.js +39 -89
- package/dist/bin/vip.js +14 -40
- package/dist/lib/analytics/clients/pendo.js +9 -18
- package/dist/lib/analytics/clients/stub.js +1 -3
- package/dist/lib/analytics/clients/tracks.js +11 -20
- package/dist/lib/analytics/index.js +4 -11
- package/dist/lib/api/app.js +1 -11
- package/dist/lib/api/cache-purge.js +4 -7
- package/dist/lib/api/feature-flags.js +1 -4
- package/dist/lib/api/http.js +9 -15
- package/dist/lib/api/user.js +1 -7
- package/dist/lib/api.js +7 -18
- package/dist/lib/app-logs/app-logs.js +2 -9
- package/dist/lib/app.js +2 -5
- package/dist/lib/cli/apiConfig.js +4 -19
- package/dist/lib/cli/command.js +43 -133
- package/dist/lib/cli/config.js +1 -5
- package/dist/lib/cli/envAlias.js +14 -15
- package/dist/lib/cli/exit.js +4 -6
- package/dist/lib/cli/format.js +8 -50
- package/dist/lib/cli/progress.js +13 -42
- package/dist/lib/cli/prompt.js +1 -5
- package/dist/lib/cli/repo.js +7 -20
- package/dist/lib/client-file-uploader.js +44 -97
- package/dist/lib/config/software.js +2 -52
- package/dist/lib/constants/dev-environment.js +1 -2
- package/dist/lib/constants/file-size.js +1 -1
- package/dist/lib/constants/vipgo.js +1 -1
- package/dist/lib/dev-environment/dev-environment-cli.js +140 -195
- package/dist/lib/dev-environment/dev-environment-core.js +91 -186
- package/dist/lib/dev-environment/dev-environment-lando.js +32 -96
- package/dist/lib/env.js +1 -4
- package/dist/lib/envvar/api-delete.js +1 -4
- package/dist/lib/envvar/api-get-all.js +1 -4
- package/dist/lib/envvar/api-get.js +1 -2
- package/dist/lib/envvar/api-list.js +3 -4
- package/dist/lib/envvar/api-set.js +1 -4
- package/dist/lib/envvar/api.js +5 -16
- package/dist/lib/envvar/input.js +1 -8
- package/dist/lib/envvar/logging.js +2 -6
- package/dist/lib/envvar/read-file.js +1 -3
- package/dist/lib/http/proxy-agent.js +17 -22
- package/dist/lib/keychain/browser.js +1 -4
- package/dist/lib/keychain/insecure.js +1 -10
- package/dist/lib/keychain/secure.js +1 -8
- package/dist/lib/keychain.js +4 -8
- package/dist/lib/logout.js +0 -6
- package/dist/lib/media-import/media-file-import.js +3 -7
- package/dist/lib/media-import/progress.js +6 -17
- package/dist/lib/media-import/status.js +14 -65
- package/dist/lib/read-file.js +1 -6
- package/dist/lib/rollbar.js +1 -7
- package/dist/lib/search-and-replace.js +9 -41
- package/dist/lib/site-import/db-file-import.js +3 -9
- package/dist/lib/site-import/status.js +17 -74
- package/dist/lib/token.js +1 -33
- package/dist/lib/tracker.js +4 -20
- package/dist/lib/user-error.js +0 -2
- package/dist/lib/validations/is-multi-site-sql-dump.js +4 -12
- package/dist/lib/validations/is-multi-site.js +5 -21
- package/dist/lib/validations/is-multisite-domain-mapped.js +5 -31
- package/dist/lib/validations/line-by-line.js +4 -16
- package/dist/lib/validations/site-type.js +10 -19
- package/dist/lib/validations/sql.js +11 -76
- package/dist/lib/validations/utils.js +1 -6
- package/dist/lib/vip-import-validate-files.js +82 -109
- package/npm-shrinkwrap.json +894 -357
- package/package.json +5 -2
|
@@ -3,62 +3,62 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.summaryLogs = exports.
|
|
7
|
-
|
|
6
|
+
exports.summaryLogs = exports.logErrorsForInvalidFilenames = exports.logErrorsForInvalidFileTypes = exports.logErrorsForIntermediateImages = exports.isFileSanitized = exports.folderStructureValidation = exports.findNestedDirectories = exports.doesImageHaveExistingSource = exports.acceptedExtensions = void 0;
|
|
8
7
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
9
|
-
|
|
10
8
|
var _fs = _interopRequireDefault(require("fs"));
|
|
11
|
-
|
|
12
9
|
var _path = _interopRequireDefault(require("path"));
|
|
13
|
-
|
|
14
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* External dependencies
|
|
18
14
|
*/
|
|
15
|
+
|
|
19
16
|
// Accepted media file extensions
|
|
20
17
|
const acceptedExtensions = ['jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'svg', 'tiff', 'tif', 'ico', 'asf', 'asx', 'wmv', 'wmx', 'wm', 'avi', 'divx', 'mov', 'qt', 'mpeg', 'mpg', 'mpe', 'mp4', 'm4v', 'ogv', 'webm', 'mkv', '3gp', '3gpp', '3g2', '3gp2', 'txt', 'asc', 'c', 'cc', 'h', 'srt', 'csv', 'tsv', 'ics', 'rtx', 'css', 'vtt', 'dfxp', 'mp3', 'm4a', 'm4b', 'ra', 'ram', 'wav', 'ogg', 'oga', 'mid', 'midi', 'wma', 'wax', 'mka', 'rtf', 'js', 'pdf', 'class', 'psd', 'xcf', 'doc', 'pot', 'pps', 'ppt', 'wri', 'xla', 'xls', 'xlt', 'xlw', 'mdb', 'mpp', 'docx', 'docm', 'dotx', 'dotm', 'xlsx', 'xlsm', 'xlsb', 'xltx', 'xltm', 'xlam', 'pptx', 'pptm', 'ppsx', 'ppsm', 'potx', 'potm', 'ppam', 'sldx', 'sldm', 'onetoc', ' onetoc2', 'onetmp', 'onepkg', 'oxps', 'xps', 'odt', 'odp', 'ods', 'odg', 'odc', 'odb', 'odf', 'webp', 'wp', 'wpd', 'key', 'numbers', 'pages'];
|
|
18
|
+
|
|
21
19
|
/**
|
|
22
20
|
* Character validation global variables
|
|
23
21
|
*
|
|
24
22
|
* Accepted and prohibited characters for filenames
|
|
25
23
|
*/
|
|
24
|
+
|
|
26
25
|
// Accepted characters in filenames
|
|
27
26
|
// eslint-disable-next-line max-len
|
|
28
|
-
|
|
29
27
|
exports.acceptedExtensions = acceptedExtensions;
|
|
30
28
|
const acceptedCharacters = ['Non-English characters', '(', ')', '[', ']', '~', '&', '#', '%', '=', '’', '\'', '×', '@', '`', '?', '*', '!', '\"', '\\', '<', '>', ':', ';', ',', '/', '$', '|', '`', '{', '}', 'spaces'];
|
|
31
29
|
const acceptedCharactersSet = new Set(acceptedCharacters); // Prevent duplicates with a Set
|
|
32
|
-
// Prohibited characters in filenames
|
|
33
30
|
|
|
31
|
+
// Prohibited characters in filenames
|
|
34
32
|
const prohibitedCharacters = ['+', '%20'];
|
|
35
33
|
const prohibitedCharactersSet = new Set(prohibitedCharacters);
|
|
34
|
+
|
|
36
35
|
/**
|
|
37
36
|
* Recommendations
|
|
38
37
|
*
|
|
39
38
|
* Recommend alternatives to invalid folders or files
|
|
40
39
|
*/
|
|
41
|
-
// Recommend the WordPress year/month file structure for media files
|
|
42
40
|
|
|
41
|
+
// Recommend the WordPress year/month file structure for media files
|
|
43
42
|
const recommendedFileStructure = () => {
|
|
44
43
|
console.log(_chalk.default.underline('We recommend the WordPress default folder structure for your media files: \n\n') + _chalk.default.underline('Single sites:') + _chalk.default.yellow('`uploads/year/month/image.png`\n') + ' e.g.-' + _chalk.default.yellow('`uploads/2020/06/image.png`\n') + _chalk.default.underline('Multisites:') + _chalk.default.cyan('`uploads/sites/siteID/year/month/image.png`\n') + ' e.g.-' + _chalk.default.cyan('`uploads/sites/5/2020/06/images.png`\n'));
|
|
45
44
|
console.log('------------------------------------------------------------');
|
|
46
45
|
console.log();
|
|
47
|
-
};
|
|
48
|
-
|
|
46
|
+
};
|
|
49
47
|
|
|
48
|
+
// Recommend accepted file types
|
|
50
49
|
const recommendAcceptableFileTypes = () => {
|
|
51
50
|
console.log('Accepted file types: \n\n' + _chalk.default.magenta(`${acceptedExtensions}`));
|
|
52
51
|
console.log();
|
|
53
|
-
};
|
|
54
|
-
|
|
52
|
+
};
|
|
55
53
|
|
|
54
|
+
// Accepted file name characters
|
|
56
55
|
const recommendAcceptableFileNames = () => {
|
|
57
56
|
// const acceptedCharacters = 'Non-English characters, spaces, ( ) [ ] ~';
|
|
58
57
|
const allowedCharacters = [...acceptedCharactersSet].join(' ');
|
|
59
58
|
const notAllowedCharacters = [...prohibitedCharactersSet].join(' ');
|
|
60
59
|
console.log('The following characters are allowed in file names:\n' + _chalk.default.green(`All special characters, including: ${allowedCharacters}\n\n`) + 'The following characters are prohibited in file names:\n' + _chalk.default.red(`Encoded or alternate whitespace, such as ${notAllowedCharacters}, are converted to proper spaces\n`));
|
|
61
60
|
};
|
|
61
|
+
|
|
62
62
|
/**
|
|
63
63
|
* Nested Directory Search
|
|
64
64
|
*
|
|
@@ -72,34 +72,30 @@ const recommendAcceptableFileNames = () => {
|
|
|
72
72
|
*
|
|
73
73
|
* @param {string} directory Root directory, or the given (current) directory
|
|
74
74
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
77
75
|
const files = [];
|
|
78
76
|
const folderStructureObj = {};
|
|
79
|
-
|
|
80
77
|
const findNestedDirectories = directory => {
|
|
81
78
|
let nestedDirectories;
|
|
82
|
-
|
|
83
79
|
try {
|
|
84
80
|
// Read nested directories within the given directory
|
|
85
|
-
nestedDirectories = _fs.default.readdirSync(directory);
|
|
81
|
+
nestedDirectories = _fs.default.readdirSync(directory);
|
|
86
82
|
|
|
83
|
+
// Filter out hidden files such as .DS_Store
|
|
87
84
|
nestedDirectories = nestedDirectories.filter(file => !/(^|\/)\.[^\/\.]/g.test(file));
|
|
88
85
|
nestedDirectories.forEach(dir => {
|
|
89
86
|
// Concatenate the file path of the parent directory with the nested directory
|
|
90
87
|
const filePath = _path.default.join(directory, dir);
|
|
91
|
-
|
|
92
88
|
const statSync = _fs.default.statSync(filePath); // Get stats on the file/folder
|
|
93
|
-
// Keep looking for nested directories until we hit individual files
|
|
94
|
-
|
|
95
89
|
|
|
90
|
+
// Keep looking for nested directories until we hit individual files
|
|
96
91
|
if (statSync.isDirectory()) {
|
|
97
92
|
findNestedDirectories(filePath);
|
|
98
93
|
} else {
|
|
99
94
|
// Once we hit media files, add the path of all existing folders
|
|
100
95
|
// as object keys to validate folder structure later on
|
|
101
|
-
folderStructureObj[directory] = true;
|
|
96
|
+
folderStructureObj[directory] = true;
|
|
102
97
|
|
|
98
|
+
// Also, push individual files to an array to do individual file validations later on
|
|
103
99
|
return files.push(filePath);
|
|
104
100
|
}
|
|
105
101
|
});
|
|
@@ -107,12 +103,12 @@ const findNestedDirectories = directory => {
|
|
|
107
103
|
console.error(_chalk.default.red('✕'), ` Error: Cannot read nested directory: ${directory}. Reason: ${error.message}`);
|
|
108
104
|
return;
|
|
109
105
|
}
|
|
110
|
-
|
|
111
106
|
return {
|
|
112
107
|
files,
|
|
113
108
|
folderStructureObj
|
|
114
109
|
};
|
|
115
110
|
};
|
|
111
|
+
|
|
116
112
|
/**
|
|
117
113
|
* Folder structure validation
|
|
118
114
|
*
|
|
@@ -122,30 +118,27 @@ const findNestedDirectories = directory => {
|
|
|
122
118
|
* @param {Boolean} sites Check if site is a multisite or single site
|
|
123
119
|
* @return {Object} indexes
|
|
124
120
|
*/
|
|
125
|
-
|
|
126
|
-
|
|
127
121
|
exports.findNestedDirectories = findNestedDirectories;
|
|
128
|
-
|
|
129
122
|
const getIndexPositionOfFolders = (folderPath, sites) => {
|
|
130
123
|
let sitesIndex, siteIDIndex, yearIndex, monthIndex;
|
|
131
124
|
let pathMutate = folderPath; // Mutate `path` for multisites
|
|
132
|
-
// Turn the path into an array to determine index position
|
|
133
125
|
|
|
126
|
+
// Turn the path into an array to determine index position
|
|
134
127
|
const directories = pathMutate.split('/');
|
|
128
|
+
|
|
135
129
|
/**
|
|
136
130
|
* Upload folder
|
|
137
131
|
*
|
|
138
132
|
* Find if an `uploads` folder exists and return its index position
|
|
139
133
|
*/
|
|
140
|
-
|
|
141
134
|
const uploadsIndex = directories.indexOf('uploads');
|
|
135
|
+
|
|
142
136
|
/**
|
|
143
137
|
* Multisite folder
|
|
144
138
|
*
|
|
145
139
|
* If a sites directory exists, find the directory and return its index position
|
|
146
140
|
* Find if a siteID folder exists via regex, then obtain that value
|
|
147
141
|
*/
|
|
148
|
-
|
|
149
142
|
if (sites) {
|
|
150
143
|
sitesIndex = directories.indexOf('sites');
|
|
151
144
|
const regexSiteID = /\/sites\/(\d+)/g;
|
|
@@ -153,42 +146,40 @@ const getIndexPositionOfFolders = (folderPath, sites) => {
|
|
|
153
146
|
|
|
154
147
|
if (siteID) {
|
|
155
148
|
siteIDIndex = directories.indexOf(siteID[1]);
|
|
156
|
-
}
|
|
157
|
-
// e.g.- `uploads/sites/11/2020/06` -> `uploads/2020/06`
|
|
158
|
-
|
|
149
|
+
}
|
|
159
150
|
|
|
151
|
+
// Remove the multisite-specific path to avoid confusing a 2 digit site ID with the month
|
|
152
|
+
// e.g.- `uploads/sites/11/2020/06` -> `uploads/2020/06`
|
|
160
153
|
pathMutate = pathMutate.replace(siteID[0], '');
|
|
161
154
|
}
|
|
155
|
+
|
|
162
156
|
/**
|
|
163
157
|
* Year folder
|
|
164
158
|
*
|
|
165
159
|
* Find if a year folder exists via a four digit regex matching pattern,
|
|
166
160
|
* then obtain that value
|
|
167
161
|
*/
|
|
168
|
-
|
|
169
|
-
|
|
170
162
|
const regexYear = /\b\d{4}\b/g;
|
|
171
163
|
const year = regexYear.exec(pathMutate); // Returns an array with the regex-matching value
|
|
172
164
|
|
|
173
165
|
if (year) {
|
|
174
166
|
yearIndex = directories.indexOf(year[0]);
|
|
175
167
|
}
|
|
168
|
+
|
|
176
169
|
/**
|
|
177
170
|
* Month folder
|
|
178
171
|
*
|
|
179
172
|
* Find if a month folder exists via a two digit regex matching pattern,
|
|
180
173
|
* then obtain that value
|
|
181
174
|
*/
|
|
182
|
-
|
|
183
|
-
|
|
184
175
|
const regexMonth = /\b\d{2}\b/g;
|
|
185
176
|
const month = regexMonth.exec(pathMutate); // Returns an array with the regex-matching value
|
|
186
177
|
|
|
187
178
|
if (month) {
|
|
188
179
|
monthIndex = directories.indexOf(month[0]);
|
|
189
|
-
}
|
|
190
|
-
|
|
180
|
+
}
|
|
191
181
|
|
|
182
|
+
// Multisite
|
|
192
183
|
if (sites) {
|
|
193
184
|
return {
|
|
194
185
|
uploadsIndex,
|
|
@@ -197,15 +188,16 @@ const getIndexPositionOfFolders = (folderPath, sites) => {
|
|
|
197
188
|
yearIndex,
|
|
198
189
|
monthIndex
|
|
199
190
|
};
|
|
200
|
-
}
|
|
201
|
-
|
|
191
|
+
}
|
|
202
192
|
|
|
193
|
+
// Single site
|
|
203
194
|
return {
|
|
204
195
|
uploadsIndex,
|
|
205
196
|
yearIndex,
|
|
206
197
|
monthIndex
|
|
207
198
|
};
|
|
208
199
|
};
|
|
200
|
+
|
|
209
201
|
/**
|
|
210
202
|
* Single site folder structure validation
|
|
211
203
|
*
|
|
@@ -218,23 +210,23 @@ const getIndexPositionOfFolders = (folderPath, sites) => {
|
|
|
218
210
|
* @param {string} folderPath Path of the entire folder structure
|
|
219
211
|
* @returns {string|null} Returns null if the folder structure is good; else, returns the folder path
|
|
220
212
|
*/
|
|
221
|
-
|
|
222
|
-
|
|
223
213
|
const singleSiteValidation = folderPath => {
|
|
224
214
|
let errors = 0; // Tally individual folder errors
|
|
225
215
|
|
|
226
|
-
console.log(_chalk.default.bold('Folder:'), _chalk.default.cyan(`${folderPath}`));
|
|
216
|
+
console.log(_chalk.default.bold('Folder:'), _chalk.default.cyan(`${folderPath}`));
|
|
227
217
|
|
|
218
|
+
// Use destructuring to retrieve the index position of each folder
|
|
228
219
|
const {
|
|
229
220
|
uploadsIndex,
|
|
230
221
|
yearIndex,
|
|
231
222
|
monthIndex
|
|
232
223
|
} = getIndexPositionOfFolders(folderPath);
|
|
224
|
+
|
|
233
225
|
/**
|
|
234
226
|
* Logging
|
|
235
227
|
*/
|
|
236
|
-
// Uploads folder
|
|
237
228
|
|
|
229
|
+
// Uploads folder
|
|
238
230
|
if (uploadsIndex === 0) {
|
|
239
231
|
console.log();
|
|
240
232
|
console.log('✅ File structure: Uploads directory exists');
|
|
@@ -242,17 +234,17 @@ const singleSiteValidation = folderPath => {
|
|
|
242
234
|
console.log();
|
|
243
235
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Media files should reside in an', _chalk.default.magenta('`uploads`'), 'directory');
|
|
244
236
|
errors++;
|
|
245
|
-
}
|
|
246
|
-
|
|
237
|
+
}
|
|
247
238
|
|
|
239
|
+
// Year folder
|
|
248
240
|
if (yearIndex && yearIndex === 1) {
|
|
249
241
|
console.log('✅ File structure: Year directory exists (format: YYYY)');
|
|
250
242
|
} else {
|
|
251
243
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Structure your WordPress media files into', _chalk.default.magenta('`uploads/YYYY`'), 'directories');
|
|
252
244
|
errors++;
|
|
253
|
-
}
|
|
254
|
-
|
|
245
|
+
}
|
|
255
246
|
|
|
247
|
+
// Month folder
|
|
256
248
|
if (monthIndex && monthIndex === 2) {
|
|
257
249
|
console.log('✅ File structure: Month directory exists (format: MM)');
|
|
258
250
|
console.log();
|
|
@@ -260,15 +252,15 @@ const singleSiteValidation = folderPath => {
|
|
|
260
252
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Structure your WordPress media files into', _chalk.default.magenta('`uploads/YYYY/MM`'), 'directories');
|
|
261
253
|
console.log();
|
|
262
254
|
errors++;
|
|
263
|
-
}
|
|
264
|
-
|
|
255
|
+
}
|
|
265
256
|
|
|
257
|
+
// Push individual folder errors to the collective array of errors
|
|
266
258
|
if (errors > 0) {
|
|
267
259
|
return folderPath;
|
|
268
260
|
}
|
|
269
|
-
|
|
270
261
|
return null;
|
|
271
262
|
};
|
|
263
|
+
|
|
272
264
|
/**
|
|
273
265
|
* Multisite folder structure validation
|
|
274
266
|
*
|
|
@@ -282,13 +274,12 @@ const singleSiteValidation = folderPath => {
|
|
|
282
274
|
* @param {string} folderPath Path of the entire folder structure
|
|
283
275
|
* @returns {string|null} Returns null if the folder structure is good; else, returns the folder path
|
|
284
276
|
*/
|
|
285
|
-
|
|
286
|
-
|
|
287
277
|
const multiSiteValidation = folderPath => {
|
|
288
278
|
let errors = 0; // Tally individual folder errors
|
|
289
279
|
|
|
290
|
-
console.log(_chalk.default.bold('Folder:'), _chalk.default.cyan(`${folderPath}`));
|
|
280
|
+
console.log(_chalk.default.bold('Folder:'), _chalk.default.cyan(`${folderPath}`));
|
|
291
281
|
|
|
282
|
+
// Use destructuring to retrieve the index position of each folder
|
|
292
283
|
const {
|
|
293
284
|
uploadsIndex,
|
|
294
285
|
sitesIndex,
|
|
@@ -296,11 +287,12 @@ const multiSiteValidation = folderPath => {
|
|
|
296
287
|
yearIndex,
|
|
297
288
|
monthIndex
|
|
298
289
|
} = getIndexPositionOfFolders(folderPath, true);
|
|
290
|
+
|
|
299
291
|
/**
|
|
300
292
|
* Logging
|
|
301
293
|
*/
|
|
302
|
-
// Uploads folder
|
|
303
294
|
|
|
295
|
+
// Uploads folder
|
|
304
296
|
if (uploadsIndex === 0) {
|
|
305
297
|
console.log();
|
|
306
298
|
console.log('✅ File structure: Uploads directory exists');
|
|
@@ -308,34 +300,34 @@ const multiSiteValidation = folderPath => {
|
|
|
308
300
|
console.log();
|
|
309
301
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Media files should reside in an', _chalk.default.magenta('`uploads`'), 'directory');
|
|
310
302
|
errors++;
|
|
311
|
-
}
|
|
312
|
-
|
|
303
|
+
}
|
|
313
304
|
|
|
305
|
+
// Sites folder
|
|
314
306
|
if (sitesIndex === 1) {
|
|
315
307
|
console.log('✅ File structure: Sites directory exists');
|
|
316
308
|
} else {
|
|
317
309
|
console.log();
|
|
318
310
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Media files should reside in an', _chalk.default.magenta('`sites`'), 'directory');
|
|
319
311
|
errors++;
|
|
320
|
-
}
|
|
321
|
-
|
|
312
|
+
}
|
|
322
313
|
|
|
314
|
+
// Site ID folder
|
|
323
315
|
if (siteIDIndex && siteIDIndex === 2) {
|
|
324
316
|
console.log('✅ File structure: Site ID directory exists');
|
|
325
317
|
} else {
|
|
326
318
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Structure your WordPress media files into', _chalk.default.magenta('`uploads/sites/<siteID>`'), 'directories');
|
|
327
319
|
errors++;
|
|
328
|
-
}
|
|
329
|
-
|
|
320
|
+
}
|
|
330
321
|
|
|
322
|
+
// Year folder
|
|
331
323
|
if (yearIndex && yearIndex === 3) {
|
|
332
324
|
console.log('✅ File structure: Year directory exists (format: YYYY)');
|
|
333
325
|
} else {
|
|
334
326
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Structure your WordPress media files into', _chalk.default.magenta('`uploads/sites/<siteID>/YYYY`'), 'directories');
|
|
335
327
|
errors++;
|
|
336
|
-
}
|
|
337
|
-
|
|
328
|
+
}
|
|
338
329
|
|
|
330
|
+
// Month folder
|
|
339
331
|
if (monthIndex && monthIndex === 4) {
|
|
340
332
|
console.log('✅ File structure: Month directory exists (format: MM)');
|
|
341
333
|
console.log();
|
|
@@ -343,15 +335,15 @@ const multiSiteValidation = folderPath => {
|
|
|
343
335
|
console.log(_chalk.default.yellow('✕'), 'Recommended: Structure your WordPress media files into', _chalk.default.magenta('`uploads/sites/<siteID>/YYYY/MM`'), 'directories');
|
|
344
336
|
console.log();
|
|
345
337
|
errors++;
|
|
346
|
-
}
|
|
347
|
-
|
|
338
|
+
}
|
|
348
339
|
|
|
340
|
+
// Push individual folder errors to the collective array of errors
|
|
349
341
|
if (errors > 0) {
|
|
350
342
|
return folderPath;
|
|
351
343
|
}
|
|
352
|
-
|
|
353
344
|
return null;
|
|
354
345
|
};
|
|
346
|
+
|
|
355
347
|
/**
|
|
356
348
|
* Folder structure validation
|
|
357
349
|
*
|
|
@@ -360,15 +352,15 @@ const multiSiteValidation = folderPath => {
|
|
|
360
352
|
* @param {Array} folderStructureKeys Array of paths for each folder
|
|
361
353
|
* @return {Array} All the erroneous folder paths in an array
|
|
362
354
|
*/
|
|
363
|
-
|
|
364
|
-
|
|
365
355
|
const folderStructureValidation = folderStructureKeys => {
|
|
366
356
|
// Collect all the folder paths that aren't in the recommended structure
|
|
367
|
-
const allErrors = [];
|
|
357
|
+
const allErrors = [];
|
|
368
358
|
|
|
359
|
+
// Loop through each path to validate the folder structure format
|
|
369
360
|
for (const folderPath of folderStructureKeys) {
|
|
370
|
-
let badFolders;
|
|
361
|
+
let badFolders;
|
|
371
362
|
|
|
363
|
+
// Check for multisite folder structure
|
|
372
364
|
if (folderPath.search('sites') !== -1) {
|
|
373
365
|
// Returns null if the folder path is good, otherwise it returns the folder path itself
|
|
374
366
|
badFolders = multiSiteValidation(folderPath);
|
|
@@ -376,18 +368,16 @@ const folderStructureValidation = folderStructureKeys => {
|
|
|
376
368
|
// Returns null if the folder path is good, otherwise it returns the folder path itself
|
|
377
369
|
badFolders = singleSiteValidation(folderPath);
|
|
378
370
|
}
|
|
379
|
-
|
|
380
371
|
if (badFolders) {
|
|
381
372
|
allErrors.push(badFolders);
|
|
382
373
|
}
|
|
383
374
|
}
|
|
384
|
-
|
|
385
375
|
if (allErrors.length > 0) {
|
|
386
376
|
recommendedFileStructure();
|
|
387
377
|
}
|
|
388
|
-
|
|
389
378
|
return allErrors;
|
|
390
379
|
};
|
|
380
|
+
|
|
391
381
|
/**
|
|
392
382
|
* Character validation
|
|
393
383
|
*
|
|
@@ -397,22 +387,21 @@ const folderStructureValidation = folderStructureKeys => {
|
|
|
397
387
|
* @param {string} file - The current file being validated
|
|
398
388
|
* @returns {Boolean} - Checks if the filename has been sanitized
|
|
399
389
|
*/
|
|
400
|
-
|
|
401
|
-
|
|
402
390
|
exports.folderStructureValidation = folderStructureValidation;
|
|
403
|
-
|
|
404
391
|
const isFileSanitized = file => {
|
|
405
392
|
const filename = _path.default.basename(file);
|
|
393
|
+
let sanitizedFile = filename;
|
|
406
394
|
|
|
407
|
-
|
|
395
|
+
// Convert encoded or alternate whitespace into a proper space
|
|
408
396
|
// Encoded spaces (%20), no-break spaces - keeps words together (\u00A0), and plus signs
|
|
409
|
-
|
|
410
397
|
const regexSpaces = /\u00A0|(%20)|\+/g;
|
|
411
|
-
sanitizedFile = sanitizedFile.replace(regexSpaces, ' ');
|
|
398
|
+
sanitizedFile = sanitizedFile.replace(regexSpaces, ' ');
|
|
412
399
|
|
|
400
|
+
// Check if the filename has been sanitized
|
|
413
401
|
const checkFile = sanitizedFile !== filename;
|
|
414
402
|
return checkFile;
|
|
415
403
|
};
|
|
404
|
+
|
|
416
405
|
/**
|
|
417
406
|
* Intermediate image validation
|
|
418
407
|
*
|
|
@@ -427,53 +416,47 @@ const isFileSanitized = file => {
|
|
|
427
416
|
* @param {string} filename The current file being validated
|
|
428
417
|
* @returns {Array} Returns an array of the matching regex characters
|
|
429
418
|
*/
|
|
430
|
-
|
|
431
|
-
|
|
432
419
|
exports.isFileSanitized = isFileSanitized;
|
|
433
|
-
|
|
434
420
|
const identifyIntermediateImage = filename => {
|
|
435
421
|
const regex = /(-|_)?(\d+x\d+)(@\d+\w)?(\.\w{3,4})$/;
|
|
436
422
|
return filename.match(regex);
|
|
437
|
-
};
|
|
438
|
-
|
|
423
|
+
};
|
|
439
424
|
|
|
425
|
+
// Check if an intermediate image has an existing original (source) image
|
|
440
426
|
const doesImageHaveExistingSource = file => {
|
|
441
|
-
const filename = _path.default.basename(file);
|
|
442
|
-
|
|
427
|
+
const filename = _path.default.basename(file);
|
|
443
428
|
|
|
429
|
+
// Intermediate image regex check
|
|
444
430
|
const intermediateImage = identifyIntermediateImage(filename);
|
|
445
|
-
|
|
446
431
|
if (null !== intermediateImage) {
|
|
447
432
|
const imageSizing = intermediateImage[0]; // First capture group of the regex validation
|
|
448
|
-
|
|
449
433
|
const extension = _path.default.extname(filename).substr(1); // Extension of the path (e.g.- `.jpg`)
|
|
434
|
+
|
|
450
435
|
// Filename manipulation: if an image is an intermediate image, strip away the image sizing
|
|
451
436
|
// e.g.- `panda4000x6000.png` -> `panda.png`
|
|
452
|
-
|
|
453
|
-
|
|
454
437
|
const baseFileName = filename.replace(imageSizing, '') + '.' + extension;
|
|
455
|
-
const splitFolder = file.split('/');
|
|
438
|
+
const splitFolder = file.split('/');
|
|
456
439
|
|
|
440
|
+
// Remove the last element (intermediate image filename) and replace it with the original image filename
|
|
457
441
|
splitFolder.splice(splitFolder.length - 1, 1, baseFileName);
|
|
458
|
-
const originalImage = splitFolder.join('/');
|
|
442
|
+
const originalImage = splitFolder.join('/');
|
|
459
443
|
|
|
444
|
+
// Check if an image with the same path + name (the original) already exists
|
|
460
445
|
if (_fs.default.existsSync(originalImage)) {
|
|
461
446
|
return originalImage;
|
|
462
447
|
}
|
|
463
|
-
|
|
464
448
|
return false;
|
|
465
449
|
}
|
|
466
450
|
};
|
|
451
|
+
|
|
467
452
|
/**
|
|
468
453
|
* Error logging
|
|
469
454
|
*
|
|
470
455
|
* Log errors for invalid folders or files
|
|
471
456
|
*/
|
|
472
|
-
// Log errors for files with invalid file extensions and recommend accepted file types
|
|
473
|
-
|
|
474
457
|
|
|
458
|
+
// Log errors for files with invalid file extensions and recommend accepted file types
|
|
475
459
|
exports.doesImageHaveExistingSource = doesImageHaveExistingSource;
|
|
476
|
-
|
|
477
460
|
const logErrorsForInvalidFileTypes = invalidFiles => {
|
|
478
461
|
invalidFiles.map(file => {
|
|
479
462
|
console.error(_chalk.default.red('✕'), 'File extensions: Invalid file type for file: ', _chalk.default.cyan(`${file}`));
|
|
@@ -482,11 +465,10 @@ const logErrorsForInvalidFileTypes = invalidFiles => {
|
|
|
482
465
|
recommendAcceptableFileTypes();
|
|
483
466
|
console.log('------------------------------------------------------------');
|
|
484
467
|
console.log();
|
|
485
|
-
};
|
|
486
|
-
|
|
468
|
+
};
|
|
487
469
|
|
|
470
|
+
// Log errors for files with invalid filenames and show a list of accepted/prohibited chars
|
|
488
471
|
exports.logErrorsForInvalidFileTypes = logErrorsForInvalidFileTypes;
|
|
489
|
-
|
|
490
472
|
const logErrorsForInvalidFilenames = invalidFiles => {
|
|
491
473
|
invalidFiles.map(file => {
|
|
492
474
|
console.error(_chalk.default.red('✕'), 'Character validation: Invalid filename for file: ', _chalk.default.cyan(`${file}`));
|
|
@@ -495,21 +477,17 @@ const logErrorsForInvalidFilenames = invalidFiles => {
|
|
|
495
477
|
recommendAcceptableFileNames();
|
|
496
478
|
console.log('------------------------------------------------------------');
|
|
497
479
|
console.log();
|
|
498
|
-
};
|
|
499
|
-
|
|
480
|
+
};
|
|
500
481
|
|
|
482
|
+
// Log errors for intermediate image file duplicates
|
|
501
483
|
exports.logErrorsForInvalidFilenames = logErrorsForInvalidFilenames;
|
|
502
|
-
|
|
503
484
|
const logErrorsForIntermediateImages = obj => {
|
|
504
485
|
for (const original in obj) {
|
|
505
486
|
console.error(_chalk.default.red('✕'), 'Intermediate images: Duplicate files found:\n' + 'Original file: ' + _chalk.default.blue(`${original}\n`) + 'Intermediate images: ' + _chalk.default.cyan(`${obj[original]}\n`));
|
|
506
487
|
}
|
|
507
|
-
|
|
508
488
|
console.log('------------------------------------------------------------');
|
|
509
489
|
};
|
|
510
|
-
|
|
511
490
|
exports.logErrorsForIntermediateImages = logErrorsForIntermediateImages;
|
|
512
|
-
|
|
513
491
|
const summaryLogs = ({
|
|
514
492
|
folderErrorsLength,
|
|
515
493
|
intImagesErrorsLength,
|
|
@@ -523,26 +501,21 @@ const summaryLogs = ({
|
|
|
523
501
|
} else {
|
|
524
502
|
folderErrorsLength = _chalk.default.bgGreen(' PASS ') + _chalk.default.bold.green(` ${totalFolders} folders, `) + `${totalFolders} folders total`;
|
|
525
503
|
}
|
|
526
|
-
|
|
527
504
|
if (intImagesErrorsLength > 0) {
|
|
528
505
|
intImagesErrorsLength = _chalk.default.white.bgRed(' ERROR ') + _chalk.default.red(` ${intImagesErrorsLength} intermediate images`) + `, ${totalFiles} files total`;
|
|
529
506
|
} else {
|
|
530
507
|
intImagesErrorsLength = _chalk.default.white.bgGreen(' PASS ') + _chalk.default.green(` ${intImagesErrorsLength} intermediate images`) + `, ${totalFiles} files total`;
|
|
531
508
|
}
|
|
532
|
-
|
|
533
509
|
if (fileTypeErrorsLength > 0) {
|
|
534
510
|
fileTypeErrorsLength = _chalk.default.white.bgRed(' ERROR ') + _chalk.default.red(` ${fileTypeErrorsLength} invalid file extensions`) + `, ${totalFiles} files total`;
|
|
535
511
|
} else {
|
|
536
512
|
fileTypeErrorsLength = _chalk.default.white.bgGreen(' PASS ') + _chalk.default.green(` ${fileTypeErrorsLength} invalid file extensions`) + `, ${totalFiles} files total`;
|
|
537
513
|
}
|
|
538
|
-
|
|
539
514
|
if (filenameErrorsLength) {
|
|
540
515
|
filenameErrorsLength = _chalk.default.white.bgRed(' ERROR ') + _chalk.default.red(` ${filenameErrorsLength} invalid filenames`) + `, ${totalFiles} files total`;
|
|
541
516
|
} else {
|
|
542
517
|
filenameErrorsLength = _chalk.default.bgGreen(' PASS ') + _chalk.default.green(` ${filenameErrorsLength} invalid filenames`) + `, ${totalFiles} files total`;
|
|
543
518
|
}
|
|
544
|
-
|
|
545
519
|
console.log(`\n${folderErrorsLength}\n${intImagesErrorsLength}\n${fileTypeErrorsLength}\n${filenameErrorsLength}\n`);
|
|
546
520
|
};
|
|
547
|
-
|
|
548
521
|
exports.summaryLogs = summaryLogs;
|