webspresso 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -715,6 +715,17 @@ The `fsy` object is available in all templates:
715
715
  {{ fsy.prettyBytes(1024) }}
716
716
  {{ fsy.prettyMs(5000) }}
717
717
 
718
+ {# Date/Time helpers (dayjs) #}
719
+ {{ fsy.dateFormat(post.created_at, 'YYYY-MM-DD HH:mm') }}
720
+ {{ fsy.dateFromNow(post.created_at) }} {# "2 hours ago" #}
721
+ {{ fsy.dateAgo(post.created_at) }} {# "2 hours ago" #}
722
+ {{ fsy.dateUntil(event.date) }} {# "in 2 hours" #}
723
+ {{ fsy.date(post.created_at).format('MMMM D, YYYY') }} {# Full dayjs API #}
724
+ {% if fsy.dateIsBefore(post.created_at, fsy.date()) %}Published{% endif %}
725
+ {{ fsy.dateDiff(post.created_at, fsy.date(), 'day') }} days ago
726
+ {{ fsy.dateAdd(post.created_at, 7, 'day').format('YYYY-MM-DD') }}
727
+ {{ fsy.dateStartOf(post.created_at, 'month').format('YYYY-MM-DD') }}
728
+
718
729
  {# Environment #}
719
730
  {% if fsy.isDev() %}Dev mode{% endif %}
720
731
 
package/bin/webspresso.js CHANGED
@@ -9,7 +9,7 @@ const { program } = require('commander');
9
9
  const inquirer = require('inquirer');
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
- const { spawn } = require('child_process');
12
+ const { spawn, execSync } = require('child_process');
13
13
 
14
14
  program
15
15
  .name('webspresso')
@@ -1493,8 +1493,66 @@ program
1493
1493
  faker = require('@faker-js/faker');
1494
1494
  } catch {
1495
1495
  console.error('āŒ @faker-js/faker not installed.');
1496
- console.log(' Install it with: npm install @faker-js/faker');
1497
- process.exit(1);
1496
+
1497
+ // Check if it's in package.json
1498
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
1499
+ let shouldInstall = false;
1500
+
1501
+ if (fs.existsSync(packageJsonPath)) {
1502
+ try {
1503
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
1504
+ const hasFaker = packageJson.dependencies?.['@faker-js/faker'] ||
1505
+ packageJson.devDependencies?.['@faker-js/faker'];
1506
+
1507
+ if (hasFaker) {
1508
+ console.log(' @faker-js/faker is in package.json but not installed.');
1509
+ console.log(' Run: npm install');
1510
+ process.exit(1);
1511
+ } else {
1512
+ // Ask if user wants to install it
1513
+ const { install } = await inquirer.prompt([
1514
+ {
1515
+ type: 'confirm',
1516
+ name: 'install',
1517
+ message: 'Install @faker-js/faker now?',
1518
+ default: true
1519
+ }
1520
+ ]);
1521
+
1522
+ if (install) {
1523
+ shouldInstall = true;
1524
+ } else {
1525
+ console.log(' Install it manually with: npm install @faker-js/faker');
1526
+ process.exit(1);
1527
+ }
1528
+ }
1529
+ } catch (err) {
1530
+ console.log(' Install it with: npm install @faker-js/faker');
1531
+ process.exit(1);
1532
+ }
1533
+ } else {
1534
+ console.log(' Install it with: npm install @faker-js/faker');
1535
+ process.exit(1);
1536
+ }
1537
+
1538
+ // Install faker if user confirmed
1539
+ if (shouldInstall) {
1540
+ console.log('\nšŸ“¦ Installing @faker-js/faker...\n');
1541
+ try {
1542
+ execSync('npm install @faker-js/faker', {
1543
+ stdio: 'inherit',
1544
+ cwd: process.cwd()
1545
+ });
1546
+ console.log('\nāœ… @faker-js/faker installed successfully!\n');
1547
+
1548
+ // Try to require again
1549
+ faker = require('@faker-js/faker');
1550
+ } catch (err) {
1551
+ console.error('\nāŒ Failed to install @faker-js/faker:', err.message);
1552
+ console.log(' Install it manually with: npm install @faker-js/faker');
1553
+ process.exit(1);
1554
+ }
1555
+ }
1498
1556
  }
1499
1557
 
1500
1558
  // Load database config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -38,6 +38,7 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "commander": "^11.1.0",
41
+ "dayjs": "^1.11.19",
41
42
  "express": "^4.18.2",
42
43
  "helmet": "^7.2.0",
43
44
  "inquirer": "^8.2.6",
@@ -46,11 +47,11 @@
46
47
  "zod": "^3.23.0"
47
48
  },
48
49
  "peerDependencies": {
50
+ "@faker-js/faker": "^9.0.0",
51
+ "better-sqlite3": "^9.0.0",
49
52
  "dotenv": "^16.0.0",
50
- "pg": "^8.0.0",
51
53
  "mysql2": "^3.0.0",
52
- "better-sqlite3": "^9.0.0",
53
- "@faker-js/faker": "^9.0.0"
54
+ "pg": "^8.0.0"
54
55
  },
55
56
  "peerDependenciesMeta": {
56
57
  "dotenv": {
package/src/helpers.js CHANGED
@@ -6,6 +6,17 @@
6
6
  const querystring = require('querystring');
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
+ const dayjs = require('dayjs');
10
+ const relativeTime = require('dayjs/plugin/relativeTime');
11
+ const utc = require('dayjs/plugin/utc');
12
+ const timezone = require('dayjs/plugin/timezone');
13
+ const customParseFormat = require('dayjs/plugin/customParseFormat');
14
+
15
+ // Extend dayjs with plugins
16
+ dayjs.extend(relativeTime);
17
+ dayjs.extend(utc);
18
+ dayjs.extend(timezone);
19
+ dayjs.extend(customParseFormat);
9
20
 
10
21
  /**
11
22
  * Asset Manager - handles asset paths, versioning, and manifest
@@ -419,6 +430,157 @@ function createHelpers(ctx) {
419
430
  */
420
431
  img(src, alt = '', attrs = {}) {
421
432
  return getAssetManager().img(src, alt, attrs);
433
+ },
434
+
435
+ /**
436
+ * Date/time helpers using dayjs
437
+ */
438
+
439
+ /**
440
+ * Create a dayjs instance from a date
441
+ * @param {string|Date|number} date - Date to parse
442
+ * @param {string} format - Optional format string
443
+ * @returns {Object} dayjs instance
444
+ */
445
+ date(date, format) {
446
+ if (!date) return dayjs();
447
+ if (format) {
448
+ return dayjs(date, format);
449
+ }
450
+ return dayjs(date);
451
+ },
452
+
453
+ /**
454
+ * Format a date
455
+ * @param {string|Date|number} date - Date to format
456
+ * @param {string} format - Format string (default: 'YYYY-MM-DD')
457
+ * @returns {string}
458
+ */
459
+ dateFormat(date, format = 'YYYY-MM-DD') {
460
+ if (!date) return '';
461
+ return dayjs(date).format(format);
462
+ },
463
+
464
+ /**
465
+ * Get relative time (e.g., "2 hours ago")
466
+ * @param {string|Date|number} date - Date to format
467
+ * @returns {string}
468
+ */
469
+ dateFromNow(date) {
470
+ if (!date) return '';
471
+ return dayjs(date).fromNow();
472
+ },
473
+
474
+ /**
475
+ * Get time ago (e.g., "2 hours ago")
476
+ * @param {string|Date|number} date - Date to format
477
+ * @returns {string}
478
+ */
479
+ dateAgo(date) {
480
+ if (!date) return '';
481
+ return dayjs(date).fromNow();
482
+ },
483
+
484
+ /**
485
+ * Get time until (e.g., "in 2 hours")
486
+ * @param {string|Date|number} date - Date to format
487
+ * @returns {string}
488
+ */
489
+ dateUntil(date) {
490
+ if (!date) return '';
491
+ return dayjs(date).toNow();
492
+ },
493
+
494
+ /**
495
+ * Check if date is before another date
496
+ * @param {string|Date|number} date1 - First date
497
+ * @param {string|Date|number} date2 - Second date
498
+ * @returns {boolean}
499
+ */
500
+ dateIsBefore(date1, date2) {
501
+ if (!date1 || !date2) return false;
502
+ return dayjs(date1).isBefore(date2);
503
+ },
504
+
505
+ /**
506
+ * Check if date is after another date
507
+ * @param {string|Date|number} date1 - First date
508
+ * @param {string|Date|number} date2 - Second date
509
+ * @returns {boolean}
510
+ */
511
+ dateIsAfter(date1, date2) {
512
+ if (!date1 || !date2) return false;
513
+ return dayjs(date1).isAfter(date2);
514
+ },
515
+
516
+ /**
517
+ * Check if date is same as another date
518
+ * @param {string|Date|number} date1 - First date
519
+ * @param {string|Date|number} date2 - Second date
520
+ * @param {string} unit - Unit to compare (day, month, year, etc.)
521
+ * @returns {boolean}
522
+ */
523
+ dateIsSame(date1, date2, unit = 'day') {
524
+ if (!date1 || !date2) return false;
525
+ return dayjs(date1).isSame(date2, unit);
526
+ },
527
+
528
+ /**
529
+ * Get difference between two dates
530
+ * @param {string|Date|number} date1 - First date
531
+ * @param {string|Date|number} date2 - Second date
532
+ * @param {string} unit - Unit (day, month, year, hour, minute, second)
533
+ * @returns {number}
534
+ */
535
+ dateDiff(date1, date2, unit = 'day') {
536
+ if (!date1 || !date2) return 0;
537
+ return dayjs(date1).diff(date2, unit);
538
+ },
539
+
540
+ /**
541
+ * Add time to a date
542
+ * @param {string|Date|number} date - Date to add to
543
+ * @param {number} amount - Amount to add
544
+ * @param {string} unit - Unit (day, month, year, hour, minute, second)
545
+ * @returns {Object} dayjs instance
546
+ */
547
+ dateAdd(date, amount, unit = 'day') {
548
+ if (!date) return dayjs();
549
+ return dayjs(date).add(amount, unit);
550
+ },
551
+
552
+ /**
553
+ * Subtract time from a date
554
+ * @param {string|Date|number} date - Date to subtract from
555
+ * @param {number} amount - Amount to subtract
556
+ * @param {string} unit - Unit (day, month, year, hour, minute, second)
557
+ * @returns {Object} dayjs instance
558
+ */
559
+ dateSubtract(date, amount, unit = 'day') {
560
+ if (!date) return dayjs();
561
+ return dayjs(date).subtract(amount, unit);
562
+ },
563
+
564
+ /**
565
+ * Get start of a time period
566
+ * @param {string|Date|number} date - Date
567
+ * @param {string} unit - Unit (day, month, year, week)
568
+ * @returns {Object} dayjs instance
569
+ */
570
+ dateStartOf(date, unit = 'day') {
571
+ if (!date) return dayjs();
572
+ return dayjs(date).startOf(unit);
573
+ },
574
+
575
+ /**
576
+ * Get end of a time period
577
+ * @param {string|Date|number} date - Date
578
+ * @param {string} unit - Unit (day, month, year, week)
579
+ * @returns {Object} dayjs instance
580
+ */
581
+ dateEndOf(date, unit = 'day') {
582
+ if (!date) return dayjs();
583
+ return dayjs(date).endOf(unit);
422
584
  }
423
585
  };
424
586
  }