@julien-lin/universal-pwa-cli 1.2.5 → 1.2.7

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 (3) hide show
  1. package/dist/index.cjs +213 -33
  2. package/dist/index.js +212 -32
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -25,10 +25,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/index.ts
27
27
  var import_commander = require("commander");
28
- var import_chalk4 = __toESM(require("chalk"), 1);
29
- var import_fs4 = require("fs");
28
+ var import_chalk5 = __toESM(require("chalk"), 1);
29
+ var import_fs5 = require("fs");
30
30
  var import_url = require("url");
31
- var import_path4 = require("path");
31
+ var import_path5 = require("path");
32
32
 
33
33
  // src/commands/init.ts
34
34
  var import_universal_pwa_core = require("@julien-lin/universal-pwa-core");
@@ -213,21 +213,46 @@ async function initCommand(options = {}) {
213
213
  try {
214
214
  const htmlFiles = await (0, import_glob.glob)("**/*.html", {
215
215
  cwd: result.projectPath,
216
- ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.nuxt/**"],
216
+ ignore: ["**/node_modules/**", "**/.next/**", "**/.nuxt/**"],
217
217
  absolute: true
218
218
  });
219
+ htmlFiles.sort((a, b) => {
220
+ const aInDist = a.includes("/dist/");
221
+ const bInDist = b.includes("/dist/");
222
+ const aInPublic = a.includes("/public/");
223
+ const bInPublic = b.includes("/public/");
224
+ if (aInDist && !bInDist) return -1;
225
+ if (!aInDist && bInDist) return 1;
226
+ if (aInPublic && !bInPublic) return -1;
227
+ if (!aInPublic && bInPublic) return 1;
228
+ return 0;
229
+ });
219
230
  let injectedCount = 0;
220
231
  for (const htmlFile of htmlFiles.slice(0, 10)) {
221
232
  try {
222
233
  const normalizePathForInjection = (fullPath, basePath, outputDir2, fallback) => {
223
234
  if (!fullPath) return fallback;
224
235
  try {
236
+ const htmlInDist = htmlFile.includes("/dist/");
237
+ const swInDist = fullPath.includes("/dist/");
238
+ if (htmlInDist && swInDist) {
239
+ const distIndex = fullPath.indexOf("/dist/");
240
+ if (distIndex !== -1) {
241
+ const distPath = fullPath.substring(distIndex + 6);
242
+ return distPath.startsWith("/") ? distPath : `/${distPath}`;
243
+ }
244
+ }
225
245
  const rel = relativePath(fullPath, basePath);
226
246
  let normalized = rel.startsWith("/") ? rel : `/${rel}`;
227
247
  const outputDirName = outputDir2.replace(basePath, "").replace(/^\/+|\/+$/g, "");
228
248
  if (outputDirName && normalized.startsWith(`/${outputDirName}/`)) {
229
249
  normalized = normalized.replace(`/${outputDirName}/`, "/");
230
250
  }
251
+ if (normalized.includes("/dist/")) {
252
+ const distIndex = normalized.indexOf("/dist/");
253
+ normalized = normalized.substring(distIndex + 6);
254
+ normalized = normalized.startsWith("/") ? normalized : `/${normalized}`;
255
+ }
231
256
  return normalized;
232
257
  } catch {
233
258
  return fallback;
@@ -347,19 +372,161 @@ function previewCommand(options = {}) {
347
372
  }
348
373
  }
349
374
 
375
+ // src/commands/verify.ts
376
+ var import_fs3 = require("fs");
377
+ var import_path3 = require("path");
378
+ var import_chalk3 = __toESM(require("chalk"), 1);
379
+ function verifyCommand(options = {}) {
380
+ const {
381
+ projectPath = process.cwd(),
382
+ outputDir,
383
+ checkDocker = true
384
+ } = options;
385
+ const result = {
386
+ success: false,
387
+ projectPath: (0, import_path3.resolve)(projectPath),
388
+ outputDir: "",
389
+ filesFound: [],
390
+ filesMissing: [],
391
+ warnings: [],
392
+ errors: [],
393
+ dockerfileFound: false,
394
+ dockerfileNeedsUpdate: false,
395
+ dockerfileSuggestions: []
396
+ };
397
+ try {
398
+ if (!(0, import_fs3.existsSync)(result.projectPath)) {
399
+ result.errors.push(`Project path does not exist: ${result.projectPath}`);
400
+ return result;
401
+ }
402
+ console.log(import_chalk3.default.blue("\u{1F50D} Verifying PWA setup..."));
403
+ const finalOutputDir = outputDir ?? (0, import_path3.join)(result.projectPath, "public");
404
+ result.outputDir = finalOutputDir;
405
+ const requiredFiles = [
406
+ "sw.js",
407
+ "manifest.json",
408
+ "icon-192x192.png",
409
+ "icon-512x512.png",
410
+ "apple-touch-icon.png"
411
+ ];
412
+ const recommendedFiles = [
413
+ "icon-72x72.png",
414
+ "icon-96x96.png",
415
+ "icon-128x128.png",
416
+ "icon-144x144.png",
417
+ "icon-152x152.png",
418
+ "icon-384x384.png"
419
+ ];
420
+ console.log(import_chalk3.default.blue("\u{1F4CB} Checking required PWA files..."));
421
+ for (const file of requiredFiles) {
422
+ const filePath = (0, import_path3.join)(finalOutputDir, file);
423
+ if ((0, import_fs3.existsSync)(filePath)) {
424
+ result.filesFound.push(file);
425
+ console.log(import_chalk3.default.green(` \u2713 ${file}`));
426
+ } else {
427
+ result.filesMissing.push(file);
428
+ result.errors.push(`Missing required file: ${file}`);
429
+ console.log(import_chalk3.default.red(` \u2717 ${file} (MISSING)`));
430
+ }
431
+ }
432
+ console.log(import_chalk3.default.blue("\u{1F4CB} Checking recommended PWA files..."));
433
+ for (const file of recommendedFiles) {
434
+ const filePath = (0, import_path3.join)(finalOutputDir, file);
435
+ if ((0, import_fs3.existsSync)(filePath)) {
436
+ result.filesFound.push(file);
437
+ console.log(import_chalk3.default.green(` \u2713 ${file}`));
438
+ } else {
439
+ result.filesMissing.push(file);
440
+ result.warnings.push(`Missing recommended file: ${file}`);
441
+ console.log(import_chalk3.default.yellow(` \u26A0 ${file} (recommended)`));
442
+ }
443
+ }
444
+ if (checkDocker) {
445
+ const dockerfilePath = (0, import_path3.join)(result.projectPath, "Dockerfile");
446
+ const dockerfileExists = (0, import_fs3.existsSync)(dockerfilePath);
447
+ result.dockerfileFound = dockerfileExists;
448
+ if (dockerfileExists) {
449
+ console.log(import_chalk3.default.blue("\u{1F433} Checking Dockerfile..."));
450
+ const dockerfileContent = (0, import_fs3.readFileSync)(dockerfilePath, "utf-8");
451
+ const pwaFilesInDockerfile = [
452
+ "sw.js",
453
+ "manifest.json",
454
+ "icon-",
455
+ "apple-touch-icon.png"
456
+ ];
457
+ let needsUpdate = false;
458
+ for (const file of pwaFilesInDockerfile) {
459
+ if (!dockerfileContent.includes(file)) {
460
+ needsUpdate = true;
461
+ result.dockerfileNeedsUpdate = true;
462
+ break;
463
+ }
464
+ }
465
+ if (needsUpdate) {
466
+ result.warnings.push("Dockerfile may not copy all PWA files");
467
+ console.log(import_chalk3.default.yellow(" \u26A0 Dockerfile may need updates to copy PWA files"));
468
+ if (!dockerfileContent.includes("sw.js")) {
469
+ result.dockerfileSuggestions.push("COPY sw.js /usr/share/nginx/html/");
470
+ }
471
+ if (!dockerfileContent.includes("manifest.json")) {
472
+ result.dockerfileSuggestions.push("COPY manifest.json /usr/share/nginx/html/");
473
+ }
474
+ if (!dockerfileContent.includes("icon-")) {
475
+ result.dockerfileSuggestions.push("COPY icon-*.png /usr/share/nginx/html/");
476
+ }
477
+ if (!dockerfileContent.includes("apple-touch-icon.png")) {
478
+ result.dockerfileSuggestions.push("COPY apple-touch-icon.png /usr/share/nginx/html/");
479
+ }
480
+ if (result.dockerfileSuggestions.length > 0) {
481
+ console.log(import_chalk3.default.yellow("\n Suggested Dockerfile additions:"));
482
+ result.dockerfileSuggestions.forEach((suggestion) => {
483
+ console.log(import_chalk3.default.gray(` ${suggestion}`));
484
+ });
485
+ }
486
+ } else {
487
+ console.log(import_chalk3.default.green(" \u2713 Dockerfile appears to copy PWA files"));
488
+ }
489
+ } else {
490
+ console.log(import_chalk3.default.gray(" \u2139 No Dockerfile found (skipping Docker checks)"));
491
+ }
492
+ }
493
+ console.log(import_chalk3.default.blue("\u{1F4C4} Checking HTML files..."));
494
+ result.success = result.filesMissing.length === 0 && result.errors.length === 0;
495
+ console.log(import_chalk3.default.blue("\n\u{1F4CA} Summary:"));
496
+ console.log(import_chalk3.default.gray(` Files found: ${result.filesFound.length}`));
497
+ console.log(import_chalk3.default.gray(` Files missing: ${result.filesMissing.length}`));
498
+ console.log(import_chalk3.default.gray(` Warnings: ${result.warnings.length}`));
499
+ console.log(import_chalk3.default.gray(` Errors: ${result.errors.length}`));
500
+ if (result.success) {
501
+ console.log(import_chalk3.default.green("\n\u2705 PWA setup is complete!"));
502
+ } else {
503
+ console.log(import_chalk3.default.red("\n\u274C PWA setup has issues that need to be fixed."));
504
+ if (result.dockerfileNeedsUpdate) {
505
+ console.log(import_chalk3.default.yellow("\n\u{1F4A1} Tip: Update your Dockerfile to copy PWA files."));
506
+ }
507
+ }
508
+ return result;
509
+ } catch (error) {
510
+ const errorMessage = error instanceof Error ? error.message : String(error);
511
+ result.errors.push(`Verification failed: ${errorMessage}`);
512
+ console.log(import_chalk3.default.red(`\u2717 Verification failed: ${errorMessage}`));
513
+ return result;
514
+ }
515
+ }
516
+
350
517
  // src/index.ts
351
518
  var import_universal_pwa_core8 = require("@julien-lin/universal-pwa-core");
352
519
 
353
520
  // src/prompts.ts
354
521
  var import_inquirer = __toESM(require("inquirer"), 1);
355
- var import_fs3 = require("fs");
356
- var import_path3 = require("path");
357
- var import_chalk3 = __toESM(require("chalk"), 1);
522
+ var import_fs4 = require("fs");
523
+ var import_path4 = require("path");
524
+ var import_chalk4 = __toESM(require("chalk"), 1);
358
525
  function detectProjectName(projectPath) {
359
526
  try {
360
- const packageJsonPath2 = (0, import_path3.join)(projectPath, "package.json");
361
- if ((0, import_fs3.existsSync)(packageJsonPath2)) {
362
- const packageJsonContent = (0, import_fs3.readFileSync)(packageJsonPath2, "utf-8");
527
+ const packageJsonPath2 = (0, import_path4.join)(projectPath, "package.json");
528
+ if ((0, import_fs4.existsSync)(packageJsonPath2)) {
529
+ const packageJsonContent = (0, import_fs4.readFileSync)(packageJsonPath2, "utf-8");
363
530
  const packageJson = JSON.parse(packageJsonContent);
364
531
  return packageJson.name || void 0;
365
532
  }
@@ -380,8 +547,8 @@ function findDefaultIconSource(projectPath) {
380
547
  "icon.png"
381
548
  ];
382
549
  for (const path of commonPaths) {
383
- const fullPath = (0, import_path3.join)(projectPath, path);
384
- if ((0, import_fs3.existsSync)(fullPath)) {
550
+ const fullPath = (0, import_path4.join)(projectPath, path);
551
+ if ((0, import_fs4.existsSync)(fullPath)) {
385
552
  return path;
386
553
  }
387
554
  }
@@ -392,7 +559,7 @@ async function promptInitOptions(projectPath, framework) {
392
559
  const defaultIconSource = findDefaultIconSource(projectPath);
393
560
  const defaultName = detectedName || (framework ? `${framework} App` : "My PWA");
394
561
  const defaultShortName = defaultName.substring(0, 12);
395
- console.log(import_chalk3.default.blue("\n\u{1F4CB} Configuration PWA\n"));
562
+ console.log(import_chalk4.default.blue("\n\u{1F4CB} Configuration PWA\n"));
396
563
  const answers = await import_inquirer.default.prompt([
397
564
  {
398
565
  type: "input",
@@ -434,8 +601,8 @@ async function promptInitOptions(projectPath, framework) {
434
601
  if (!input || input.trim().length === 0) {
435
602
  return true;
436
603
  }
437
- const fullPath = (0, import_fs3.existsSync)(input) ? input : (0, import_path3.join)(projectPath, input);
438
- if (!(0, import_fs3.existsSync)(fullPath)) {
604
+ const fullPath = (0, import_fs4.existsSync)(input) ? input : (0, import_path4.join)(projectPath, input);
605
+ if (!(0, import_fs4.existsSync)(fullPath)) {
439
606
  return `Le fichier n'existe pas: ${input}`;
440
607
  }
441
608
  return true;
@@ -491,11 +658,11 @@ async function promptInitOptions(projectPath, framework) {
491
658
  // src/index.ts
492
659
  var import_meta = {};
493
660
  var __filename = (0, import_url.fileURLToPath)(import_meta.url);
494
- var __dirname = (0, import_path4.dirname)(__filename);
495
- var packageJsonPath = (0, import_path4.join)(__dirname, "../package.json");
661
+ var __dirname = (0, import_path5.dirname)(__filename);
662
+ var packageJsonPath = (0, import_path5.join)(__dirname, "../package.json");
496
663
  var version = "0.0.0";
497
664
  try {
498
- const packageJsonContent = (0, import_fs4.readFileSync)(packageJsonPath, "utf-8");
665
+ const packageJsonContent = (0, import_fs5.readFileSync)(packageJsonPath, "utf-8");
499
666
  const packageJson = JSON.parse(packageJsonContent);
500
667
  version = packageJson.version || "0.0.0";
501
668
  } catch {
@@ -509,14 +676,14 @@ program.command("init").description("Initialize PWA in your project").option("-p
509
676
  const hasOptions = options.name || options.shortName || options.iconSource || options.themeColor || options.backgroundColor || options.skipIcons !== void 0;
510
677
  let finalOptions = { ...options };
511
678
  if (!hasOptions) {
512
- console.log(import_chalk4.default.blue("\u{1F50D} Scanning project..."));
679
+ console.log(import_chalk5.default.blue("\u{1F50D} Scanning project..."));
513
680
  const scanResult = await (0, import_universal_pwa_core8.scanProject)({
514
681
  projectPath,
515
682
  includeAssets: false,
516
683
  includeArchitecture: false
517
684
  });
518
- console.log(import_chalk4.default.green(`\u2713 Framework detected: ${scanResult.framework.framework ?? "Unknown"}`));
519
- console.log(import_chalk4.default.green(`\u2713 Architecture: ${scanResult.architecture.architecture}`));
685
+ console.log(import_chalk5.default.green(`\u2713 Framework detected: ${scanResult.framework.framework ?? "Unknown"}`));
686
+ console.log(import_chalk5.default.green(`\u2713 Architecture: ${scanResult.architecture.architecture}`));
520
687
  const promptAnswers = await promptInitOptions(projectPath, scanResult.framework.framework);
521
688
  finalOptions = {
522
689
  ...options,
@@ -542,7 +709,7 @@ program.command("init").description("Initialize PWA in your project").option("-p
542
709
  });
543
710
  process.exit(result.success ? 0 : 1);
544
711
  } catch (error) {
545
- console.error(import_chalk4.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
712
+ console.error(import_chalk5.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
546
713
  process.exit(1);
547
714
  }
548
715
  });
@@ -555,31 +722,44 @@ program.command("preview").description("Preview PWA setup").option("-p, --projec
555
722
  });
556
723
  process.exit(result.success ? 0 : 1);
557
724
  } catch (error) {
558
- console.error(import_chalk4.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
725
+ console.error(import_chalk5.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
559
726
  process.exit(1);
560
727
  }
561
728
  });
562
729
  program.command("scan").description("Scan project and detect framework/architecture").option("-p, --project-path <path>", "Project path", process.cwd()).action(async (options) => {
563
730
  try {
564
- console.log(import_chalk4.default.blue("\u{1F50D} Scanning project..."));
731
+ console.log(import_chalk5.default.blue("\u{1F50D} Scanning project..."));
565
732
  const result = await (0, import_universal_pwa_core8.scanProject)({
566
733
  projectPath: options.projectPath ?? process.cwd(),
567
734
  includeAssets: true,
568
735
  includeArchitecture: true
569
736
  });
570
- console.log(import_chalk4.default.green(`
737
+ console.log(import_chalk5.default.green(`
571
738
  \u2713 Framework: ${result.framework.framework ?? "Unknown"}`));
572
- console.log(import_chalk4.default.green(`\u2713 Architecture: ${result.architecture.architecture}`));
573
- console.log(import_chalk4.default.green(`\u2713 Build Tool: ${result.architecture.buildTool ?? "Unknown"}`));
574
- console.log(import_chalk4.default.gray(`
739
+ console.log(import_chalk5.default.green(`\u2713 Architecture: ${result.architecture.architecture}`));
740
+ console.log(import_chalk5.default.green(`\u2713 Build Tool: ${result.architecture.buildTool ?? "Unknown"}`));
741
+ console.log(import_chalk5.default.gray(`
575
742
  Assets found:`));
576
- console.log(import_chalk4.default.gray(` - JavaScript: ${result.assets.javascript.length} files`));
577
- console.log(import_chalk4.default.gray(` - CSS: ${result.assets.css.length} files`));
578
- console.log(import_chalk4.default.gray(` - Images: ${result.assets.images.length} files`));
579
- console.log(import_chalk4.default.gray(` - Fonts: ${result.assets.fonts.length} files`));
743
+ console.log(import_chalk5.default.gray(` - JavaScript: ${result.assets.javascript.length} files`));
744
+ console.log(import_chalk5.default.gray(` - CSS: ${result.assets.css.length} files`));
745
+ console.log(import_chalk5.default.gray(` - Images: ${result.assets.images.length} files`));
746
+ console.log(import_chalk5.default.gray(` - Fonts: ${result.assets.fonts.length} files`));
580
747
  process.exit(0);
581
748
  } catch (error) {
582
- console.error(import_chalk4.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
749
+ console.error(import_chalk5.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
750
+ process.exit(1);
751
+ }
752
+ });
753
+ program.command("verify").description("Verify PWA setup and check for missing files").option("-p, --project-path <path>", "Project path", process.cwd()).option("-o, --output-dir <dir>", "Output directory", "public").option("--no-docker", "Skip Dockerfile checks").action(async (options) => {
754
+ try {
755
+ const result = await verifyCommand({
756
+ projectPath: options.projectPath,
757
+ outputDir: options.outputDir,
758
+ checkDocker: options.docker !== false
759
+ });
760
+ process.exit(result.success ? 0 : 1);
761
+ } catch (error) {
762
+ console.error(import_chalk5.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
583
763
  process.exit(1);
584
764
  }
585
765
  });
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk4 from "chalk";
6
- import { readFileSync as readFileSync2 } from "fs";
5
+ import chalk5 from "chalk";
6
+ import { readFileSync as readFileSync3 } from "fs";
7
7
  import { fileURLToPath } from "url";
8
- import { dirname, join as join4 } from "path";
8
+ import { dirname, join as join5 } from "path";
9
9
 
10
10
  // src/commands/init.ts
11
11
  import { scanProject } from "@julien-lin/universal-pwa-core";
@@ -190,21 +190,46 @@ async function initCommand(options = {}) {
190
190
  try {
191
191
  const htmlFiles = await glob("**/*.html", {
192
192
  cwd: result.projectPath,
193
- ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.nuxt/**"],
193
+ ignore: ["**/node_modules/**", "**/.next/**", "**/.nuxt/**"],
194
194
  absolute: true
195
195
  });
196
+ htmlFiles.sort((a, b) => {
197
+ const aInDist = a.includes("/dist/");
198
+ const bInDist = b.includes("/dist/");
199
+ const aInPublic = a.includes("/public/");
200
+ const bInPublic = b.includes("/public/");
201
+ if (aInDist && !bInDist) return -1;
202
+ if (!aInDist && bInDist) return 1;
203
+ if (aInPublic && !bInPublic) return -1;
204
+ if (!aInPublic && bInPublic) return 1;
205
+ return 0;
206
+ });
196
207
  let injectedCount = 0;
197
208
  for (const htmlFile of htmlFiles.slice(0, 10)) {
198
209
  try {
199
210
  const normalizePathForInjection = (fullPath, basePath, outputDir2, fallback) => {
200
211
  if (!fullPath) return fallback;
201
212
  try {
213
+ const htmlInDist = htmlFile.includes("/dist/");
214
+ const swInDist = fullPath.includes("/dist/");
215
+ if (htmlInDist && swInDist) {
216
+ const distIndex = fullPath.indexOf("/dist/");
217
+ if (distIndex !== -1) {
218
+ const distPath = fullPath.substring(distIndex + 6);
219
+ return distPath.startsWith("/") ? distPath : `/${distPath}`;
220
+ }
221
+ }
202
222
  const rel = relativePath(fullPath, basePath);
203
223
  let normalized = rel.startsWith("/") ? rel : `/${rel}`;
204
224
  const outputDirName = outputDir2.replace(basePath, "").replace(/^\/+|\/+$/g, "");
205
225
  if (outputDirName && normalized.startsWith(`/${outputDirName}/`)) {
206
226
  normalized = normalized.replace(`/${outputDirName}/`, "/");
207
227
  }
228
+ if (normalized.includes("/dist/")) {
229
+ const distIndex = normalized.indexOf("/dist/");
230
+ normalized = normalized.substring(distIndex + 6);
231
+ normalized = normalized.startsWith("/") ? normalized : `/${normalized}`;
232
+ }
208
233
  return normalized;
209
234
  } catch {
210
235
  return fallback;
@@ -324,19 +349,161 @@ function previewCommand(options = {}) {
324
349
  }
325
350
  }
326
351
 
352
+ // src/commands/verify.ts
353
+ import { existsSync as existsSync3, readFileSync } from "fs";
354
+ import { join as join3, resolve as resolve3 } from "path";
355
+ import chalk3 from "chalk";
356
+ function verifyCommand(options = {}) {
357
+ const {
358
+ projectPath = process.cwd(),
359
+ outputDir,
360
+ checkDocker = true
361
+ } = options;
362
+ const result = {
363
+ success: false,
364
+ projectPath: resolve3(projectPath),
365
+ outputDir: "",
366
+ filesFound: [],
367
+ filesMissing: [],
368
+ warnings: [],
369
+ errors: [],
370
+ dockerfileFound: false,
371
+ dockerfileNeedsUpdate: false,
372
+ dockerfileSuggestions: []
373
+ };
374
+ try {
375
+ if (!existsSync3(result.projectPath)) {
376
+ result.errors.push(`Project path does not exist: ${result.projectPath}`);
377
+ return result;
378
+ }
379
+ console.log(chalk3.blue("\u{1F50D} Verifying PWA setup..."));
380
+ const finalOutputDir = outputDir ?? join3(result.projectPath, "public");
381
+ result.outputDir = finalOutputDir;
382
+ const requiredFiles = [
383
+ "sw.js",
384
+ "manifest.json",
385
+ "icon-192x192.png",
386
+ "icon-512x512.png",
387
+ "apple-touch-icon.png"
388
+ ];
389
+ const recommendedFiles = [
390
+ "icon-72x72.png",
391
+ "icon-96x96.png",
392
+ "icon-128x128.png",
393
+ "icon-144x144.png",
394
+ "icon-152x152.png",
395
+ "icon-384x384.png"
396
+ ];
397
+ console.log(chalk3.blue("\u{1F4CB} Checking required PWA files..."));
398
+ for (const file of requiredFiles) {
399
+ const filePath = join3(finalOutputDir, file);
400
+ if (existsSync3(filePath)) {
401
+ result.filesFound.push(file);
402
+ console.log(chalk3.green(` \u2713 ${file}`));
403
+ } else {
404
+ result.filesMissing.push(file);
405
+ result.errors.push(`Missing required file: ${file}`);
406
+ console.log(chalk3.red(` \u2717 ${file} (MISSING)`));
407
+ }
408
+ }
409
+ console.log(chalk3.blue("\u{1F4CB} Checking recommended PWA files..."));
410
+ for (const file of recommendedFiles) {
411
+ const filePath = join3(finalOutputDir, file);
412
+ if (existsSync3(filePath)) {
413
+ result.filesFound.push(file);
414
+ console.log(chalk3.green(` \u2713 ${file}`));
415
+ } else {
416
+ result.filesMissing.push(file);
417
+ result.warnings.push(`Missing recommended file: ${file}`);
418
+ console.log(chalk3.yellow(` \u26A0 ${file} (recommended)`));
419
+ }
420
+ }
421
+ if (checkDocker) {
422
+ const dockerfilePath = join3(result.projectPath, "Dockerfile");
423
+ const dockerfileExists = existsSync3(dockerfilePath);
424
+ result.dockerfileFound = dockerfileExists;
425
+ if (dockerfileExists) {
426
+ console.log(chalk3.blue("\u{1F433} Checking Dockerfile..."));
427
+ const dockerfileContent = readFileSync(dockerfilePath, "utf-8");
428
+ const pwaFilesInDockerfile = [
429
+ "sw.js",
430
+ "manifest.json",
431
+ "icon-",
432
+ "apple-touch-icon.png"
433
+ ];
434
+ let needsUpdate = false;
435
+ for (const file of pwaFilesInDockerfile) {
436
+ if (!dockerfileContent.includes(file)) {
437
+ needsUpdate = true;
438
+ result.dockerfileNeedsUpdate = true;
439
+ break;
440
+ }
441
+ }
442
+ if (needsUpdate) {
443
+ result.warnings.push("Dockerfile may not copy all PWA files");
444
+ console.log(chalk3.yellow(" \u26A0 Dockerfile may need updates to copy PWA files"));
445
+ if (!dockerfileContent.includes("sw.js")) {
446
+ result.dockerfileSuggestions.push("COPY sw.js /usr/share/nginx/html/");
447
+ }
448
+ if (!dockerfileContent.includes("manifest.json")) {
449
+ result.dockerfileSuggestions.push("COPY manifest.json /usr/share/nginx/html/");
450
+ }
451
+ if (!dockerfileContent.includes("icon-")) {
452
+ result.dockerfileSuggestions.push("COPY icon-*.png /usr/share/nginx/html/");
453
+ }
454
+ if (!dockerfileContent.includes("apple-touch-icon.png")) {
455
+ result.dockerfileSuggestions.push("COPY apple-touch-icon.png /usr/share/nginx/html/");
456
+ }
457
+ if (result.dockerfileSuggestions.length > 0) {
458
+ console.log(chalk3.yellow("\n Suggested Dockerfile additions:"));
459
+ result.dockerfileSuggestions.forEach((suggestion) => {
460
+ console.log(chalk3.gray(` ${suggestion}`));
461
+ });
462
+ }
463
+ } else {
464
+ console.log(chalk3.green(" \u2713 Dockerfile appears to copy PWA files"));
465
+ }
466
+ } else {
467
+ console.log(chalk3.gray(" \u2139 No Dockerfile found (skipping Docker checks)"));
468
+ }
469
+ }
470
+ console.log(chalk3.blue("\u{1F4C4} Checking HTML files..."));
471
+ result.success = result.filesMissing.length === 0 && result.errors.length === 0;
472
+ console.log(chalk3.blue("\n\u{1F4CA} Summary:"));
473
+ console.log(chalk3.gray(` Files found: ${result.filesFound.length}`));
474
+ console.log(chalk3.gray(` Files missing: ${result.filesMissing.length}`));
475
+ console.log(chalk3.gray(` Warnings: ${result.warnings.length}`));
476
+ console.log(chalk3.gray(` Errors: ${result.errors.length}`));
477
+ if (result.success) {
478
+ console.log(chalk3.green("\n\u2705 PWA setup is complete!"));
479
+ } else {
480
+ console.log(chalk3.red("\n\u274C PWA setup has issues that need to be fixed."));
481
+ if (result.dockerfileNeedsUpdate) {
482
+ console.log(chalk3.yellow("\n\u{1F4A1} Tip: Update your Dockerfile to copy PWA files."));
483
+ }
484
+ }
485
+ return result;
486
+ } catch (error) {
487
+ const errorMessage = error instanceof Error ? error.message : String(error);
488
+ result.errors.push(`Verification failed: ${errorMessage}`);
489
+ console.log(chalk3.red(`\u2717 Verification failed: ${errorMessage}`));
490
+ return result;
491
+ }
492
+ }
493
+
327
494
  // src/index.ts
328
495
  import { scanProject as scanProject2 } from "@julien-lin/universal-pwa-core";
329
496
 
330
497
  // src/prompts.ts
331
498
  import inquirer from "inquirer";
332
- import { existsSync as existsSync3, readFileSync } from "fs";
333
- import { join as join3 } from "path";
334
- import chalk3 from "chalk";
499
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
500
+ import { join as join4 } from "path";
501
+ import chalk4 from "chalk";
335
502
  function detectProjectName(projectPath) {
336
503
  try {
337
- const packageJsonPath2 = join3(projectPath, "package.json");
338
- if (existsSync3(packageJsonPath2)) {
339
- const packageJsonContent = readFileSync(packageJsonPath2, "utf-8");
504
+ const packageJsonPath2 = join4(projectPath, "package.json");
505
+ if (existsSync4(packageJsonPath2)) {
506
+ const packageJsonContent = readFileSync2(packageJsonPath2, "utf-8");
340
507
  const packageJson = JSON.parse(packageJsonContent);
341
508
  return packageJson.name || void 0;
342
509
  }
@@ -357,8 +524,8 @@ function findDefaultIconSource(projectPath) {
357
524
  "icon.png"
358
525
  ];
359
526
  for (const path of commonPaths) {
360
- const fullPath = join3(projectPath, path);
361
- if (existsSync3(fullPath)) {
527
+ const fullPath = join4(projectPath, path);
528
+ if (existsSync4(fullPath)) {
362
529
  return path;
363
530
  }
364
531
  }
@@ -369,7 +536,7 @@ async function promptInitOptions(projectPath, framework) {
369
536
  const defaultIconSource = findDefaultIconSource(projectPath);
370
537
  const defaultName = detectedName || (framework ? `${framework} App` : "My PWA");
371
538
  const defaultShortName = defaultName.substring(0, 12);
372
- console.log(chalk3.blue("\n\u{1F4CB} Configuration PWA\n"));
539
+ console.log(chalk4.blue("\n\u{1F4CB} Configuration PWA\n"));
373
540
  const answers = await inquirer.prompt([
374
541
  {
375
542
  type: "input",
@@ -411,8 +578,8 @@ async function promptInitOptions(projectPath, framework) {
411
578
  if (!input || input.trim().length === 0) {
412
579
  return true;
413
580
  }
414
- const fullPath = existsSync3(input) ? input : join3(projectPath, input);
415
- if (!existsSync3(fullPath)) {
581
+ const fullPath = existsSync4(input) ? input : join4(projectPath, input);
582
+ if (!existsSync4(fullPath)) {
416
583
  return `Le fichier n'existe pas: ${input}`;
417
584
  }
418
585
  return true;
@@ -468,10 +635,10 @@ async function promptInitOptions(projectPath, framework) {
468
635
  // src/index.ts
469
636
  var __filename = fileURLToPath(import.meta.url);
470
637
  var __dirname = dirname(__filename);
471
- var packageJsonPath = join4(__dirname, "../package.json");
638
+ var packageJsonPath = join5(__dirname, "../package.json");
472
639
  var version = "0.0.0";
473
640
  try {
474
- const packageJsonContent = readFileSync2(packageJsonPath, "utf-8");
641
+ const packageJsonContent = readFileSync3(packageJsonPath, "utf-8");
475
642
  const packageJson = JSON.parse(packageJsonContent);
476
643
  version = packageJson.version || "0.0.0";
477
644
  } catch {
@@ -485,14 +652,14 @@ program.command("init").description("Initialize PWA in your project").option("-p
485
652
  const hasOptions = options.name || options.shortName || options.iconSource || options.themeColor || options.backgroundColor || options.skipIcons !== void 0;
486
653
  let finalOptions = { ...options };
487
654
  if (!hasOptions) {
488
- console.log(chalk4.blue("\u{1F50D} Scanning project..."));
655
+ console.log(chalk5.blue("\u{1F50D} Scanning project..."));
489
656
  const scanResult = await scanProject2({
490
657
  projectPath,
491
658
  includeAssets: false,
492
659
  includeArchitecture: false
493
660
  });
494
- console.log(chalk4.green(`\u2713 Framework detected: ${scanResult.framework.framework ?? "Unknown"}`));
495
- console.log(chalk4.green(`\u2713 Architecture: ${scanResult.architecture.architecture}`));
661
+ console.log(chalk5.green(`\u2713 Framework detected: ${scanResult.framework.framework ?? "Unknown"}`));
662
+ console.log(chalk5.green(`\u2713 Architecture: ${scanResult.architecture.architecture}`));
496
663
  const promptAnswers = await promptInitOptions(projectPath, scanResult.framework.framework);
497
664
  finalOptions = {
498
665
  ...options,
@@ -518,7 +685,7 @@ program.command("init").description("Initialize PWA in your project").option("-p
518
685
  });
519
686
  process.exit(result.success ? 0 : 1);
520
687
  } catch (error) {
521
- console.error(chalk4.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
688
+ console.error(chalk5.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
522
689
  process.exit(1);
523
690
  }
524
691
  });
@@ -531,31 +698,44 @@ program.command("preview").description("Preview PWA setup").option("-p, --projec
531
698
  });
532
699
  process.exit(result.success ? 0 : 1);
533
700
  } catch (error) {
534
- console.error(chalk4.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
701
+ console.error(chalk5.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
535
702
  process.exit(1);
536
703
  }
537
704
  });
538
705
  program.command("scan").description("Scan project and detect framework/architecture").option("-p, --project-path <path>", "Project path", process.cwd()).action(async (options) => {
539
706
  try {
540
- console.log(chalk4.blue("\u{1F50D} Scanning project..."));
707
+ console.log(chalk5.blue("\u{1F50D} Scanning project..."));
541
708
  const result = await scanProject2({
542
709
  projectPath: options.projectPath ?? process.cwd(),
543
710
  includeAssets: true,
544
711
  includeArchitecture: true
545
712
  });
546
- console.log(chalk4.green(`
713
+ console.log(chalk5.green(`
547
714
  \u2713 Framework: ${result.framework.framework ?? "Unknown"}`));
548
- console.log(chalk4.green(`\u2713 Architecture: ${result.architecture.architecture}`));
549
- console.log(chalk4.green(`\u2713 Build Tool: ${result.architecture.buildTool ?? "Unknown"}`));
550
- console.log(chalk4.gray(`
715
+ console.log(chalk5.green(`\u2713 Architecture: ${result.architecture.architecture}`));
716
+ console.log(chalk5.green(`\u2713 Build Tool: ${result.architecture.buildTool ?? "Unknown"}`));
717
+ console.log(chalk5.gray(`
551
718
  Assets found:`));
552
- console.log(chalk4.gray(` - JavaScript: ${result.assets.javascript.length} files`));
553
- console.log(chalk4.gray(` - CSS: ${result.assets.css.length} files`));
554
- console.log(chalk4.gray(` - Images: ${result.assets.images.length} files`));
555
- console.log(chalk4.gray(` - Fonts: ${result.assets.fonts.length} files`));
719
+ console.log(chalk5.gray(` - JavaScript: ${result.assets.javascript.length} files`));
720
+ console.log(chalk5.gray(` - CSS: ${result.assets.css.length} files`));
721
+ console.log(chalk5.gray(` - Images: ${result.assets.images.length} files`));
722
+ console.log(chalk5.gray(` - Fonts: ${result.assets.fonts.length} files`));
556
723
  process.exit(0);
557
724
  } catch (error) {
558
- console.error(chalk4.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
725
+ console.error(chalk5.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
726
+ process.exit(1);
727
+ }
728
+ });
729
+ program.command("verify").description("Verify PWA setup and check for missing files").option("-p, --project-path <path>", "Project path", process.cwd()).option("-o, --output-dir <dir>", "Output directory", "public").option("--no-docker", "Skip Dockerfile checks").action(async (options) => {
730
+ try {
731
+ const result = await verifyCommand({
732
+ projectPath: options.projectPath,
733
+ outputDir: options.outputDir,
734
+ checkDocker: options.docker !== false
735
+ });
736
+ process.exit(result.success ? 0 : 1);
737
+ } catch (error) {
738
+ console.error(chalk5.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
559
739
  process.exit(1);
560
740
  }
561
741
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@julien-lin/universal-pwa-cli",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "CLI to transform any web project into a PWA",
5
5
  "keywords": [
6
6
  "pwa",
@@ -62,7 +62,7 @@
62
62
  "inquirer": "^12.0.0",
63
63
  "pino": "^9.14.0",
64
64
  "zod": "^4.2.1",
65
- "@julien-lin/universal-pwa-core": "^1.2.5"
65
+ "@julien-lin/universal-pwa-core": "^1.2.7"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@vitest/coverage-v8": "^2.1.4",