@metricinsights/pp-dev 0.9.0 → 0.10.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/README.md +146 -229
  3. package/dist/cjs/cli.js +1 -1200
  4. package/dist/cjs/cli.js.map +1 -1
  5. package/dist/cjs/helpers.js +1 -28
  6. package/dist/cjs/helpers.js.map +1 -1
  7. package/dist/cjs/index-7kvqDDBw.js +2 -0
  8. package/dist/cjs/index-7kvqDDBw.js.map +1 -0
  9. package/dist/cjs/index.js +1 -26
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/package.json +10 -7
  12. package/dist/cjs/plugin-CoHlzIq-.js +2 -0
  13. package/dist/cjs/plugin-CoHlzIq-.js.map +1 -0
  14. package/dist/cjs/plugin.js +1 -25
  15. package/dist/cjs/plugin.js.map +1 -1
  16. package/dist/client/client.css +233 -38
  17. package/dist/client/client.css.map +1 -0
  18. package/dist/client/client.js +110 -14
  19. package/dist/client/client.js.map +1 -1
  20. package/dist/client/index.html +39 -26
  21. package/dist/esm/cli.js +1 -1173
  22. package/dist/esm/cli.js.map +1 -1
  23. package/dist/esm/helpers.js +1 -24
  24. package/dist/esm/helpers.js.map +1 -1
  25. package/dist/esm/index-C2GV98GH.js +2 -0
  26. package/dist/esm/index-C2GV98GH.js.map +1 -0
  27. package/dist/esm/index.js +1 -19
  28. package/dist/esm/index.js.map +1 -1
  29. package/dist/esm/package.json +10 -7
  30. package/dist/esm/plugin-B909lge8.js +2 -0
  31. package/dist/esm/plugin-B909lge8.js.map +1 -0
  32. package/dist/esm/plugin.js +1 -16
  33. package/dist/esm/plugin.js.map +1 -1
  34. package/dist/types/index.d.ts +102 -2
  35. package/package.json +10 -7
  36. package/dist/cjs/index-BE4YF5iw.js +0 -331
  37. package/dist/cjs/index-BE4YF5iw.js.map +0 -1
  38. package/dist/cjs/plugin-DZS4Taov.js +0 -1315
  39. package/dist/cjs/plugin-DZS4Taov.js.map +0 -1
  40. package/dist/client/index.d.ts +0 -2
  41. package/dist/esm/index-7YgmP5z7.js +0 -308
  42. package/dist/esm/index-7YgmP5z7.js.map +0 -1
  43. package/dist/esm/plugin-BeHiwpzF.js +0 -1277
  44. package/dist/esm/plugin-BeHiwpzF.js.map +0 -1
  45. package/dist/types/cli.d.ts +0 -3
  46. package/dist/types/helpers.d.ts +0 -24
  47. package/dist/types/plugin.d.ts +0 -86
package/dist/esm/cli.js CHANGED
@@ -1,1174 +1,2 @@
1
- import * as path from 'path';
2
- import * as fs from 'fs';
3
- import { performance } from 'node:perf_hooks';
4
- import { cac } from 'cac';
5
- import { g as getViteConfig, V as VERSION } from './index-7YgmP5z7.js';
6
- import { c as createLogger, a as colors, i as initPPRedirect, M as MiAPI, b as initProxyCache, d as initProxy, e as initLoadPPData, f as initRewriteResponse, u as urlReplacer, g as cutUrlParams } from './plugin-BeHiwpzF.js';
7
- import { loadConfigFromFile, mergeConfig, build, resolveConfig, optimizeDeps, preview } from 'vite';
8
- import { URL as URL$1, parse } from 'url';
9
- import * as express from 'express';
10
- import * as winston from 'winston';
11
- import * as dirCompare from 'dir-compare';
12
- import DiffMatchPatch from 'diff-match-patch';
13
- import { isBinaryFile } from 'isbinaryfile';
14
- import * as os from 'os';
15
- import * as crypto from 'crypto';
16
- import extractZip from 'extract-zip';
17
- import svgToFont from 'svgtofont';
18
- import 'ejs';
19
- import 'esbuild';
20
- import 'http-proxy-middleware';
21
- import 'picocolors';
22
- import 'axios';
23
- import 'jsdom';
24
- import 'https';
25
- import 'memory-cache';
26
- import 'process';
27
- import 'child_process';
28
- import 'console';
29
- import 'zlib';
30
-
31
- function isDefined(value) {
32
- return value != null;
33
- }
34
- function bindShortcuts(server, opts) {
35
- if (!server.httpServer || !process.stdin.isTTY || process.env.CI) {
36
- return;
37
- }
38
- server._shortcutsOptions = opts;
39
- const logger = createLogger();
40
- if (opts.print) {
41
- logger.info(colors.dim(colors.green(' ➜')) + colors.dim(' press ') + colors.bold('h') + colors.dim(' to show help'));
42
- }
43
- const shortcuts = (opts.customShortcuts ?? []).filter(isDefined).concat(BASE_SHORTCUTS);
44
- let actionRunning = false;
45
- const onInput = async (input) => {
46
- // ctrl+c or ctrl+d
47
- if (input === '\x03' || input === '\x04') {
48
- await server.close().finally(() => process.exit(1));
49
- return;
50
- }
51
- if (actionRunning) {
52
- return;
53
- }
54
- if (input === 'h') {
55
- logger.info([
56
- '',
57
- colors.bold(' Shortcuts'),
58
- ...shortcuts.map((shortcut) => colors.dim(' press ') + colors.bold(shortcut.key) + colors.dim(` to ${shortcut.description}`)),
59
- ].join('\n'));
60
- }
61
- const shortcut = shortcuts.find((shortcut) => shortcut.key === input);
62
- if (!shortcut) {
63
- return;
64
- }
65
- actionRunning = true;
66
- await shortcut.action(server);
67
- actionRunning = false;
68
- };
69
- process.stdin.setRawMode(true);
70
- process.stdin.on('data', onInput).setEncoding('utf8').resume();
71
- server.httpServer.on('close', () => {
72
- process.stdin.off('data', onInput).pause();
73
- });
74
- }
75
- const BASE_SHORTCUTS = [
76
- {
77
- key: 'r',
78
- description: 'restart the server',
79
- async action(server) {
80
- await server.restart();
81
- },
82
- },
83
- {
84
- key: 'u',
85
- description: 'show server url',
86
- action(server) {
87
- server.config.logger.info('');
88
- server.printUrls();
89
- },
90
- },
91
- {
92
- key: 'o',
93
- description: 'open in browser',
94
- action(server) {
95
- server.openBrowser();
96
- },
97
- },
98
- {
99
- key: 'c',
100
- description: 'clear console',
101
- action(server) {
102
- server.config.logger.clearScreen('error');
103
- },
104
- },
105
- {
106
- key: 'q',
107
- description: 'quit',
108
- async action(server) {
109
- await server.close().finally(() => process.exit());
110
- },
111
- },
112
- {
113
- key: 'C',
114
- description: 'clear proxy cache',
115
- action(server) {
116
- if (server.cache) {
117
- server.cache.clear();
118
- server.config.logger.info('Proxy cache cleared');
119
- }
120
- },
121
- },
122
- ];
123
-
124
- function createDevServer(logLevel = 'info') {
125
- const server = express.default();
126
- const logger = winston.createLogger({
127
- level: logLevel,
128
- format: winston.format.cli({ level: true }),
129
- transports: [new winston.transports.Console()],
130
- });
131
- server.config = {
132
- logger,
133
- };
134
- const originalListen = server.listen;
135
- let listener;
136
- server.listen = function (...args) {
137
- listener = originalListen.apply(this, args);
138
- };
139
- server.printUrls = function (base) {
140
- if (!listener) {
141
- throw new Error('Server is not listening');
142
- }
143
- const colorUrl = (url) => colors.cyan(url.replace(/:(\d+)\//, (_, port) => `:${colors.bold(port)}/`));
144
- const address = listener.address();
145
- if (address && typeof address === 'object') {
146
- if (address.address === '::') {
147
- const url = new URL$1(base || '', `http://localhost:${address.port}`);
148
- logger.info(` ${colors.green('➜')} ${colors.bold('Local')}: ${colorUrl(url.toString())}`);
149
- }
150
- else {
151
- const url = new URL$1(base || '', `http://[${address.address}]:${address.port}`);
152
- logger.info(` ${colors.green('➜')} ${colors.bold('Local')}: ${colorUrl(url.toString())}`);
153
- }
154
- }
155
- };
156
- return server;
157
- }
158
-
159
- const changelogTemplate = /* HTML */ `<!DOCTYPE html>
160
- <html lang="en">
161
- <head>
162
- <meta charset="UTF-8" />
163
- <title>Changelog Diff</title>
164
- <style>
165
- tr,
166
- td {
167
- padding: 0;
168
- }
169
- .diff-file {
170
- margin-top: 20px;
171
- border: 1px solid #e1e4e8;
172
- border-radius: 6px;
173
- }
174
- .diff-file-title {
175
- padding: 10px 20px;
176
- background-color: #f6f8fa;
177
- border-bottom: 1px solid #e1e4e8;
178
- border-radius: 6px 6px 0 0;
179
- font-weight: bold;
180
- }
181
- .diff-file-title .renamed {
182
- font-weight: normal;
183
- }
184
- .diff-file-title .renamed .from {
185
- color: #cb2431;
186
- }
187
- .diff-file-title .renamed .to {
188
- color: #22863a;
189
- }
190
- .diff-file-title .added {
191
- color: #22863a;
192
- }
193
- .diff-file-title .deleted {
194
- color: #cb2431;
195
- }
196
- .diff-file-content {
197
- }
198
- .diff-table {
199
- tab-size: 8;
200
- width: 100%;
201
- border-collapse: separate;
202
- border-spacing: 0;
203
- }
204
- .blob-num {
205
- position: relative;
206
- color: #1f2328;
207
- width: 1%;
208
- min-width: 50px;
209
- padding: 0 10px;
210
- font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
211
- font-size: 12px;
212
- line-height: 20px;
213
- text-align: right;
214
- white-space: nowrap;
215
- vertical-align: top;
216
- cursor: pointer;
217
- -webkit-user-select: none;
218
- user-select: none;
219
- }
220
- .blob-num.addition {
221
- background-color: #ccffd8;
222
- border-color: #1f883e;
223
- }
224
- .blob-num.deletion {
225
- background-color: #ffd7d5;
226
- border-color: #cf222e;
227
- }
228
- .blob-num::before {
229
- content: attr(data-line-number);
230
- }
231
- .blob-code {
232
- position: relative;
233
- padding: 0 10px 0 22px;
234
- vertical-align: top;
235
- color: #1f2329;
236
- }
237
- .blob-code.code-addition {
238
- background-color: #e6ffec;
239
- }
240
- .blob-code.code-deletion {
241
- background-color: #ffebe9;
242
- }
243
- .blob-code.skip,
244
- .blob-code.message {
245
- text-align: center;
246
- }
247
- .blob-code.skip .blob-code-inner,
248
- .blob-code.message .blob-code-inner {
249
- font-weight: bold;
250
- color: #6a737d;
251
- padding: 10px 0;
252
- }
253
- .blob-code-inner {
254
- display: table-cell;
255
- overflow: visible;
256
- font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
257
- font-size: 12px;
258
- word-wrap: anywhere;
259
- white-space: pre-wrap;
260
- }
261
- .blob-code-inner::before {
262
- content: attr(data-code-prefix);
263
- position: absolute;
264
- top: 1px;
265
- left: 8px;
266
- padding-right: 8px;
267
- }
268
- </style>
269
- </head>
270
- <body>
271
- <h1>Changelog Diff</h1>
272
-
273
- %FILES%
274
- </body>
275
- </html>`;
276
- const LINE_ADDED = 1;
277
- const LINE_REMOVED = -1;
278
- const LINE_CONTEXT = 0;
279
- /**
280
- * Escape HTML sequence
281
- * @param str
282
- */
283
- function escapeHTMLSequence(str) {
284
- return str.replace(/[\u00A0-\u9999<>&]/g, (i) => '&#' + i.charCodeAt(0) + ';');
285
- }
286
- const fileNameWithHashRegEx = /(.+)(-[a-f0-9]{6,20})(\.[a-z0-9]+)$/i;
287
- /**
288
- * Changelog generator class
289
- * @class
290
- * @classdesc
291
- * Generates a changelog file based on the differences between two asset folders or zip files
292
- * @example
293
- * const changelogGenerator = new ChangelogGenerator({
294
- * previousAssetsPath: './dist-zip/previous',
295
- * currentAssetsPath: './dist-zip/current',
296
- * destinationPath: './dist-zip',
297
- * changelogFilename: 'CHANGELOG.html',
298
- * });
299
- * changelogGenerator.generateChangelog();
300
- */
301
- class ChangelogGenerator {
302
- oldAssetsPath;
303
- newAssetsPath;
304
- destinationPath;
305
- changelogFilename;
306
- changelogTemplate = changelogTemplate;
307
- diffFileTemplateHandler;
308
- diffLineTemplateHandler;
309
- contextLines = 3;
310
- logger;
311
- /**
312
- * Changelog generator class constructor
313
- * @param opts
314
- */
315
- constructor(opts) {
316
- const { oldAssetsPath, newAssetsPath, destinationPath, changelogTemplate, diffFileTemplateHandler, diffLineTemplateHandler, changelogFilename, contextLines, } = opts;
317
- this.logger = createLogger();
318
- if (!oldAssetsPath || !newAssetsPath || !destinationPath) {
319
- throw new Error('Previous assets path, current assets path and destination path are required');
320
- }
321
- if (oldAssetsPath === newAssetsPath) {
322
- throw new Error('Previous and current assets paths must be different');
323
- }
324
- if (!this.isExists(oldAssetsPath)) {
325
- throw new Error(`Previous assets path ${oldAssetsPath} does not exist`);
326
- }
327
- if (!this.isExists(newAssetsPath)) {
328
- throw new Error(`Current assets path ${newAssetsPath} does not exist`);
329
- }
330
- if (this.isZipFile(oldAssetsPath)) {
331
- const unzipDestinationPath = path.resolve(os.tmpdir(), crypto.createHash('md5').update(oldAssetsPath).digest('hex'));
332
- this.oldAssetsPath = this.unzipFile(oldAssetsPath, unzipDestinationPath)
333
- .then(() => {
334
- return this.normalizeAssetFolderPath(unzipDestinationPath);
335
- })
336
- .then((path) => {
337
- if (this.isEmptyFolder(path)) {
338
- throw new Error(`Previous assets path ${path} is empty`);
339
- }
340
- return path;
341
- });
342
- }
343
- else if (this.isFolder(oldAssetsPath)) {
344
- const path = this.normalizeAssetFolderPath(oldAssetsPath);
345
- if (this.isEmptyFolder(path)) {
346
- throw new Error(`Previous assets path ${path} is empty`);
347
- }
348
- this.oldAssetsPath = Promise.resolve(path);
349
- }
350
- else {
351
- throw new Error(`Invalid previous assets path ${oldAssetsPath}. It must be a folder or a zip file`);
352
- }
353
- if (this.isZipFile(newAssetsPath)) {
354
- const unzipDestinationPath = path.resolve(os.tmpdir(), crypto.createHash('md5').update(newAssetsPath).digest('hex'));
355
- this.newAssetsPath = this.unzipFile(newAssetsPath, unzipDestinationPath)
356
- .then(() => {
357
- return this.normalizeAssetFolderPath(unzipDestinationPath);
358
- })
359
- .then((path) => {
360
- if (this.isEmptyFolder(path)) {
361
- throw new Error(`Current assets path ${path} is empty`);
362
- }
363
- return path;
364
- });
365
- }
366
- else if (this.isFolder(newAssetsPath)) {
367
- const path = this.normalizeAssetFolderPath(newAssetsPath);
368
- if (this.isEmptyFolder(path)) {
369
- throw new Error(`Current assets path ${newAssetsPath} is empty`);
370
- }
371
- this.newAssetsPath = Promise.resolve(path);
372
- }
373
- else {
374
- throw new Error(`Invalid current assets path ${newAssetsPath}. It must be a folder or a zip file`);
375
- }
376
- this.destinationPath = destinationPath;
377
- this.mkdirpSync(this.destinationPath);
378
- if (changelogFilename) {
379
- this.changelogFilename = changelogFilename;
380
- }
381
- else {
382
- this.changelogFilename = 'CHANGELOG.html';
383
- }
384
- if (changelogTemplate) {
385
- if (this.templateIsValid(changelogTemplate)) {
386
- this.changelogTemplate = changelogTemplate;
387
- }
388
- else {
389
- this.logger.warn(colors.yellow('Invalid changelog template, using default'));
390
- }
391
- }
392
- if (typeof diffFileTemplateHandler === 'function') {
393
- this.diffFileTemplateHandler = diffFileTemplateHandler;
394
- }
395
- if (typeof diffLineTemplateHandler === 'function') {
396
- this.diffLineTemplateHandler = diffLineTemplateHandler;
397
- }
398
- if (contextLines) {
399
- this.contextLines = contextLines;
400
- }
401
- }
402
- templateIsValid(template) {
403
- return template.includes('%FILES%');
404
- }
405
- isExists(assetPath) {
406
- return fs.existsSync(assetPath);
407
- }
408
- isZipFile(assetPath) {
409
- return assetPath.endsWith('.zip');
410
- }
411
- isFolder(assetPath) {
412
- return fs.lstatSync(assetPath).isDirectory();
413
- }
414
- isEmptyFolder(assetPath) {
415
- return fs.readdirSync(assetPath, { withFileTypes: true }).length === 0;
416
- }
417
- mkdirpSync(dir) {
418
- if (!fs.existsSync(dir)) {
419
- fs.mkdirSync(dir, { recursive: true });
420
- }
421
- }
422
- async unzipFile(assetPath, destinationPath) {
423
- fs.rmSync(destinationPath, { force: true, recursive: true });
424
- return extractZip(assetPath, { dir: destinationPath });
425
- }
426
- normalizeAssetFolderPath(assetPath) {
427
- const folderContent = fs.readdirSync(assetPath);
428
- if (folderContent.length === 1 && fs.lstatSync(path.join(assetPath, folderContent[0])).isDirectory()) {
429
- return this.normalizeAssetFolderPath(path.join(assetPath, folderContent[0]));
430
- }
431
- return assetPath;
432
- }
433
- pathToPosix(path) {
434
- return path.replace(/\\/g, '/');
435
- }
436
- diffTableTemplate(diffLinesHTML) {
437
- return /* HTML */ `<table class="diff-table">
438
- <tbody>
439
- ${diffLinesHTML}
440
- </tbody>
441
- </table>`;
442
- }
443
- getDiffTableHTML(diffLines) {
444
- const diffLinesHTML = diffLines
445
- .filter((value, index, array) => {
446
- if (value.lineType === LINE_CONTEXT) {
447
- return ((index >= 0 && index < this.contextLines) ||
448
- (index > array.length - (this.contextLines + 1) && index <= array.length - 1) ||
449
- array
450
- .slice(index - this.contextLines, index + this.contextLines + 1)
451
- .some((line) => line.lineType !== LINE_CONTEXT));
452
- }
453
- return true;
454
- })
455
- .map((line, index, array) => {
456
- if (index > 0) {
457
- const prevLine = array[index - 1];
458
- if (line.lineNumber - prevLine.lineNumber > 1) {
459
- return [{ lineNumber: -1, lineContent: '', lineType: LINE_CONTEXT }, line];
460
- }
461
- }
462
- return [line];
463
- })
464
- .flat()
465
- .map((line) => this.diffLineHTML(line))
466
- .join('');
467
- return this.diffTableTemplate(diffLinesHTML);
468
- }
469
- diffLineMessageTemplate(message) {
470
- return /* HTML */ `<tr>
471
- <td class="blob-num"></td>
472
- <td class="blob-num"></td>
473
- <td class="blob-code message">
474
- <span class="blob-code-inner">${message}</span>
475
- </td>
476
- </tr>`;
477
- }
478
- diffLineSkipTemplate() {
479
- return /* HTML */ `<tr>
480
- <td class="blob-num"></td>
481
- <td class="blob-num"></td>
482
- <td class="blob-code skip">
483
- <span class="blob-code-inner">Skip</span>
484
- </td>
485
- </tr>`;
486
- }
487
- diffLineTemplate(diffLine) {
488
- const { lineNumber, lineContent, lineType } = diffLine;
489
- const numClass = lineType === LINE_ADDED ? 'addition' : lineType === LINE_REMOVED ? 'deletion' : '';
490
- const codeClass = lineType === LINE_ADDED ? 'code-addition' : lineType === LINE_REMOVED ? 'code-deletion' : '';
491
- const prefix = lineType === LINE_ADDED ? '+' : lineType === LINE_REMOVED ? '-' : ' ';
492
- return /* HTML */ `<tr>
493
- <td
494
- class="blob-num ${numClass}${numClass === 'addition' ? ' empty' : ''}"
495
- ${numClass !== 'addition' ? ` data-line-number="${lineNumber}"` : ''}
496
- ></td>
497
- <td
498
- class="blob-num ${numClass}${numClass === 'deletion' ? ' empty' : ''}"
499
- ${numClass !== 'deletion' ? ` data-line-number="${lineNumber}"` : ''}
500
- ></td>
501
- <td class="blob-code ${codeClass}">
502
- <span class="blob-code-inner" data-code-prefix="${prefix}">${escapeHTMLSequence(lineContent ?? '')}</span>
503
- </td>
504
- </tr>`;
505
- }
506
- diffLineHTML(diffLine) {
507
- if (this.diffLineTemplateHandler) {
508
- return this.diffLineTemplateHandler(diffLine);
509
- }
510
- const { lineNumber } = diffLine;
511
- if (lineNumber === -1) {
512
- return this.diffLineSkipTemplate();
513
- }
514
- return this.diffLineTemplate(diffLine);
515
- }
516
- diffFileTemplate(filename, htmlDiff) {
517
- if (this.diffFileTemplateHandler) {
518
- return this.diffFileTemplateHandler(filename, htmlDiff);
519
- }
520
- return /* HTML */ `<div class="diff-file">
521
- <div class="diff-file-title">${filename}</div>
522
- <div class="diff-file-content">${htmlDiff}</div>
523
- </div>`;
524
- }
525
- async generateAssetFoldersDiff() {
526
- this.logger.info(colors.blue(`Comparing asset folders ${await this.oldAssetsPath} and ${await this.newAssetsPath}`));
527
- const dirDiff = await dirCompare.compare(await this.oldAssetsPath, await this.newAssetsPath, {
528
- compareContent: true,
529
- skipSymlinks: true,
530
- compareSize: true,
531
- compareDate: false,
532
- compareNameHandler: (name1, name2) => {
533
- if (fileNameWithHashRegEx.test(name1)) {
534
- name1 = name1.replace(fileNameWithHashRegEx, '$1$3');
535
- }
536
- if (fileNameWithHashRegEx.test(name2)) {
537
- name2 = name2.replace(fileNameWithHashRegEx, '$1$3');
538
- }
539
- if (name1.localeCompare(name2) === 0) {
540
- return 0;
541
- }
542
- return name1.localeCompare(name2) > 0 ? 1 : -1;
543
- },
544
- });
545
- return dirDiff.diffSet?.filter((d) => d.state !== 'equal' || d.name1 !== d.name2) || [];
546
- }
547
- async generateAssetFilesDiff(oldFileString, newFileString) {
548
- const dmp = new DiffMatchPatch();
549
- const linesChars = dmp.diff_linesToChars_(oldFileString, newFileString);
550
- const linesDiff = dmp.diff_main(linesChars.chars1, linesChars.chars2, false);
551
- dmp.diff_charsToLines_(linesDiff, linesChars.lineArray);
552
- let lineNumber = 0;
553
- return linesDiff
554
- .map((diffLine) => {
555
- const [lineType, lineContent] = diffLine;
556
- const linesCount = lineContent.endsWith('\n')
557
- ? lineContent.split('\n').length - 1
558
- : lineContent.split('\n').length;
559
- const lines = lineContent
560
- .split('\n')
561
- .map((line, index) => {
562
- return { lineContent: line, lineNumber: lineNumber + index + 1, lineType };
563
- })
564
- .slice(0, linesCount);
565
- if (lineType !== LINE_REMOVED) {
566
- lineNumber += linesCount;
567
- }
568
- return lines;
569
- })
570
- .flat();
571
- }
572
- /**
573
- * Generate diff for a file
574
- * @param difference
575
- * @private
576
- */
577
- async generateFilesDiff(difference) {
578
- if (difference.state === 'equal') {
579
- const filepath1 = this.pathToPosix(path.join('.', difference.relativePath, difference.name1 ?? ''));
580
- const filepath2 = this.pathToPosix(path.join('.', difference.relativePath, difference.name2 ?? ''));
581
- return this.diffFileTemplate(
582
- /* HTML */ `<span class="renamed"
583
- >Renamed <span class="from">${filepath1}</span> -> <span class="to">${filepath2}</span></span
584
- >`, this.diffTableTemplate(this.diffLineMessageTemplate('No changes')));
585
- }
586
- const assetFile1Path = difference.path1 && difference.name1 ? path.join(difference.path1, difference.name1) : null;
587
- const assetFile2Path = difference.path2 && difference.name2 ? path.join(difference.path2, difference.name2) : null;
588
- const filepath = this.pathToPosix(path.join('.', difference.relativePath, (difference.name1 || difference.name2) ?? ''));
589
- if (difference.state === 'left' && assetFile1Path) {
590
- return this.diffFileTemplate(
591
- /* HTML */ `<span class="removed">Removed ${filepath}</span>`, this.diffTableTemplate(this.diffLineMessageTemplate('File removed')));
592
- }
593
- if (difference.state === 'right' && assetFile2Path) {
594
- return this.diffFileTemplate(
595
- /* HTML */ `<span class="added">Added ${filepath}</span>`, this.diffTableTemplate(this.diffLineMessageTemplate('File added')));
596
- }
597
- if (difference.state === 'distinct' && assetFile1Path && assetFile2Path) {
598
- const filepath1 = this.pathToPosix(path.join('.', difference.relativePath, difference.name1 ?? ''));
599
- const filepath2 = this.pathToPosix(path.join('.', difference.relativePath, difference.name2 ?? ''));
600
- const filenameTitle = difference.name1 !== difference.name2
601
- ? /* HTML */ `<span class="renamed"
602
- >Renamed <span class="from">${filepath1}</span> -> <span class="to">${filepath2}</span></span
603
- >`
604
- : filepath;
605
- return this.diffFileTemplate(filenameTitle, (await isBinaryFile(assetFile1Path)) || (await isBinaryFile(assetFile2Path))
606
- ? this.diffTableTemplate(this.diffLineMessageTemplate('Binary file'))
607
- : this.getDiffTableHTML(await this.generateAssetFilesDiff(fs.readFileSync(assetFile1Path, 'utf-8'), fs.readFileSync(assetFile2Path, 'utf-8'))));
608
- }
609
- return '';
610
- }
611
- /**
612
- * Generate changelog file based on the differences between two asset folders or zip files
613
- * and write it to the destination folder
614
- */
615
- async generateChangelog() {
616
- this.logger.info(colors.green('Generating changelog'));
617
- const diffSet = await this.generateAssetFoldersDiff();
618
- const htmlDiff = (await Promise.all(diffSet.map((difference) => this.generateFilesDiff(difference)))).join('');
619
- this.logger.info(colors.green('Writing changelog file'));
620
- const templateArray = this.changelogTemplate.split('%FILES%');
621
- templateArray.splice(1, 0, htmlDiff);
622
- const changelogHTML = templateArray.join('');
623
- fs.writeFileSync(path.join(this.destinationPath, this.changelogFilename), changelogHTML);
624
- this.logger.info(colors.green(`Changelog file written to ${path.join(this.destinationPath, this.changelogFilename)}`));
625
- }
626
- }
627
-
628
- class IconFontGenerator {
629
- sourceDir;
630
- outputDir;
631
- fontName;
632
- constructor(options) {
633
- this.sourceDir = options.sourceDir;
634
- this.outputDir = options.outputDir;
635
- this.fontName = options.fontName;
636
- }
637
- async generate() {
638
- await svgToFont({
639
- src: this.sourceDir,
640
- dist: this.outputDir,
641
- fontName: this.fontName,
642
- css: true,
643
- typescript: true,
644
- startUnicode: 0xea01,
645
- svgicons2svgfont: {
646
- fontHeight: 1024,
647
- },
648
- });
649
- }
650
- }
651
-
652
- const cli = cac('pp-dev');
653
- let profileSession = global.__pp_dev_profile_session;
654
- let profileCount = 0;
655
- const stopProfiler = (log) => {
656
- if (!profileSession) {
657
- return;
658
- }
659
- return new Promise((res, rej) => {
660
- profileSession.post('Profiler.stop', (err, { profile }) => {
661
- // Write profile to disk, upload, etc.
662
- if (!err) {
663
- const outPath = path.resolve(`./pp-dev-profile-${profileCount++}.cpuprofile`);
664
- fs.writeFileSync(outPath, JSON.stringify(profile));
665
- log(colors.yellow(`CPU profile written to ${colors.white(colors.dim(outPath))}`));
666
- profileSession = undefined;
667
- res();
668
- }
669
- else {
670
- rej(err);
671
- }
672
- });
673
- });
674
- };
675
- const filterDuplicateOptions = (options) => {
676
- for (const [key, value] of Object.entries(options)) {
677
- if (Array.isArray(value)) {
678
- options[key] = value[value.length - 1];
679
- }
680
- }
681
- };
682
- /**
683
- * removing global flags before passing as command specific sub-configs
684
- */
685
- function cleanOptions(options) {
686
- const ret = { ...options };
687
- delete ret['--'];
688
- delete ret.c;
689
- delete ret.config;
690
- delete ret.base;
691
- delete ret.l;
692
- delete ret.logLevel;
693
- delete ret.clearScreen;
694
- delete ret.d;
695
- delete ret.debug;
696
- delete ret.f;
697
- delete ret.filter;
698
- delete ret.m;
699
- delete ret.mode;
700
- return ret;
701
- }
702
- cli
703
- .option('-c, --config <file>', `[string] use specified config file`)
704
- .option('--base <path>', `[string] public base path (default: /)`)
705
- .option('-l, --logLevel <level>', `[string] info | warn | error | silent`)
706
- .option('--clearScreen', `[boolean] allow/disable clear screen when logging`)
707
- .option('-d, --debug [feat]', `[string | boolean] show debug logs`)
708
- .option('-f, --filter <filter>', `[string] filter debug logs`)
709
- .option('-m, --mode <mode>', `[string] set env mode`);
710
- // dev
711
- cli
712
- .command('[root]', 'start dev server') // default command
713
- .alias('serve') // the command is called 'serve' in Vite's API
714
- .alias('dev') // alias to align with the script name
715
- .option('--host [host]', `[string] specify hostname`)
716
- .option('--port <port>', `[number] specify port`)
717
- .option('--https', `[boolean] use TLS + HTTP/2`)
718
- .option('--open [path]', `[boolean | string] open browser on startup`)
719
- .option('--cors', `[boolean] enable CORS`)
720
- .option('--strictPort', `[boolean] exit if specified port is already in use`)
721
- .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle`)
722
- .action(async (root, options) => {
723
- filterDuplicateOptions(options);
724
- // output structure is preserved even after bundling so require()
725
- // is ok here
726
- const { createServer } = await import('vite');
727
- try {
728
- const configFromFile = await loadConfigFromFile({ mode: options.mode || 'development', command: 'serve' }, options.config, root, options.logLevel);
729
- let config = await getViteConfig();
730
- if (configFromFile) {
731
- const { plugins, ...fileConfig } = configFromFile.config;
732
- config = mergeConfig(config, fileConfig);
733
- }
734
- const server = await createServer(mergeConfig(config, {
735
- root,
736
- base: options.base,
737
- mode: options.mode,
738
- configFile: options.config,
739
- logLevel: options.logLevel,
740
- clearScreen: options.clearScreen,
741
- optimizeDeps: { force: options.force },
742
- server: cleanOptions(options),
743
- customLogger: createLogger(options.logLevel),
744
- }, true));
745
- if (!server.config.base || server.config.base === '/') {
746
- throw new Error('base cannot be equal to "/" or empty string');
747
- }
748
- if (!server.httpServer) {
749
- throw new Error('HTTP server not available');
750
- }
751
- await server.listen();
752
- const logger = createLogger(options.logLevel);
753
- const ppDevStartTime = global.__pp_dev_start_time ?? false;
754
- const startupDurationString = ppDevStartTime
755
- ? colors.dim(`ready in ${colors.reset(colors.bold(Math.ceil(performance.now() - ppDevStartTime)))} ms`)
756
- : '';
757
- logger.info(`\n ${colors.green(`${colors.bold('PP-DEV')} v${VERSION}`)} ${startupDurationString}\n`);
758
- server.printUrls();
759
- bindShortcuts(server, {
760
- print: true,
761
- customShortcuts: [
762
- profileSession && {
763
- key: 'p',
764
- description: 'start/stop the profiler',
765
- async action(server) {
766
- if (profileSession) {
767
- await stopProfiler(logger.info);
768
- }
769
- else {
770
- const inspector = await import('node:inspector').then((r) => r.default);
771
- await new Promise((res) => {
772
- profileSession = new inspector.Session();
773
- profileSession.connect();
774
- profileSession.post('Profiler.enable', () => {
775
- profileSession?.post('Profiler.start', () => {
776
- logger.info('Profiler started');
777
- res();
778
- });
779
- });
780
- });
781
- }
782
- },
783
- },
784
- {
785
- key: 'l',
786
- description: 'proxy re-login',
787
- action(server) {
788
- server.ws.send({
789
- type: 'custom',
790
- event: 'redirect',
791
- data: { url: `/auth/index/logout?proxyRedirect=${encodeURIComponent('/')}` },
792
- });
793
- },
794
- },
795
- ],
796
- });
797
- }
798
- catch (e) {
799
- const logger = createLogger(options.logLevel);
800
- logger.error(colors.red(`error when starting dev server:\n${e.stack}`), {
801
- error: e,
802
- });
803
- stopProfiler(logger.info);
804
- process.exit(1);
805
- }
806
- });
807
- // dev
808
- cli
809
- .command('next [root]', 'start dev server') // default command
810
- .alias('next-serve') // the command is called 'serve' in Vite's API
811
- .alias('next-dev') // alias to align with the script name
812
- .option('--host [host]', `[string] specify hostname`)
813
- .option('--port <port>', `[number] specify port`, { default: 3000 })
814
- .option('--https', `[boolean] use TLS + HTTP/2`)
815
- .option('--open [path]', `[boolean | string] open browser on startup`)
816
- .option('--cors', `[boolean] enable CORS`)
817
- .option('--strictPort', `[boolean] exit if specified port is already in use`)
818
- .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle`)
819
- .action(async (root, options) => {
820
- filterDuplicateOptions(options);
821
- const { default: next } = await import('next');
822
- const logger = createLogger();
823
- const server = createDevServer(options.logLevel);
824
- const opts = cleanOptions(options);
825
- const app = next({ dev: true, hostname: opts.host, port: opts.port });
826
- await app.prepare();
827
- const nextServer = (await app.getServer());
828
- let base = nextServer.nextConfig.basePath;
829
- const { assetPrefix } = nextServer.nextConfig;
830
- if (!base.endsWith('/')) {
831
- base += '/';
832
- }
833
- if (base === '/') {
834
- throw new Error('basePath cannot be equal to "/" or empty string');
835
- }
836
- const baseWithoutTrailingSlash = base.substring(0, base.lastIndexOf('/'));
837
- const templateName = nextServer.nextConfig.serverRuntimeConfig.templateName;
838
- const ppDevConfig = nextServer.nextConfig.serverRuntimeConfig.ppDevConfig;
839
- const { backendBaseURL, portalPageId, templateLess = true, enableProxyCache = true, miHudLess = true, proxyCacheTTL = 10 * 60 * 1000, disableSSLValidation = false, } = ppDevConfig;
840
- server.use(initPPRedirect(base, templateName));
841
- if (backendBaseURL) {
842
- const baseUrlHost = new URL(backendBaseURL).host;
843
- const mi = new MiAPI(backendBaseURL, {
844
- headers: {
845
- host: baseUrlHost,
846
- referer: backendBaseURL,
847
- origin: backendBaseURL.replace(/^(https?:\/\/)([^/]+)(\/.*)?$/i, '$1$2'),
848
- },
849
- portalPageId,
850
- templateLess,
851
- disableSSLValidation,
852
- });
853
- if (enableProxyCache) {
854
- let ttl = +proxyCacheTTL;
855
- if (!ttl || Number.isNaN(ttl) || ttl < 0) {
856
- ttl = 10 * 60 * 1000; // 10 minutes
857
- }
858
- server.use(initProxyCache({ devServer: server, ttl }));
859
- }
860
- const proxyIgnore = ['/@vite', '/@metricinsights', '/@', baseWithoutTrailingSlash];
861
- if (assetPrefix) {
862
- proxyIgnore.push(assetPrefix);
863
- }
864
- server.use(initProxy({
865
- devServer: server,
866
- baseURL: backendBaseURL,
867
- proxyIgnore,
868
- disableSSLValidation,
869
- }));
870
- const isIndexRegExp = new RegExp(`^((${base})|/)$`);
871
- // Get portal page variables from the backend (also, redirect magic)
872
- server.use(initLoadPPData(isIndexRegExp, mi, ppDevConfig));
873
- server.use(initRewriteResponse((url) => {
874
- return isIndexRegExp.test(cutUrlParams(url));
875
- }, (response, req) => {
876
- return Buffer.from(urlReplacer(baseUrlHost, req.headers.host ?? '', mi.buildPage(response, miHudLess)));
877
- }));
878
- }
879
- const handle = app.getRequestHandler();
880
- server.all('*', (req, res) => {
881
- if (req.url.startsWith(assetPrefix) && assetPrefix !== baseWithoutTrailingSlash) {
882
- const parsedUrl = parse(req.url.replace(assetPrefix, baseWithoutTrailingSlash), true);
883
- return handle(req, res, parsedUrl);
884
- }
885
- const parsedUrl = parse(req.url, true);
886
- handle(req, res, parsedUrl);
887
- });
888
- try {
889
- await new Promise((resolve) => {
890
- if (opts.host) {
891
- resolve(server.listen(opts.port, opts.host, () => {
892
- //
893
- }));
894
- }
895
- else {
896
- resolve(server.listen(opts.port, () => {
897
- //
898
- }));
899
- }
900
- });
901
- const ppDevStartTime = global.__pp_dev_start_time ?? false;
902
- const startupDurationString = ppDevStartTime
903
- ? colors.dim(`ready in ${colors.reset(colors.bold(Math.ceil(performance.now() - ppDevStartTime)))} ms`)
904
- : '';
905
- logger.info(`\n ${colors.green(`${colors.bold('PP-DEV')} v${VERSION}`)} ${startupDurationString}\n`, {
906
- clear: true,
907
- });
908
- server.printUrls(base);
909
- // bindShortcuts(server, {
910
- // print: true,
911
- // customShortcuts: [
912
- // profileSession && {
913
- // key: 'p',
914
- // description: 'start/stop the profiler',
915
- // async action(server) {
916
- // if (profileSession) {
917
- // await stopProfiler(server.config.logger.info);
918
- // } else {
919
- // const inspector = await import('node:inspector').then((r) => (r as any).default);
920
- // await new Promise<void>((res) => {
921
- // profileSession = new inspector.Session();
922
- // profileSession.connect();
923
- // profileSession.post('Profiler.enable', () => {
924
- // profileSession?.post('Profiler.start', () => {
925
- // server.config.logger.info('Profiler started');
926
- // res();
927
- // });
928
- // });
929
- // });
930
- // }
931
- // },
932
- // },
933
- // {
934
- // key: 'l',
935
- // description: 'proxy re-login',
936
- // action(server: ViteDevServer): void | Promise<void> {
937
- // server.ws.send({
938
- // type: 'custom',
939
- // event: 'redirect',
940
- // data: { url: `/auth/index/logout?proxyRedirect=${encodeURIComponent('/')}` },
941
- // });
942
- // },
943
- // },
944
- // ],
945
- // });
946
- }
947
- catch (e) {
948
- const logger = createLogger(options.logLevel);
949
- logger.error(colors.red(`error when starting dev server:\n${e.stack}`), {
950
- error: e,
951
- });
952
- stopProfiler(logger.info);
953
- process.exit(1);
954
- }
955
- });
956
- // build
957
- cli
958
- .command('build [root]', 'build for production')
959
- .option('--target <target>', `[string] transpile target (default: 'modules')`)
960
- .option('--outDir <dir>', `[string] output directory (default: dist)`)
961
- .option('--assetsDir <dir>', `[string] directory under outDir to place assets in (default: assets)`)
962
- .option('--assetsInlineLimit <number>', `[number] static asset base64 inline threshold in bytes (default: 4096)`)
963
- .option('--ssr [entry]', `[string] build specified entry for server-side rendering`)
964
- .option('--sourcemap [output]', `[boolean | "inline" | "hidden"] output source maps for build (default: false)`)
965
- .option('--minify [minifier]', `[boolean | "terser" | "esbuild"] enable/disable minification, ` + `or specify minifier to use (default: esbuild)`)
966
- .option('--manifest [name]', `[boolean | string] emit build manifest json`)
967
- .option('--ssrManifest [name]', `[boolean | string] emit ssr manifest json`)
968
- .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle (experimental)`)
969
- .option('--emptyOutDir', `[boolean] force empty outDir when it's outside of root`)
970
- .option('-w, --watch', `[boolean] rebuilds when modules have changed on disk`)
971
- .option('--changelog [assetsFile]', `[boolean | string] generate changelog between assetsFile and current build (default: false)`)
972
- .action(async (root, options) => {
973
- filterDuplicateOptions(options);
974
- const buildOptions = cleanOptions(options);
975
- try {
976
- const configFromFile = await loadConfigFromFile({ mode: options.mode || 'production', command: 'build' }, options.config, root, options.logLevel);
977
- let config = await getViteConfig();
978
- if (configFromFile) {
979
- const { plugins, ...fileConfig } = configFromFile.config;
980
- config = mergeConfig(config, fileConfig);
981
- }
982
- const buildConfig = mergeConfig(config, {
983
- root,
984
- base: options.base,
985
- mode: options.mode,
986
- configFile: options.config,
987
- logLevel: options.logLevel,
988
- clearScreen: options.clearScreen,
989
- optimizeDeps: { force: options.force },
990
- build: buildOptions,
991
- }, true);
992
- await build(buildConfig);
993
- if (buildOptions.changelog) {
994
- const executionRoot = root || process.cwd();
995
- const outDir = buildConfig.build?.outDir || 'dist';
996
- let oldAssetsPath = '';
997
- if (typeof buildOptions.changelog === 'string') {
998
- oldAssetsPath = path.resolve(executionRoot, buildOptions.changelog);
999
- }
1000
- else {
1001
- const backupsDirPath = path.resolve(executionRoot, buildConfig.ppDevConfig?.syncBackupsDir || 'backups');
1002
- if (!fs.existsSync(backupsDirPath)) {
1003
- createLogger(options.logLevel).warn(colors.yellow(`backups directory not found, skipping changelog generation`));
1004
- return;
1005
- }
1006
- const backups = fs.readdirSync(backupsDirPath, { withFileTypes: true });
1007
- if (!backups.length) {
1008
- createLogger(options.logLevel).warn(colors.yellow(`no backups found, skipping changelog generation`));
1009
- return;
1010
- }
1011
- const latestBackup = backups
1012
- .filter((value) => {
1013
- return value.isFile() && value.name.endsWith('.zip');
1014
- })
1015
- .reduce((latest, current) => {
1016
- const latestTime = fs.statSync(path.resolve(backupsDirPath, latest.name)).mtimeMs;
1017
- const currentTime = fs.statSync(path.resolve(backupsDirPath, current.name)).mtimeMs;
1018
- return latestTime > currentTime ? latest : current;
1019
- }, backups[0]).name;
1020
- oldAssetsPath = path.resolve(backupsDirPath, latestBackup);
1021
- }
1022
- const currentAssetFilePath = path.resolve(executionRoot, outDir);
1023
- let changelogDestination = 'dist-zip';
1024
- if (buildConfig.ppDevConfig) {
1025
- if (buildConfig.ppDevConfig.distZip === false) {
1026
- changelogDestination = buildConfig.build?.outDir || 'dist';
1027
- }
1028
- else if (typeof buildConfig.ppDevConfig.distZip === 'object' &&
1029
- typeof buildConfig.ppDevConfig.distZip.outDir === 'string') {
1030
- changelogDestination = buildConfig.ppDevConfig.distZip.outDir;
1031
- }
1032
- }
1033
- const changelogGenerator = new ChangelogGenerator({
1034
- oldAssetsPath,
1035
- newAssetsPath: currentAssetFilePath,
1036
- destinationPath: path.resolve(executionRoot, changelogDestination),
1037
- });
1038
- await changelogGenerator.generateChangelog();
1039
- }
1040
- }
1041
- catch (e) {
1042
- createLogger(options.logLevel).error(colors.red(`error during build:\n${e.stack}`), { error: e });
1043
- process.exit(1);
1044
- }
1045
- finally {
1046
- stopProfiler((message) => createLogger(options.logLevel).info(message));
1047
- }
1048
- });
1049
- // changelog
1050
- cli
1051
- .command('changelog [oldAssetPath] [newAssetPath]', 'generate changelog between two assets files/folders')
1052
- .option('--oldAssetsPath <oldAssetsPath>', `[string] path to the old assets zip file or folder`)
1053
- .option('--newAssetsPath <newAssetsPath>', `[string] path to the new assets zip file or folder`)
1054
- .option('--destination <destination>', `[string] destination folder for the changelog (default: .)`)
1055
- .option('--filename <filename>', `[string] filename for the changelog (default: CHANGELOG.html)`)
1056
- .action(async (oldAssetPath, newAssetPath, options) => {
1057
- filterDuplicateOptions(options);
1058
- const { oldAssetsPath: oldPath = oldAssetPath, newAssetsPath: newPath = newAssetPath, destination = '.', filename = 'CHANGELOG.html', logLevel, } = options;
1059
- const root = process.cwd();
1060
- if (!oldPath || !newPath) {
1061
- createLogger(logLevel).error(colors.red(`error during changelog generation: oldAssetPath and newAssetPath are required`));
1062
- process.exit(1);
1063
- }
1064
- const fullOldPath = path.resolve(root, oldPath);
1065
- const fullNewPath = path.resolve(root, newPath);
1066
- const fullDestination = path.resolve(root, destination);
1067
- const changelogGenerator = new ChangelogGenerator({
1068
- oldAssetsPath: fullOldPath,
1069
- newAssetsPath: fullNewPath,
1070
- destinationPath: fullDestination,
1071
- changelogFilename: filename,
1072
- });
1073
- await changelogGenerator.generateChangelog();
1074
- });
1075
- cli
1076
- .command('generate-icon-font [source] [destination]', 'generate icon font from SVG files')
1077
- .option('--source <source>', `[string] path to the source directory with SVG files`)
1078
- .option('--destination <destination>', `[string] path to the destination directory to save the generated font files`)
1079
- .option('--font-name, -n <fontName>', `[string] name of the font to generate (default: 'icon-font')`)
1080
- .action(async (source, destination, options) => {
1081
- filterDuplicateOptions(options);
1082
- const { source: sourceDir = source, destination: destDir = destination, fontName = 'icon-font' } = options;
1083
- const root = process.cwd();
1084
- const fullSourceDir = path.resolve(root, sourceDir);
1085
- const fullDestDir = path.resolve(root, destDir);
1086
- const iconFontGenerator = new IconFontGenerator({
1087
- sourceDir: fullSourceDir,
1088
- outputDir: fullDestDir,
1089
- fontName,
1090
- });
1091
- const logger = createLogger(options.logLevel);
1092
- logger.info(`Generating icon font from SVG files in ${colors.dim(fullSourceDir)}`);
1093
- await iconFontGenerator.generate();
1094
- logger.info(`Icon font generated and saved to ${colors.dim(fullDestDir)}`);
1095
- });
1096
- // optimize
1097
- cli
1098
- .command('optimize [root]', 'pre-bundle dependencies')
1099
- .option('--force', `[boolean] force the optimizer to ignore the cache and re-bundle`)
1100
- .action(async (root, options) => {
1101
- filterDuplicateOptions(options);
1102
- try {
1103
- const configFromFile = await loadConfigFromFile({ mode: options.mode || 'production', command: 'build' }, options.config, root, options.logLevel);
1104
- let config = await getViteConfig();
1105
- if (configFromFile) {
1106
- const { plugins, ...fileConfig } = configFromFile.config;
1107
- config = mergeConfig(config, fileConfig);
1108
- }
1109
- const optimizeConfig = await resolveConfig(mergeConfig(config, {
1110
- root,
1111
- base: options.base,
1112
- configFile: options.config,
1113
- logLevel: options.logLevel,
1114
- mode: options.mode,
1115
- }), 'serve');
1116
- await optimizeDeps(optimizeConfig, options.force, true);
1117
- }
1118
- catch (e) {
1119
- createLogger(options.logLevel).error(colors.red(`error when optimizing deps:\n${e.stack}`), { error: e });
1120
- process.exit(1);
1121
- }
1122
- });
1123
- cli
1124
- .command('preview [root]', 'locally preview production build')
1125
- .option('--host [host]', `[string] specify hostname`)
1126
- .option('--port <port>', `[number] specify port`)
1127
- .option('--strictPort', `[boolean] exit if specified port is already in use`)
1128
- .option('--https', `[boolean] use TLS + HTTP/2`)
1129
- .option('--open [path]', `[boolean | string] open browser on startup`)
1130
- .option('--outDir <dir>', `[string] output directory (default: dist)`)
1131
- .action(async (root, options) => {
1132
- filterDuplicateOptions(options);
1133
- try {
1134
- const configFromFile = await loadConfigFromFile({ mode: options.mode || 'production', command: 'build' }, options.config, root, options.logLevel);
1135
- let config = await getViteConfig();
1136
- if (configFromFile) {
1137
- const { plugins, ...fileConfig } = configFromFile.config;
1138
- config = mergeConfig(config, fileConfig);
1139
- }
1140
- const server = await preview(mergeConfig(config, {
1141
- root,
1142
- base: options.base,
1143
- configFile: options.config,
1144
- logLevel: options.logLevel,
1145
- mode: options.mode,
1146
- build: {
1147
- outDir: options.outDir,
1148
- },
1149
- preview: {
1150
- port: options.port,
1151
- strictPort: options.strictPort,
1152
- host: options.host,
1153
- https: options.https,
1154
- open: options.open,
1155
- },
1156
- }));
1157
- server.printUrls();
1158
- }
1159
- catch (e) {
1160
- createLogger(options.logLevel).error(colors.red(`error when starting preview server:\n${e.stack}`), {
1161
- error: e,
1162
- });
1163
- process.exit(1);
1164
- }
1165
- finally {
1166
- stopProfiler((message) => createLogger(options.logLevel).info(message));
1167
- }
1168
- });
1169
- cli.help();
1170
- cli.version(VERSION);
1171
- cli.parse();
1172
-
1173
- export { stopProfiler };
1
+ import*as e from"path";import*as t from"fs";import{performance as o}from"node:perf_hooks";import{cac as n}from"cac";import{loadConfigFromFile as i,loadEnv as s,mergeConfig as r,build as a,resolveConfig as l,optimizeDeps as d,preview as c}from"vite";import{g as p,V as f}from"./index-C2GV98GH.js";import{c as h,a as m,i as g,M as u,b,d as v,e as w,f as y,g as P,r as T,u as x,h as L}from"./plugin-B909lge8.js";import{URL as $,parse as S}from"url";import*as F from"express";import*as k from"winston";import*as A from"dir-compare";import C from"diff-match-patch";import{isBinaryFile as D}from"isbinaryfile";import*as E from"os";import*as j from"crypto";import z from"extract-zip";import H from"svgtofont";import*as _ from"node:process";import"ejs";import"esbuild";import"http-proxy-middleware";import"picocolors";import"axios";import"jsdom";import"https";import"memory-cache";import"process";import"child_process";import"console";import"zlib";function I(e){return null!==e||void 0!==e}const M=[{key:"r",description:"restart the server",async action(e){await e.restart()}},{key:"u",description:"show server url",action(e){e.config.logger.info(""),e.printUrls()}},{key:"o",description:"open in browser",action(e){e.openBrowser()}},{key:"c",description:"clear console",action(e){e.config.logger.clearScreen("error")}},{key:"q",description:"quit",async action(e){await e.close().finally((()=>process.exit()))}},{key:"C",description:"clear proxy cache",action(e){e.cache&&(e.cache.clear(),e.config.logger.info("Proxy cache cleared"))}}];const N=/(.+)(-[a-f0-9]{6,20})(\.[a-z0-9]+)$/i;class R{oldAssetsPath;newAssetsPath;destinationPath;changelogFilename;changelogTemplate='<!DOCTYPE html>\n <html lang="en">\n <head>\n <meta charset="UTF-8" />\n <title>Changelog Diff</title>\n <style>\n tr,\n td {\n padding: 0;\n }\n .diff-file {\n margin-top: 20px;\n border: 1px solid #e1e4e8;\n border-radius: 6px;\n }\n .diff-file-title {\n padding: 10px 20px;\n background-color: #f6f8fa;\n border-bottom: 1px solid #e1e4e8;\n border-radius: 6px 6px 0 0;\n font-weight: bold;\n }\n .diff-file-title .renamed {\n font-weight: normal;\n }\n .diff-file-title .renamed .from {\n color: #cb2431;\n }\n .diff-file-title .renamed .to {\n color: #22863a;\n }\n .diff-file-title .added {\n color: #22863a;\n }\n .diff-file-title .deleted {\n color: #cb2431;\n }\n .diff-file-content {\n }\n .diff-table {\n tab-size: 8;\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n }\n .blob-num {\n position: relative;\n color: #1f2328;\n width: 1%;\n min-width: 50px;\n padding: 0 10px;\n font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n font-size: 12px;\n line-height: 20px;\n text-align: right;\n white-space: nowrap;\n vertical-align: top;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n }\n .blob-num.addition {\n background-color: #ccffd8;\n border-color: #1f883e;\n }\n .blob-num.deletion {\n background-color: #ffd7d5;\n border-color: #cf222e;\n }\n .blob-num::before {\n content: attr(data-line-number);\n }\n .blob-code {\n position: relative;\n padding: 0 10px 0 22px;\n vertical-align: top;\n color: #1f2329;\n }\n .blob-code.code-addition {\n background-color: #e6ffec;\n }\n .blob-code.code-deletion {\n background-color: #ffebe9;\n }\n .blob-code.skip,\n .blob-code.message {\n text-align: center;\n }\n .blob-code.skip .blob-code-inner,\n .blob-code.message .blob-code-inner {\n font-weight: bold;\n color: #6a737d;\n padding: 10px 0;\n }\n .blob-code-inner {\n display: table-cell;\n overflow: visible;\n font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;\n font-size: 12px;\n word-wrap: anywhere;\n white-space: pre-wrap;\n }\n .blob-code-inner::before {\n content: attr(data-code-prefix);\n position: absolute;\n top: 1px;\n left: 8px;\n padding-right: 8px;\n }\n </style>\n </head>\n <body>\n <h1>Changelog Diff</h1>\n\n %FILES%\n </body>\n </html>';diffFileTemplateHandler;diffLineTemplateHandler;contextLines=3;logger;constructor(t){const{oldAssetsPath:o,newAssetsPath:n,destinationPath:i,changelogTemplate:s,diffFileTemplateHandler:r,diffLineTemplateHandler:a,changelogFilename:l,contextLines:d}=t;if(this.logger=h(),!o||!n||!i)throw new Error("Previous assets path, current assets path and destination path are required");if(o===n)throw new Error("Previous and current assets paths must be different");if(!this.isExists(o))throw new Error(`Previous assets path ${o} does not exist`);if(!this.isExists(n))throw new Error(`Current assets path ${n} does not exist`);if(this.isZipFile(o)){const t=e.resolve(E.tmpdir(),j.createHash("md5").update(o).digest("hex"));this.oldAssetsPath=this.unzipFile(o,t).then((()=>this.normalizeAssetFolderPath(t))).then((e=>{if(this.isEmptyFolder(e))throw new Error(`Previous assets path ${e} is empty`);return e}))}else{if(!this.isFolder(o))throw new Error(`Invalid previous assets path ${o}. It must be a folder or a zip file`);{const e=this.normalizeAssetFolderPath(o);if(this.isEmptyFolder(e))throw new Error(`Previous assets path ${e} is empty`);this.oldAssetsPath=Promise.resolve(e)}}if(this.isZipFile(n)){const t=e.resolve(E.tmpdir(),j.createHash("md5").update(n).digest("hex"));this.newAssetsPath=this.unzipFile(n,t).then((()=>this.normalizeAssetFolderPath(t))).then((e=>{if(this.isEmptyFolder(e))throw new Error(`Current assets path ${e} is empty`);return e}))}else{if(!this.isFolder(n))throw new Error(`Invalid current assets path ${n}. It must be a folder or a zip file`);{const e=this.normalizeAssetFolderPath(n);if(this.isEmptyFolder(e))throw new Error(`Current assets path ${n} is empty`);this.newAssetsPath=Promise.resolve(e)}}this.destinationPath=i,this.mkdirpSync(this.destinationPath),this.changelogFilename=l||"CHANGELOG.html",s&&(this.templateIsValid(s)?this.changelogTemplate=s:this.logger.warn(m.yellow("Invalid changelog template, using default"))),"function"==typeof r&&(this.diffFileTemplateHandler=r),"function"==typeof a&&(this.diffLineTemplateHandler=a),d&&(this.contextLines=d)}templateIsValid(e){return e.includes("%FILES%")}isExists(e){return t.existsSync(e)}isZipFile(e){return e.endsWith(".zip")}isFolder(e){return t.lstatSync(e).isDirectory()}isEmptyFolder(e){return 0===t.readdirSync(e,{withFileTypes:!0}).length}mkdirpSync(e){t.existsSync(e)||t.mkdirSync(e,{recursive:!0})}async unzipFile(e,o){return t.rmSync(o,{force:!0,recursive:!0}),z(e,{dir:o})}normalizeAssetFolderPath(o){const n=t.readdirSync(o);return 1===n.length&&t.lstatSync(e.join(o,n[0])).isDirectory()?this.normalizeAssetFolderPath(e.join(o,n[0])):o}pathToPosix(e){return e.replace(/\\/g,"/")}diffTableTemplate(e){return`<table class="diff-table">\n <tbody>\n ${e}\n </tbody>\n </table>`}getDiffTableHTML(e){const t=e.filter(((e,t,o)=>0!==e.lineType||(t>=0&&t<this.contextLines||t>o.length-(this.contextLines+1)&&t<=o.length-1||o.slice(t-this.contextLines,t+this.contextLines+1).some((e=>0!==e.lineType))))).map(((e,t,o)=>{if(t>0){const n=o[t-1];if(e.lineNumber-n.lineNumber>1)return[{lineNumber:-1,lineContent:"",lineType:0},e]}return[e]})).flat().map((e=>this.diffLineHTML(e))).join("");return this.diffTableTemplate(t)}diffLineMessageTemplate(e){return`<tr>\n <td class="blob-num"></td>\n <td class="blob-num"></td>\n <td class="blob-code message">\n <span class="blob-code-inner">${e}</span>\n </td>\n </tr>`}diffLineSkipTemplate(){return'<tr>\n <td class="blob-num"></td>\n <td class="blob-num"></td>\n <td class="blob-code skip">\n <span class="blob-code-inner">Skip</span>\n </td>\n </tr>'}diffLineTemplate(e){const{lineNumber:t,lineContent:o,lineType:n}=e,i=1===n?"addition":-1===n?"deletion":"";return`<tr>\n <td\n class="blob-num ${i}${"addition"===i?" empty":""}"\n ${"addition"!==i?` data-line-number="${t}"`:""}\n ></td>\n <td\n class="blob-num ${i}${"deletion"===i?" empty":""}"\n ${"deletion"!==i?` data-line-number="${t}"`:""}\n ></td>\n <td class="blob-code ${1===n?"code-addition":-1===n?"code-deletion":""}">\n <span class="blob-code-inner" data-code-prefix="${1===n?"+":-1===n?"-":" "}">${s=o??"",s.replace(/[\u00A0-\u9999<>&]/g,(e=>"&#"+e.charCodeAt(0)+";"))}</span>\n </td>\n </tr>`;var s}diffLineHTML(e){if(this.diffLineTemplateHandler)return this.diffLineTemplateHandler(e);const{lineNumber:t}=e;return-1===t?this.diffLineSkipTemplate():this.diffLineTemplate(e)}diffFileTemplate(e,t){return this.diffFileTemplateHandler?this.diffFileTemplateHandler(e,t):`<div class="diff-file">\n <div class="diff-file-title">${e}</div>\n <div class="diff-file-content">${t}</div>\n </div>`}async generateAssetFoldersDiff(){this.logger.info(m.blue(`Comparing asset folders ${await this.oldAssetsPath} and ${await this.newAssetsPath}`));const e=await A.compare(await this.oldAssetsPath,await this.newAssetsPath,{compareContent:!0,skipSymlinks:!0,compareSize:!0,compareDate:!1,compareNameHandler:(e,t)=>(N.test(e)&&(e=e.replace(N,"$1$3")),N.test(t)&&(t=t.replace(N,"$1$3")),0===e.localeCompare(t)?0:e.localeCompare(t)>0?1:-1)});return e.diffSet?.filter((e=>"equal"!==e.state||e.name1!==e.name2))||[]}async generateAssetFilesDiff(e,t){const o=new C,n=o.diff_linesToChars_(e,t),i=o.diff_main(n.chars1,n.chars2,!1);o.diff_charsToLines_(i,n.lineArray);let s=0;return i.map((e=>{const[t,o]=e,n=o.endsWith("\n")?o.split("\n").length-1:o.split("\n").length,i=o.split("\n").map(((e,o)=>({lineContent:e,lineNumber:s+o+1,lineType:t}))).slice(0,n);return-1!==t&&(s+=n),i})).flat()}async generateFilesDiff(o){if("equal"===o.state){const t=this.pathToPosix(e.join(".",o.relativePath,o.name1??"")),n=this.pathToPosix(e.join(".",o.relativePath,o.name2??""));return this.diffFileTemplate(`<span class="renamed"\n >Renamed <span class="from">${t}</span> -> <span class="to">${n}</span></span\n >`,this.diffTableTemplate(this.diffLineMessageTemplate("No changes")))}const n=o.path1&&o.name1?e.join(o.path1,o.name1):null,i=o.path2&&o.name2?e.join(o.path2,o.name2):null,s=this.pathToPosix(e.join(".",o.relativePath,(o.name1||o.name2)??""));if("left"===o.state&&n)return this.diffFileTemplate(`<span class="removed">Removed ${s}</span>`,this.diffTableTemplate(this.diffLineMessageTemplate("File removed")));if("right"===o.state&&i)return this.diffFileTemplate(`<span class="added">Added ${s}</span>`,this.diffTableTemplate(this.diffLineMessageTemplate("File added")));if("distinct"===o.state&&n&&i){const r=this.pathToPosix(e.join(".",o.relativePath,o.name1??"")),a=this.pathToPosix(e.join(".",o.relativePath,o.name2??"")),l=o.name1!==o.name2?`<span class="renamed"\n >Renamed <span class="from">${r}</span> -> <span class="to">${a}</span></span\n >`:s;return this.diffFileTemplate(l,await D(n)||await D(i)?this.diffTableTemplate(this.diffLineMessageTemplate("Binary file")):this.getDiffTableHTML(await this.generateAssetFilesDiff(t.readFileSync(n,"utf-8"),t.readFileSync(i,"utf-8"))))}return""}async generateChangelog(){this.logger.info(m.green("Generating changelog"));const o=await this.generateAssetFoldersDiff(),n=(await Promise.all(o.map((e=>this.generateFilesDiff(e))))).join("");this.logger.info(m.green("Writing changelog file"));const i=this.changelogTemplate.split("%FILES%");i.splice(1,0,n);const s=i.join("");t.writeFileSync(e.join(this.destinationPath,this.changelogFilename),s),this.logger.info(m.green(`Changelog file written to ${e.join(this.destinationPath,this.changelogFilename)}`))}}class U{sourceDir;outputDir;fontName;constructor(e){this.sourceDir=e.sourceDir,this.outputDir=e.outputDir,this.fontName=e.fontName}async generate(){await H({src:this.sourceDir,dist:this.outputDir,fontName:this.fontName,css:!0,typescript:!0,startUnicode:59905,svgicons2svgfont:{fontHeight:1024}})}}const O=n("pp-dev");let q=global.__pp_dev_profile_session,G=0;const V=o=>{if(q)return new Promise(((n,i)=>{q.post("Profiler.stop",((s,{profile:r})=>{if(s)i(s);else{const i=e.resolve(`./pp-dev-profile-${G++}.cpuprofile`);t.writeFileSync(i,JSON.stringify(r)),o(m.yellow(`CPU profile written to ${m.white(m.dim(i))}`)),q=void 0,n()}}))}))},W=e=>{for(const[t,o]of Object.entries(e))Array.isArray(o)&&(e[t]=o[o.length-1])};function B(e){const t={...e};return delete t["--"],delete t.c,delete t.config,delete t.base,delete t.l,delete t.logLevel,delete t.clearScreen,delete t.d,delete t.debug,delete t.f,delete t.filter,delete t.m,delete t.mode,t}O.option("-c, --config <file>","[string] use specified config file").option("--base <path>","[string] public base path (default: /)").option("-l, --logLevel <level>","[string] info | warn | error | silent").option("--clearScreen","[boolean] allow/disable clear screen when logging").option("-d, --debug [feat]","[string | boolean] show debug logs").option("-f, --filter <filter>","[string] filter debug logs").option("-m, --mode <mode>","[string] set env mode"),O.command("[root]","start dev server").alias("serve").alias("dev").option("--host [host]","[string] specify hostname").option("--port <port>","[number] specify port").option("--https","[boolean] use TLS + HTTP/2").option("--open [path]","[boolean | string] open browser on startup").option("--cors","[boolean] enable CORS").option("--strictPort","[boolean] exit if specified port is already in use").option("--force","[boolean] force the optimizer to ignore the cache and re-bundle").action((async(e,t)=>{W(t);const{createServer:n}=await import("vite");try{const a=await i({mode:t.mode||"development",command:"serve"},t.config,e,t.logLevel);let l=await p();const d=s(t.mode||"development",e??_.cwd(),"");if(d&&Object.keys(d).forEach((e=>{e.startsWith("MI_")&&(_.env[e]=d[e])})),a){const{plugins:e,...t}=a.config;l=r(l,t)}const c=await n(r(l,{root:e,base:t.base,mode:t.mode,configFile:t.config,logLevel:t.logLevel,clearScreen:t.clearScreen,optimizeDeps:{force:t.force},server:B(t),customLogger:h(t.logLevel)},!0));if(!c.config.base||"/"===c.config.base)throw new Error('base cannot be equal to "/" or empty string');if(!c.httpServer)throw new Error("HTTP server not available");await c.listen();const g=h(t.logLevel),u=global.__pp_dev_start_time??!1,b=u?m.dim(`ready in ${m.reset(m.bold(Math.ceil(o.now()-u)))} ms`):"";g.info(`\n ${m.green(`${m.bold("PP-DEV")} v${f}`)} ${b}\n`),c.printUrls(),function(e,t){if(!e.httpServer||!process.stdin.isTTY||process.env.CI)return;e._shortcutsOptions=t;const o=h();t.print&&o.info(m.dim(m.green(" ➜"))+m.dim(" press ")+m.bold("h")+m.dim(" to show help"));const n=(t.customShortcuts??[]).filter(I).concat(M);let i=!1;const s=async t=>{if(""===t||""===t)return void await e.close().finally((()=>process.exit(1)));if(i)return;"h"===t&&o.info(["",m.bold(" Shortcuts"),...n.map((e=>m.dim(" press ")+m.bold(e.key)+m.dim(` to ${e.description}`)))].join("\n"));const s=n.find((e=>e.key===t));s&&(i=!0,await s.action(e),i=!1)};process.stdin.setRawMode(!0),process.stdin.on("data",s).setEncoding("utf8").resume(),e.httpServer.on("close",(()=>{process.stdin.off("data",s).pause()}))}(c,{print:!0,customShortcuts:[q&&{key:"p",description:"start/stop the profiler",async action(e){if(q)await V(g.info);else{const e=await import("node:inspector").then((e=>e.default));await new Promise((t=>{q=new e.Session,q.connect(),q.post("Profiler.enable",(()=>{q?.post("Profiler.start",(()=>{g.info("Profiler started"),t()}))}))}))}}},{key:"l",description:"proxy re-login",action(e){e.ws.send({type:"custom",event:"redirect",data:{url:`/auth/index/logout?proxyRedirect=${encodeURIComponent("/")}`}})}}]})}catch(e){const o=h(t.logLevel);o.error(m.red(`error when starting dev server:\n${e.stack}`),{error:e}),V(o.info),_.exit(1)}})),O.command("next [root]","start dev server").alias("next-serve").alias("next-dev").option("--host [host]","[string] specify hostname").option("--port <port>","[number] specify port",{default:3e3}).option("--https","[boolean] use TLS + HTTP/2").option("--open [path]","[boolean | string] open browser on startup").option("--cors","[boolean] enable CORS").option("--strictPort","[boolean] exit if specified port is already in use").option("--force","[boolean] force the optimizer to ignore the cache and re-bundle").action((async(e,t)=>{W(t);const{default:n}=await import("next"),i=h(),r=function(e="info"){const t=F.default(),o=k.createLogger({level:e,format:k.format.cli({level:!0}),transports:[new k.transports.Console]});t.config={logger:o};const n=t.listen;let i;return t.listen=function(...e){i=n.apply(this,e)},t.printUrls=function(e){if(!i)throw new Error("Server is not listening");const t=e=>m.cyan(e.replace(/:(\d+)\//,((e,t)=>`:${m.bold(t)}/`))),n=i.address();if(n&&"object"==typeof n)if("::"===n.address){const i=new $(e||"",`http://localhost:${n.port}`);o.info(` ${m.green("➜")} ${m.bold("Local")}: ${t(i.toString())}`)}else{const i=new $(e||"",`http://[${n.address}]:${n.port}`);o.info(` ${m.green("➜")} ${m.bold("Local")}: ${t(i.toString())}`)}},t}(t.logLevel),a=B(t),l=s(t.mode||"development",e??_.cwd(),"");l&&Object.keys(l).forEach((e=>{e.startsWith("MI_")&&(_.env[e]=l[e])}));const d=n({dev:!0,hostname:a.host,port:a.port});await d.prepare();const c=await d.getServer();let p=c.nextConfig.basePath;const{assetPrefix:A}=c.nextConfig;if(p.endsWith("/")||(p+="/"),"/"===p)throw new Error('basePath cannot be equal to "/" or empty string');const C=p.substring(0,p.lastIndexOf("/")),D=c.nextConfig.serverRuntimeConfig.templateName,E=c.nextConfig.serverRuntimeConfig.ppDevConfig,{backendBaseURL:j,portalPageId:z,appId:H,templateLess:I=!0,enableProxyCache:M=!0,miHudLess:N=!0,proxyCacheTTL:R=6e5,disableSSLValidation:U=!1,v7Features:O=!1,personalAccessToken:q=_.env.MI_ACCESS_TOKEN}=E,G=H??z;if(r.use(g(p,D)),j){let e;try{e=new URL(j).host}catch(e){i.error(m.red(`Invalid backendBaseURL: ${j}`)),_.exit(1)}const t=new u(j,{headers:{host:e,referer:j,origin:j.replace(/^(https?:\/\/)([^/]+)(\/.*)?$/i,"$1$2")},portalPageId:G,templateLess:I,disableSSLValidation:U,v7Features:O,personalAccessToken:q});if(M){let e=+R;(!e||Number.isNaN(e)||e<0)&&(e=6e5),r.use(b({devServer:r,ttl:e}))}const o=["/@vite","/@metricinsights","/@",C];A&&o.push(A),r.use(v({devServer:r,baseURL:j,proxyIgnore:o,disableSSLValidation:U,miAPI:t}));const n=new RegExp(`^((${p})|/)$`);r.use(w(n,t,E)),r.use(y((e=>n.test(L(e))),((o,n)=>Buffer.from(x(e,n.headers.host??"",t.buildPage(o,N)))))),P.post("/@api/login",(async(e,o,n)=>{const{token:s,tokenType:r}=e.body;if(!s)return void o.status(400).json({error:"Token is required"}).end();const a=e=>(i.error(e),n(e),null);if("personal"===r){if(!await t.get("/data/page/index/auth/info",{"Content-Type":"application/json",Accept:"application/json",Authorization:`Bearer ${s}`},!0).then((async e=>{if("number"==typeof e.data?.user?.user_id)return t.personalAccessToken=s,e;o.status(400).json({error:"Token expired or invalid"}).end()})).catch(a))return;T(o,"/",302)}else if("regular"===r){if(!await t.get("/api/user",{"Content-Type":"application/json",Accept:"application/json",Token:s},!0).then((e=>{if(e.data?.users?.length)return t.personalAccessToken=void 0,o.setHeader("set-cookie",e.headers["set-cookie"]??""),e;o.status(400).json({error:"Token expired or invalid"}).end()})).catch(a))return;T(o,"/",302)}})),r.use(P)}const Z=d.getRequestHandler();r.all("*",((e,t)=>{try{if(e.url?.startsWith(A)&&A!==C){const o=e.url.replace(A,C),n=S(o,!0);return n.pathname?Z(e,t,n):(t.statusCode=400,void t.end("Invalid URL"))}const o=S(e.url||"/",!0);if(!o.pathname)return t.statusCode=400,void t.end("Invalid URL");Z(e,t,o)}catch(e){const o=e instanceof Error?e.message:"Unknown error";i.error(m.red(`Error handling request: ${o}`)),t.statusCode=500,t.end("Internal Server Error")}}));try{await new Promise((e=>{a.host?e(r.listen(a.port,a.host,(()=>{}))):e(r.listen(a.port,(()=>{})))}));const e=global.__pp_dev_start_time??!1,t=e?m.dim(`ready in ${m.reset(m.bold(Math.ceil(o.now()-e)))} ms`):"";i.info(`\n ${m.green(`${m.bold("PP-DEV")} v${f}`)} ${t}\n`,{clear:!0}),r.printUrls(p)}catch(e){const o=h(t.logLevel);o.error(m.red(`error when starting dev server:\n${e.stack}`),{error:e}),V(o.info),_.exit(1)}})),O.command("build [root]","build for production").option("--target <target>","[string] transpile target (default: 'modules')").option("--outDir <dir>","[string] output directory (default: dist)").option("--assetsDir <dir>","[string] directory under outDir to place assets in (default: assets)").option("--assetsInlineLimit <number>","[number] static asset base64 inline threshold in bytes (default: 4096)").option("--ssr [entry]","[string] build specified entry for server-side rendering").option("--sourcemap [output]",'[boolean | "inline" | "hidden"] output source maps for build (default: false)').option("--minify [minifier]",'[boolean | "terser" | "esbuild"] enable/disable minification, or specify minifier to use (default: esbuild)').option("--manifest [name]","[boolean | string] emit build manifest json").option("--ssrManifest [name]","[boolean | string] emit ssr manifest json").option("--force","[boolean] force the optimizer to ignore the cache and re-bundle (experimental)").option("--emptyOutDir","[boolean] force empty outDir when it's outside of root").option("-w, --watch","[boolean] rebuilds when modules have changed on disk").option("--changelog [assetsFile]","[boolean | string] generate changelog between assetsFile and current build (default: false)").action((async(o,n)=>{W(n);const s=B(n);try{const l=await i({mode:n.mode||"production",command:"build"},n.config,o,n.logLevel);let d=await p();if(l){const{plugins:e,...t}=l.config;d=r(d,t)}const c=r(d,{root:o,base:n.base,mode:n.mode,configFile:n.config,logLevel:n.logLevel,clearScreen:n.clearScreen,optimizeDeps:{force:n.force},build:s},!0);if(await a(c),s.changelog){const i=o||_.cwd(),r=c.build?.outDir||"dist";let a="";if("string"==typeof s.changelog)a=e.resolve(i,s.changelog);else{const o=e.resolve(i,c.ppDevConfig?.syncBackupsDir||"backups");if(!t.existsSync(o))return void h(n.logLevel).warn(m.yellow("backups directory not found, skipping changelog generation"));const s=t.readdirSync(o,{withFileTypes:!0});if(!s.length)return void h(n.logLevel).warn(m.yellow("no backups found, skipping changelog generation"));const r=s.filter((e=>e.isFile()&&e.name.endsWith(".zip"))).reduce(((n,i)=>t.statSync(e.resolve(o,n.name)).mtimeMs>t.statSync(e.resolve(o,i.name)).mtimeMs?n:i),s[0]).name;a=e.resolve(o,r)}const l=e.resolve(i,r);let d="dist-zip";c.ppDevConfig&&(!1===c.ppDevConfig.distZip?d=c.build?.outDir||"dist":"object"==typeof c.ppDevConfig.distZip&&"string"==typeof c.ppDevConfig.distZip.outDir&&(d=c.ppDevConfig.distZip.outDir));const p=new R({oldAssetsPath:a,newAssetsPath:l,destinationPath:e.resolve(i,d)});await p.generateChangelog()}}catch(e){h(n.logLevel).error(m.red(`error during build:\n${e.stack}`),{error:e}),_.exit(1)}finally{V((e=>h(n.logLevel).info(e)))}})),O.command("changelog [oldAssetPath] [newAssetPath]","generate changelog between two assets files/folders").option("--oldAssetsPath <oldAssetsPath>","[string] path to the old assets zip file or folder").option("--newAssetsPath <newAssetsPath>","[string] path to the new assets zip file or folder").option("--destination <destination>","[string] destination folder for the changelog (default: .)").option("--filename <filename>","[string] filename for the changelog (default: CHANGELOG.html)").action((async(t,o,n)=>{W(n);const{oldAssetsPath:i=t,newAssetsPath:s=o,destination:r=".",filename:a="CHANGELOG.html",logLevel:l}=n,d=_.cwd();i&&s||(h(l).error(m.red("error during changelog generation: oldAssetPath and newAssetPath are required")),_.exit(1));const c=e.resolve(d,i),p=e.resolve(d,s),f=e.resolve(d,r),g=new R({oldAssetsPath:c,newAssetsPath:p,destinationPath:f,changelogFilename:a});await g.generateChangelog()})),O.command("generate-icon-font [source] [destination]","generate icon font from SVG files").option("--source <source>","[string] path to the source directory with SVG files").option("--destination <destination>","[string] path to the destination directory to save the generated font files").option("--font-name, -n <fontName>","[string] name of the font to generate (default: 'icon-font')").action((async(t,o,n)=>{W(n);const{source:i=t,destination:s=o,fontName:r="icon-font"}=n,a=_.cwd(),l=e.resolve(a,i),d=e.resolve(a,s),c=new U({sourceDir:l,outputDir:d,fontName:r}),p=h(n.logLevel);p.info(`Generating icon font from SVG files in ${m.dim(l)}`),await c.generate(),p.info(`Icon font generated and saved to ${m.dim(d)}`)})),O.command("optimize [root]","pre-bundle dependencies").option("--force","[boolean] force the optimizer to ignore the cache and re-bundle").action((async(e,t)=>{W(t);try{const o=await i({mode:t.mode||"production",command:"build"},t.config,e,t.logLevel);let n=await p();if(o){const{plugins:e,...t}=o.config;n=r(n,t)}const s=await l(r(n,{root:e,base:t.base,configFile:t.config,logLevel:t.logLevel,mode:t.mode}),"serve");await d(s,t.force,!0)}catch(e){h(t.logLevel).error(m.red(`error when optimizing deps:\n${e.stack}`),{error:e}),_.exit(1)}})),O.command("preview [root]","locally preview production build").option("--host [host]","[string] specify hostname").option("--port <port>","[number] specify port").option("--strictPort","[boolean] exit if specified port is already in use").option("--https","[boolean] use TLS + HTTP/2").option("--open [path]","[boolean | string] open browser on startup").option("--outDir <dir>","[string] output directory (default: dist)").action((async(e,t)=>{W(t);try{const o=await i({mode:t.mode||"production",command:"build"},t.config,e,t.logLevel);let n=await p();if(o){const{plugins:e,...t}=o.config;n=r(n,t)}(await c(r(n,{root:e,base:t.base,configFile:t.config,logLevel:t.logLevel,mode:t.mode,build:{outDir:t.outDir},preview:{port:t.port,strictPort:t.strictPort,host:t.host,https:t.https,open:t.open}}))).printUrls()}catch(e){h(t.logLevel).error(m.red(`error when starting preview server:\n${e.stack}`),{error:e}),_.exit(1)}finally{V((e=>h(t.logLevel).info(e)))}})),O.help(),O.version(f),O.parse();export{V as stopProfiler};
1174
2
  //# sourceMappingURL=cli.js.map