basecampjs 0.0.12 → 0.0.14

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 (77) hide show
  1. package/dist/build/assets.d.ts +36 -0
  2. package/dist/build/assets.d.ts.map +1 -0
  3. package/dist/build/assets.js +272 -0
  4. package/dist/build/assets.js.map +1 -0
  5. package/dist/build/data.d.ts +6 -0
  6. package/dist/build/data.d.ts.map +1 -0
  7. package/dist/build/data.js +33 -0
  8. package/dist/build/data.js.map +1 -0
  9. package/dist/build/pages.d.ts +19 -0
  10. package/dist/build/pages.d.ts.map +1 -0
  11. package/dist/build/pages.js +110 -0
  12. package/dist/build/pages.js.map +1 -0
  13. package/dist/build/pipeline.d.ts +6 -0
  14. package/dist/build/pipeline.d.ts.map +1 -0
  15. package/dist/build/pipeline.js +98 -0
  16. package/dist/build/pipeline.js.map +1 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +140 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/config.d.ts +11 -0
  22. package/dist/config.d.ts.map +1 -0
  23. package/dist/config.js +60 -0
  24. package/dist/config.js.map +1 -0
  25. package/dist/dev/server.d.ts +6 -0
  26. package/dist/dev/server.d.ts.map +1 -0
  27. package/dist/dev/server.js +64 -0
  28. package/dist/dev/server.js.map +1 -0
  29. package/dist/dev/watcher.d.ts +5 -0
  30. package/dist/dev/watcher.d.ts.map +1 -0
  31. package/dist/dev/watcher.js +49 -0
  32. package/dist/dev/watcher.js.map +1 -0
  33. package/dist/index.d.ts +17 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +25 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/render/engines.d.ts +30 -0
  38. package/dist/render/engines.d.ts.map +1 -0
  39. package/dist/render/engines.js +102 -0
  40. package/dist/render/engines.js.map +1 -0
  41. package/dist/scaffolding.d.ts +25 -0
  42. package/dist/scaffolding.d.ts.map +1 -0
  43. package/dist/scaffolding.js +596 -0
  44. package/dist/scaffolding.js.map +1 -0
  45. package/dist/types.d.ts +91 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +5 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/utils/fs.d.ts +29 -0
  50. package/dist/utils/fs.d.ts.map +1 -0
  51. package/dist/utils/fs.js +104 -0
  52. package/dist/utils/fs.js.map +1 -0
  53. package/dist/utils/logger.d.ts +9 -0
  54. package/dist/utils/logger.d.ts.map +1 -0
  55. package/dist/utils/logger.js +21 -0
  56. package/dist/utils/logger.js.map +1 -0
  57. package/dist/utils/paths.d.ts +17 -0
  58. package/dist/utils/paths.d.ts.map +1 -0
  59. package/dist/utils/paths.js +55 -0
  60. package/dist/utils/paths.js.map +1 -0
  61. package/package.json +36 -6
  62. package/src/build/assets.ts +314 -0
  63. package/src/build/data.ts +32 -0
  64. package/src/build/pages.ts +143 -0
  65. package/src/build/pipeline.ts +111 -0
  66. package/src/cli.ts +155 -0
  67. package/src/config.ts +61 -0
  68. package/src/dev/server.ts +66 -0
  69. package/src/dev/watcher.ts +52 -0
  70. package/src/index.ts +45 -0
  71. package/src/render/engines.ts +139 -0
  72. package/src/scaffolding.ts +656 -0
  73. package/src/types.ts +110 -0
  74. package/src/utils/fs.ts +109 -0
  75. package/src/utils/logger.ts +27 -0
  76. package/src/utils/paths.ts +56 -0
  77. package/index.js +0 -1516
package/src/types.ts ADDED
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Core type definitions for BasecampJS
3
+ */
4
+
5
+ // Configuration types
6
+ export interface CompressionSettings {
7
+ quality: number;
8
+ formats: string[];
9
+ inputFormats: string[];
10
+ preserveOriginal: boolean;
11
+ }
12
+
13
+ export interface Integrations {
14
+ nunjucks: boolean;
15
+ liquid: boolean;
16
+ mustache: boolean;
17
+ vue: boolean;
18
+ alpine: boolean;
19
+ }
20
+
21
+ export interface ConfigHooks {
22
+ nunjucksEnv?: (env: unknown) => void;
23
+ liquidEnv?: (env: unknown) => void;
24
+ }
25
+
26
+ export interface CampsiteConfig {
27
+ siteName: string;
28
+ siteUrl: string;
29
+ srcDir: string;
30
+ outDir: string;
31
+ templateEngine: 'nunjucks' | 'liquid' | 'mustache' | string;
32
+ frontmatter: boolean;
33
+ minifyCSS: boolean;
34
+ minifyHTML: boolean;
35
+ cacheBustAssets: boolean;
36
+ excludeFiles: string[];
37
+ compressPhotos: boolean;
38
+ compressionSettings: CompressionSettings;
39
+ port: number;
40
+ integrations: Integrations;
41
+ hooks?: ConfigHooks;
42
+ }
43
+
44
+ // Page and rendering types
45
+ export interface PageFrontmatter {
46
+ layout?: string;
47
+ title?: string;
48
+ date?: string;
49
+ author?: string;
50
+ markdown?: boolean;
51
+ [key: string]: unknown;
52
+ }
53
+
54
+ export interface PageContext {
55
+ site: {
56
+ name: string;
57
+ config: CampsiteConfig;
58
+ };
59
+ page: PageFrontmatter & {
60
+ content: string;
61
+ source: string;
62
+ path: string;
63
+ };
64
+ collections: Collections;
65
+ isActive: (url: string) => boolean;
66
+ [key: string]: unknown;
67
+ }
68
+
69
+ export interface RenderOptions {
70
+ pagesDir: string;
71
+ layoutsDir: string;
72
+ outDir: string;
73
+ env: unknown; // Nunjucks environment
74
+ liquidEnv: unknown; // Liquid environment
75
+ config: CampsiteConfig;
76
+ data: Collections;
77
+ partialsDir: string;
78
+ }
79
+
80
+ // Data types
81
+ export type Collections = Record<string, unknown[]>;
82
+
83
+ // Build options
84
+ export interface BuildOptions {
85
+ skipImageCompression?: boolean;
86
+ devMode?: boolean;
87
+ }
88
+
89
+ // Asset processing types
90
+ export interface ProcessedImage {
91
+ path: string;
92
+ format: string;
93
+ size: number;
94
+ }
95
+
96
+ export interface AssetMap {
97
+ [originalPath: string]: string;
98
+ }
99
+
100
+ // Sitemap types
101
+ export interface SitemapUrl {
102
+ loc: string;
103
+ lastmod: string;
104
+ }
105
+
106
+ // Make content result
107
+ export interface MakeContentResult {
108
+ success: boolean;
109
+ skipped: boolean;
110
+ }
@@ -0,0 +1,109 @@
1
+ import { existsSync } from "fs";
2
+ import { cp, mkdir, readdir, rm, stat, writeFile } from "fs/promises";
3
+ import { basename, dirname, extname, join, relative } from "path";
4
+ import { kolor } from "./logger.js";
5
+
6
+ /**
7
+ * Ensure a directory exists (creates recursively if needed)
8
+ */
9
+ export async function ensureDir(dir: string): Promise<void> {
10
+ await mkdir(dir, { recursive: true });
11
+ }
12
+
13
+ /**
14
+ * Clean (remove and recreate) a directory
15
+ */
16
+ export async function cleanDir(dir: string): Promise<void> {
17
+ await rm(dir, { recursive: true, force: true });
18
+ await mkdir(dir, { recursive: true });
19
+ }
20
+
21
+ /**
22
+ * Recursively walk a directory and return all file paths
23
+ */
24
+ export async function walkFiles(dir: string): Promise<string[]> {
25
+ const results: string[] = [];
26
+ if (!existsSync(dir)) return results;
27
+ const entries = await readdir(dir, { withFileTypes: true });
28
+ for (const entry of entries) {
29
+ if (entry.name.startsWith(".")) continue;
30
+ const full = join(dir, entry.name);
31
+ if (entry.isDirectory()) {
32
+ results.push(...await walkFiles(full));
33
+ } else {
34
+ results.push(full);
35
+ }
36
+ }
37
+ return results;
38
+ }
39
+
40
+ /**
41
+ * Get file extension in lowercase
42
+ */
43
+ export function getExt(filePath: string): string {
44
+ return extname(filePath).toLowerCase();
45
+ }
46
+
47
+ /**
48
+ * Check if a file should be excluded based on patterns
49
+ */
50
+ export function shouldExcludeFile(filePath: string, excludePatterns: string[] | undefined): boolean {
51
+ if (!excludePatterns || excludePatterns.length === 0) return false;
52
+
53
+ const fileName = basename(filePath).toLowerCase();
54
+ const ext = getExt(filePath);
55
+
56
+ return excludePatterns.some(pattern => {
57
+ const normalized = pattern.toLowerCase();
58
+ // Support extension patterns like '.pdf' or 'pdf'
59
+ if (normalized.startsWith('.')) {
60
+ return ext === normalized;
61
+ }
62
+ if (normalized.startsWith('*.')) {
63
+ return ext === normalized.slice(1);
64
+ }
65
+ // Support exact filename matches
66
+ if (fileName === normalized) {
67
+ return true;
68
+ }
69
+ // Support glob-like patterns with wildcards
70
+ if (normalized.includes('*')) {
71
+ const regex = new RegExp('^' + normalized.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
72
+ return regex.test(fileName);
73
+ }
74
+ return false;
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Copy public directory to output, respecting exclusions
80
+ */
81
+ export async function copyPublic(publicDir: string, outDir: string, excludePatterns: string[] = []): Promise<void> {
82
+ if (!existsSync(publicDir)) return;
83
+
84
+ const files = await walkFiles(publicDir);
85
+ for (const file of files) {
86
+ const rel = relative(publicDir, file);
87
+
88
+ // Skip excluded files
89
+ if (shouldExcludeFile(file, excludePatterns)) {
90
+ console.log(kolor.dim(`Skipping excluded file: ${rel}`));
91
+ continue;
92
+ }
93
+
94
+ const destPath = join(outDir, rel);
95
+ await ensureDir(dirname(destPath));
96
+ await cp(file, destPath);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Format bytes to human-readable string
102
+ */
103
+ export function formatBytes(bytes: number): string {
104
+ if (bytes === 0) return "0 B";
105
+ const k = 1024;
106
+ const sizes = ["B", "KB", "MB", "GB"];
107
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
108
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
109
+ }
@@ -0,0 +1,27 @@
1
+ import * as kolor from "kolorist";
2
+
3
+ export { kolor };
4
+
5
+ export function logError(message: string): void {
6
+ console.error(kolor.red(message));
7
+ }
8
+
9
+ export function logWarning(message: string): void {
10
+ console.log(kolor.yellow(message));
11
+ }
12
+
13
+ export function logSuccess(message: string): void {
14
+ console.log(kolor.green(message));
15
+ }
16
+
17
+ export function logInfo(message: string): void {
18
+ console.log(kolor.cyan(message));
19
+ }
20
+
21
+ export function logDim(message: string): void {
22
+ console.log(kolor.dim(message));
23
+ }
24
+
25
+ export function logBold(message: string): void {
26
+ console.log(kolor.bold(message));
27
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Convert output-relative path to URL path
3
+ */
4
+ export function toUrlPath(outRel: string): string {
5
+ const normalized = outRel.replace(/\\/g, "/");
6
+ let path = `/${normalized}`;
7
+ // Remove trailing index.html for directory-style URLs
8
+ if (path.endsWith("index.html")) {
9
+ path = path.slice(0, -"index.html".length);
10
+ }
11
+ // Strip trailing slash except for root
12
+ if (path !== "/" && path.endsWith("/")) {
13
+ path = path.slice(0, -1);
14
+ }
15
+ return path || "/";
16
+ }
17
+
18
+ /**
19
+ * Normalize a URL for comparison (strips trailing slashes, .html extension)
20
+ */
21
+ export function normalizeUrl(url: string | undefined | null): string {
22
+ if (!url) return "/";
23
+ let normalized = url.trim();
24
+ // Remove trailing slashes except for root
25
+ if (normalized !== "/" && normalized.endsWith("/")) {
26
+ normalized = normalized.slice(0, -1);
27
+ }
28
+ // Add leading slash if missing
29
+ if (!normalized.startsWith("/")) {
30
+ normalized = "/" + normalized;
31
+ }
32
+ // Strip .html extension for comparison (so /about and /about.html match)
33
+ if (normalized !== "/" && normalized.endsWith(".html")) {
34
+ normalized = normalized.slice(0, -5);
35
+ }
36
+ return normalized;
37
+ }
38
+
39
+ /**
40
+ * Slugify text for use in URLs
41
+ */
42
+ export function slugify(text: string): string {
43
+ return text
44
+ .toLowerCase()
45
+ .trim()
46
+ .replace(/[^\w\s-]/g, "")
47
+ .replace(/[\s_-]+/g, "-")
48
+ .replace(/^-+|-+$/g, "");
49
+ }
50
+
51
+ /**
52
+ * Format a date to ISO date string (YYYY-MM-DD)
53
+ */
54
+ export function formatDate(date: Date): string {
55
+ return date.toISOString().split("T")[0];
56
+ }