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.
- package/dist/build/assets.d.ts +36 -0
- package/dist/build/assets.d.ts.map +1 -0
- package/dist/build/assets.js +272 -0
- package/dist/build/assets.js.map +1 -0
- package/dist/build/data.d.ts +6 -0
- package/dist/build/data.d.ts.map +1 -0
- package/dist/build/data.js +33 -0
- package/dist/build/data.js.map +1 -0
- package/dist/build/pages.d.ts +19 -0
- package/dist/build/pages.d.ts.map +1 -0
- package/dist/build/pages.js +110 -0
- package/dist/build/pages.js.map +1 -0
- package/dist/build/pipeline.d.ts +6 -0
- package/dist/build/pipeline.d.ts.map +1 -0
- package/dist/build/pipeline.js +98 -0
- package/dist/build/pipeline.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +140 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/dev/server.d.ts +6 -0
- package/dist/dev/server.d.ts.map +1 -0
- package/dist/dev/server.js +64 -0
- package/dist/dev/server.js.map +1 -0
- package/dist/dev/watcher.d.ts +5 -0
- package/dist/dev/watcher.d.ts.map +1 -0
- package/dist/dev/watcher.js +49 -0
- package/dist/dev/watcher.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/render/engines.d.ts +30 -0
- package/dist/render/engines.d.ts.map +1 -0
- package/dist/render/engines.js +102 -0
- package/dist/render/engines.js.map +1 -0
- package/dist/scaffolding.d.ts +25 -0
- package/dist/scaffolding.d.ts.map +1 -0
- package/dist/scaffolding.js +596 -0
- package/dist/scaffolding.js.map +1 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/fs.d.ts +29 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +104 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +21 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +17 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +55 -0
- package/dist/utils/paths.js.map +1 -0
- package/package.json +36 -6
- package/src/build/assets.ts +314 -0
- package/src/build/data.ts +32 -0
- package/src/build/pages.ts +143 -0
- package/src/build/pipeline.ts +111 -0
- package/src/cli.ts +155 -0
- package/src/config.ts +61 -0
- package/src/dev/server.ts +66 -0
- package/src/dev/watcher.ts +52 -0
- package/src/index.ts +45 -0
- package/src/render/engines.ts +139 -0
- package/src/scaffolding.ts +656 -0
- package/src/types.ts +110 -0
- package/src/utils/fs.ts +109 -0
- package/src/utils/logger.ts +27 -0
- package/src/utils/paths.ts +56 -0
- 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
|
+
}
|
package/src/utils/fs.ts
ADDED
|
@@ -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
|
+
}
|