bunki 0.6.0 → 0.7.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.
- package/README.md +430 -406
- package/dist/cli/commands/images-push.d.ts +1 -0
- package/dist/cli.js +132 -124
- package/dist/index.js +96 -91
- package/dist/types.d.ts +3 -1
- package/dist/utils/css-processor.d.ts +2 -1
- package/dist/utils/file-utils.d.ts +140 -0
- package/dist/utils/s3-uploader.d.ts +1 -1
- package/package.json +2 -2
|
@@ -9,6 +9,7 @@ export declare function handleImagesPushCommand(options: {
|
|
|
9
9
|
domain?: string;
|
|
10
10
|
images: string;
|
|
11
11
|
outputJson?: string;
|
|
12
|
+
minYear?: string;
|
|
12
13
|
}, deps?: ImagesPushDeps): Promise<void>;
|
|
13
14
|
export declare function registerImagesPushCommand(program: Command): Command;
|
|
14
15
|
export {};
|
package/dist/cli.js
CHANGED
|
@@ -28185,7 +28185,7 @@ function getDefaultConfig() {
|
|
|
28185
28185
|
return base;
|
|
28186
28186
|
}
|
|
28187
28187
|
async function createDefaultConfig(configPath = DEFAULT_CONFIG_FILE) {
|
|
28188
|
-
if (await configExists()) {
|
|
28188
|
+
if (await configExists(configPath)) {
|
|
28189
28189
|
console.log(`Config file already exists`);
|
|
28190
28190
|
return false;
|
|
28191
28191
|
}
|
|
@@ -28243,15 +28243,6 @@ async function processCSS(options2) {
|
|
|
28243
28243
|
} catch (error) {
|
|
28244
28244
|
throw new Error(`CSS input file not found: ${inputPath}`);
|
|
28245
28245
|
}
|
|
28246
|
-
let postcssConfigExists = false;
|
|
28247
|
-
try {
|
|
28248
|
-
await fs.promises.access(postcssConfigPath);
|
|
28249
|
-
postcssConfigExists = true;
|
|
28250
|
-
} catch (error) {
|
|
28251
|
-
if (verbose) {
|
|
28252
|
-
console.log(`PostCSS config not found at ${postcssConfigPath}, will fallback to simple copy`);
|
|
28253
|
-
}
|
|
28254
|
-
}
|
|
28255
28246
|
const outputDirPath = path2.dirname(outputPath);
|
|
28256
28247
|
await fs.promises.mkdir(outputDirPath, { recursive: true });
|
|
28257
28248
|
if (verbose) {
|
|
@@ -28260,71 +28251,40 @@ async function processCSS(options2) {
|
|
|
28260
28251
|
console.log(`Output: ${outputPath}`);
|
|
28261
28252
|
console.log(`Config: ${postcssConfigPath}`);
|
|
28262
28253
|
}
|
|
28263
|
-
|
|
28264
|
-
|
|
28265
|
-
|
|
28266
|
-
|
|
28267
|
-
|
|
28268
|
-
|
|
28269
|
-
|
|
28270
|
-
|
|
28271
|
-
|
|
28272
|
-
|
|
28273
|
-
|
|
28274
|
-
|
|
28275
|
-
|
|
28276
|
-
|
|
28277
|
-
|
|
28254
|
+
await runPostCSS(inputPath, outputPath, postcssConfigPath, projectRoot, verbose);
|
|
28255
|
+
}
|
|
28256
|
+
function runPostCSS(inputPath, outputPath, configPath, projectRoot, verbose) {
|
|
28257
|
+
return new Promise((resolve, reject) => {
|
|
28258
|
+
const args = [
|
|
28259
|
+
"postcss",
|
|
28260
|
+
inputPath,
|
|
28261
|
+
"-o",
|
|
28262
|
+
outputPath,
|
|
28263
|
+
"--config",
|
|
28264
|
+
configPath
|
|
28265
|
+
];
|
|
28266
|
+
const postcss = spawn("bunx", args, {
|
|
28267
|
+
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
28268
|
+
cwd: projectRoot
|
|
28269
|
+
});
|
|
28270
|
+
let errorOutput = "";
|
|
28271
|
+
if (!verbose) {
|
|
28272
|
+
postcss.stderr?.on("data", (data) => {
|
|
28273
|
+
errorOutput += data.toString();
|
|
28278
28274
|
});
|
|
28279
|
-
|
|
28280
|
-
|
|
28281
|
-
|
|
28282
|
-
|
|
28283
|
-
|
|
28275
|
+
}
|
|
28276
|
+
postcss.on("close", (code) => {
|
|
28277
|
+
if (code === 0) {
|
|
28278
|
+
if (verbose)
|
|
28279
|
+
console.log("\u2705 CSS build completed successfully!");
|
|
28280
|
+
return resolve();
|
|
28284
28281
|
}
|
|
28285
|
-
|
|
28286
|
-
if (code === 0) {
|
|
28287
|
-
if (verbose)
|
|
28288
|
-
console.log("\u2705 CSS build completed successfully!");
|
|
28289
|
-
return resolve();
|
|
28290
|
-
}
|
|
28291
|
-
if (/module is not defined in ES module scope/i.test(errorOutput) && configPathToUse.endsWith(".js")) {
|
|
28292
|
-
const cjsPath = configPathToUse.replace(/\.js$/, ".cjs");
|
|
28293
|
-
try {
|
|
28294
|
-
if (!fs.existsSync(cjsPath)) {
|
|
28295
|
-
const original = await fs.promises.readFile(configPathToUse, "utf-8");
|
|
28296
|
-
await fs.promises.writeFile(cjsPath, original, "utf-8");
|
|
28297
|
-
if (verbose) {
|
|
28298
|
-
console.log(`Retrying PostCSS with converted CommonJS config at ${cjsPath}`);
|
|
28299
|
-
}
|
|
28300
|
-
}
|
|
28301
|
-
return resolve(runPostCSS(cjsPath));
|
|
28302
|
-
} catch (e) {
|
|
28303
|
-
if (verbose)
|
|
28304
|
-
console.warn("CJS fallback failed, copying CSS.");
|
|
28305
|
-
await fs.promises.copyFile(inputPath, outputPath);
|
|
28306
|
-
return resolve();
|
|
28307
|
-
}
|
|
28308
|
-
}
|
|
28309
|
-
if (verbose) {
|
|
28310
|
-
console.warn(`PostCSS failed (code ${code}). Falling back to simple copy. Error: ${errorOutput.trim()}`);
|
|
28311
|
-
}
|
|
28312
|
-
try {
|
|
28313
|
-
await fs.promises.copyFile(inputPath, outputPath);
|
|
28314
|
-
resolve();
|
|
28315
|
-
} catch (copyErr) {
|
|
28316
|
-
reject(new Error(`CSS build failed with code ${code} and fallback copy also failed: ${copyErr.message}`));
|
|
28317
|
-
}
|
|
28318
|
-
});
|
|
28319
|
-
postcss.on("error", (err) => {
|
|
28320
|
-
if (verbose) {
|
|
28321
|
-
console.warn(`Failed to start PostCSS process (${err.message}). Falling back to copy.`);
|
|
28322
|
-
}
|
|
28323
|
-
fs.promises.copyFile(inputPath, outputPath).then(() => resolve()).catch((copyErr) => reject(new Error(`Failed to start PostCSS and fallback copy failed: ${copyErr.message}`)));
|
|
28324
|
-
});
|
|
28282
|
+
reject(new Error(`PostCSS failed with exit code ${code}: ${errorOutput.trim()}`));
|
|
28325
28283
|
});
|
|
28326
|
-
|
|
28327
|
-
|
|
28284
|
+
postcss.on("error", (err) => {
|
|
28285
|
+
reject(new Error(`Failed to start PostCSS: ${err.message}`));
|
|
28286
|
+
});
|
|
28287
|
+
});
|
|
28328
28288
|
}
|
|
28329
28289
|
async function watchCSS(options2) {
|
|
28330
28290
|
const { css, projectRoot, verbose = false } = options2;
|
|
@@ -28422,6 +28382,7 @@ import path5 from "path";
|
|
|
28422
28382
|
// src/utils/file-utils.ts
|
|
28423
28383
|
var {Glob } = globalThis.Bun;
|
|
28424
28384
|
import path4 from "path";
|
|
28385
|
+
import { mkdir } from "fs/promises";
|
|
28425
28386
|
async function findFilesByPattern(pattern, directory, absolute = true) {
|
|
28426
28387
|
const glob = new Glob(pattern);
|
|
28427
28388
|
const files = [];
|
|
@@ -28434,8 +28395,20 @@ async function findFilesByPattern(pattern, directory, absolute = true) {
|
|
|
28434
28395
|
return files;
|
|
28435
28396
|
}
|
|
28436
28397
|
async function fileExists(filePath) {
|
|
28437
|
-
|
|
28438
|
-
|
|
28398
|
+
try {
|
|
28399
|
+
const file = Bun.file(filePath);
|
|
28400
|
+
return await file.exists();
|
|
28401
|
+
} catch {
|
|
28402
|
+
return false;
|
|
28403
|
+
}
|
|
28404
|
+
}
|
|
28405
|
+
async function isDirectory(dirPath) {
|
|
28406
|
+
try {
|
|
28407
|
+
const stat = await Bun.file(dirPath).stat();
|
|
28408
|
+
return stat?.isDirectory() ?? false;
|
|
28409
|
+
} catch {
|
|
28410
|
+
return false;
|
|
28411
|
+
}
|
|
28439
28412
|
}
|
|
28440
28413
|
async function readFileAsText(filePath) {
|
|
28441
28414
|
try {
|
|
@@ -28452,18 +28425,33 @@ async function readFileAsText(filePath) {
|
|
|
28452
28425
|
function getBaseFilename(filePath, extension = ".md") {
|
|
28453
28426
|
return path4.basename(filePath, extension);
|
|
28454
28427
|
}
|
|
28455
|
-
async function
|
|
28428
|
+
async function createDir(dirPath) {
|
|
28456
28429
|
try {
|
|
28457
|
-
await
|
|
28458
|
-
} catch (error) {
|
|
28430
|
+
await mkdir(dirPath, { recursive: true });
|
|
28431
|
+
} catch (error) {
|
|
28432
|
+
if (await isDirectory(dirPath)) {
|
|
28433
|
+
return;
|
|
28434
|
+
}
|
|
28435
|
+
if (await fileExists(dirPath)) {
|
|
28436
|
+
throw new Error(`Path exists but is not a directory: ${dirPath}`);
|
|
28437
|
+
}
|
|
28438
|
+
console.error(`Error creating directory ${dirPath}:`, error);
|
|
28439
|
+
throw error;
|
|
28440
|
+
}
|
|
28441
|
+
}
|
|
28442
|
+
async function ensureDir(dirPath) {
|
|
28443
|
+
return createDir(dirPath);
|
|
28459
28444
|
}
|
|
28460
28445
|
async function copyFile(sourcePath, targetPath) {
|
|
28461
28446
|
try {
|
|
28462
28447
|
const sourceFile = Bun.file(sourcePath);
|
|
28463
|
-
|
|
28464
|
-
|
|
28448
|
+
if (!await sourceFile.exists()) {
|
|
28449
|
+
throw new Error(`Source file does not exist: ${sourcePath}`);
|
|
28450
|
+
}
|
|
28451
|
+
await Bun.write(targetPath, sourceFile);
|
|
28465
28452
|
} catch (error) {
|
|
28466
28453
|
console.error(`Error copying file from ${sourcePath} to ${targetPath}:`, error);
|
|
28454
|
+
throw error;
|
|
28467
28455
|
}
|
|
28468
28456
|
}
|
|
28469
28457
|
|
|
@@ -33614,8 +33602,11 @@ class S3Uploader {
|
|
|
33614
33602
|
}
|
|
33615
33603
|
}
|
|
33616
33604
|
}
|
|
33617
|
-
async uploadImages(imagesDir) {
|
|
33605
|
+
async uploadImages(imagesDir, minYear) {
|
|
33618
33606
|
console.log(`[S3] Uploading all images from ${imagesDir} to bucket ${this.s3Config.bucket}...`);
|
|
33607
|
+
if (minYear) {
|
|
33608
|
+
console.log(`[S3] Filtering images from year ${minYear} onwards`);
|
|
33609
|
+
}
|
|
33619
33610
|
const imageUrls = {};
|
|
33620
33611
|
try {
|
|
33621
33612
|
console.log(`[S3] Checking if directory exists: ${imagesDir}`);
|
|
@@ -33658,8 +33649,19 @@ class S3Uploader {
|
|
|
33658
33649
|
cwd: imagesDir,
|
|
33659
33650
|
absolute: false
|
|
33660
33651
|
})) {
|
|
33661
|
-
|
|
33662
|
-
|
|
33652
|
+
if (minYear) {
|
|
33653
|
+
const yearMatch = file.match(/^(\d{4})\//);
|
|
33654
|
+
if (yearMatch) {
|
|
33655
|
+
const fileYear = parseInt(yearMatch[1], 10);
|
|
33656
|
+
if (fileYear >= minYear) {
|
|
33657
|
+
console.log(`[S3] Found image file: ${file}`);
|
|
33658
|
+
files.push(file);
|
|
33659
|
+
}
|
|
33660
|
+
}
|
|
33661
|
+
} else {
|
|
33662
|
+
console.log(`[S3] Found image file: ${file}`);
|
|
33663
|
+
files.push(file);
|
|
33664
|
+
}
|
|
33663
33665
|
}
|
|
33664
33666
|
const imageFiles = files;
|
|
33665
33667
|
if (imageFiles.length === 0) {
|
|
@@ -33734,8 +33736,11 @@ async function uploadImages(options2 = {}) {
|
|
|
33734
33736
|
};
|
|
33735
33737
|
}
|
|
33736
33738
|
console.log(`Uploading images from ${imagesDir} to bucket ${s3Config.bucket}`);
|
|
33739
|
+
if (options2.minYear) {
|
|
33740
|
+
console.log(`Filtering images from year ${options2.minYear} onwards`);
|
|
33741
|
+
}
|
|
33737
33742
|
const uploader = createUploader(s3Config);
|
|
33738
|
-
const imageUrlMap = await uploader.uploadImages(imagesDir);
|
|
33743
|
+
const imageUrlMap = await uploader.uploadImages(imagesDir, options2.minYear);
|
|
33739
33744
|
if (options2.outputJson) {
|
|
33740
33745
|
const outputFile = path8.resolve(options2.outputJson);
|
|
33741
33746
|
await Bun.write(outputFile, JSON.stringify(imageUrlMap, null, 2));
|
|
@@ -33753,7 +33758,7 @@ Image upload completed successfully!`);
|
|
|
33753
33758
|
return imageUrlMap;
|
|
33754
33759
|
} catch (error) {
|
|
33755
33760
|
console.error("Error uploading images:", error);
|
|
33756
|
-
|
|
33761
|
+
throw error;
|
|
33757
33762
|
}
|
|
33758
33763
|
}
|
|
33759
33764
|
|
|
@@ -33768,7 +33773,8 @@ async function handleImagesPushCommand(options2, deps = defaultDeps3) {
|
|
|
33768
33773
|
await deps.uploadImages({
|
|
33769
33774
|
domain: options2.domain,
|
|
33770
33775
|
images: options2.images,
|
|
33771
|
-
outputJson: options2.outputJson
|
|
33776
|
+
outputJson: options2.outputJson,
|
|
33777
|
+
minYear: options2.minYear ? parseInt(options2.minYear, 10) : undefined
|
|
33772
33778
|
});
|
|
33773
33779
|
} catch (error) {
|
|
33774
33780
|
deps.logger.error("Error uploading images:", error);
|
|
@@ -33776,7 +33782,7 @@ async function handleImagesPushCommand(options2, deps = defaultDeps3) {
|
|
|
33776
33782
|
}
|
|
33777
33783
|
}
|
|
33778
33784
|
function registerImagesPushCommand(program2) {
|
|
33779
|
-
return program2.command("images:push").description("Upload images to S3-compatible storage").option("-d, --domain <domain>", "Domain name for bucket identification (defaults to domain in bunki.config.ts)").option("-i, --images <dir>", "Images directory path", DEFAULT_IMAGES_DIR).option("--output-json <file>", "Output URL mapping to JSON file").action(async (options2) => {
|
|
33785
|
+
return program2.command("images:push").description("Upload images to S3-compatible storage").option("-d, --domain <domain>", "Domain name for bucket identification (defaults to domain in bunki.config.ts)").option("-i, --images <dir>", "Images directory path", DEFAULT_IMAGES_DIR).option("--output-json <file>", "Output URL mapping to JSON file").option("--min-year <year>", "Only upload images from the specified year onwards (e.g., 2023 uploads 2023, 2024, etc.)").action(async (options2) => {
|
|
33780
33786
|
await handleImagesPushCommand(options2);
|
|
33781
33787
|
});
|
|
33782
33788
|
}
|
|
@@ -34252,56 +34258,56 @@ function getDefaultCss() {
|
|
|
34252
34258
|
}
|
|
34253
34259
|
function getSamplePost() {
|
|
34254
34260
|
return `---
|
|
34255
|
-
|
|
34256
|
-
|
|
34257
|
-
|
|
34258
|
-
|
|
34261
|
+
title: Welcome to Bunki
|
|
34262
|
+
date: 2025-01-15T12:00:00Z
|
|
34263
|
+
tags: [getting-started, bunki]
|
|
34264
|
+
---
|
|
34259
34265
|
|
|
34260
|
-
|
|
34266
|
+
# Welcome to Your New Bunki Site
|
|
34261
34267
|
|
|
34262
|
-
|
|
34268
|
+
This is a sample blog post to help you get started with Bunki. You can edit this file or create new markdown files in the \`content\` directory.
|
|
34263
34269
|
|
|
34264
|
-
|
|
34270
|
+
## Features
|
|
34265
34271
|
|
|
34266
|
-
|
|
34267
|
-
|
|
34268
|
-
|
|
34269
|
-
|
|
34270
|
-
|
|
34271
|
-
|
|
34272
|
+
- Markdown support with frontmatter
|
|
34273
|
+
- Syntax highlighting for code blocks
|
|
34274
|
+
- Tag-based organization
|
|
34275
|
+
- Pagination for post listings
|
|
34276
|
+
- RSS feed generation
|
|
34277
|
+
- Sitemap generation
|
|
34272
34278
|
|
|
34273
|
-
|
|
34279
|
+
## Adding Content
|
|
34274
34280
|
|
|
34275
|
-
|
|
34281
|
+
Create new markdown files in the \`content\` directory with frontmatter like this:
|
|
34276
34282
|
|
|
34277
|
-
|
|
34278
|
-
|
|
34279
|
-
|
|
34280
|
-
|
|
34281
|
-
|
|
34282
|
-
|
|
34283
|
+
\`\`\`markdown
|
|
34284
|
+
---
|
|
34285
|
+
title: Your Post Title
|
|
34286
|
+
date: 2025-01-01T12:00:00Z
|
|
34287
|
+
tags: [tag1, tag2]
|
|
34288
|
+
---
|
|
34283
34289
|
|
|
34284
|
-
|
|
34285
|
-
|
|
34290
|
+
Your post content goes here...
|
|
34291
|
+
\`\`\`
|
|
34286
34292
|
|
|
34287
|
-
|
|
34293
|
+
## Code Highlighting
|
|
34288
34294
|
|
|
34289
|
-
|
|
34295
|
+
Bunki supports syntax highlighting for code blocks:
|
|
34290
34296
|
|
|
34291
|
-
|
|
34292
|
-
|
|
34293
|
-
|
|
34294
|
-
|
|
34295
|
-
|
|
34297
|
+
\`\`\`javascript
|
|
34298
|
+
function hello() {
|
|
34299
|
+
console.log('Hello, world!');
|
|
34300
|
+
}
|
|
34301
|
+
\`\`\`
|
|
34296
34302
|
|
|
34297
|
-
|
|
34303
|
+
## Next Steps
|
|
34298
34304
|
|
|
34299
|
-
|
|
34300
|
-
|
|
34301
|
-
|
|
34302
|
-
|
|
34303
|
-
|
|
34304
|
-
|
|
34305
|
+
1. Edit the site configuration in \`bunki.config.ts\`
|
|
34306
|
+
2. Create your own templates in the \`templates\` directory
|
|
34307
|
+
3. Add more blog posts in the \`content\` directory
|
|
34308
|
+
4. Run \`bunki generate\` to build your site
|
|
34309
|
+
5. Run \`bunki serve\` to preview your site locally
|
|
34310
|
+
`;
|
|
34305
34311
|
}
|
|
34306
34312
|
|
|
34307
34313
|
// src/cli/commands/new-post.ts
|
|
@@ -34501,6 +34507,8 @@ registerServeCommand(program2);
|
|
|
34501
34507
|
registerCssCommand(program2);
|
|
34502
34508
|
registerImagesPushCommand(program2);
|
|
34503
34509
|
program2.name("bunki").description("An opinionated static site generator built with Bun").version("0.5.3");
|
|
34504
|
-
|
|
34510
|
+
var currentFile = import.meta.url.replace("file://", "");
|
|
34511
|
+
var mainFile = Bun.main;
|
|
34512
|
+
if (currentFile === mainFile || currentFile.endsWith(mainFile)) {
|
|
34505
34513
|
program2.parse(Bun.argv);
|
|
34506
34514
|
}
|
package/dist/index.js
CHANGED
|
@@ -23766,9 +23766,9 @@ var require_fsevents_handler = __commonJS((exports, module) => {
|
|
|
23766
23766
|
if (this.fsw.closed || this.checkIgnored(path4))
|
|
23767
23767
|
return;
|
|
23768
23768
|
if (event === EV_UNLINK) {
|
|
23769
|
-
const
|
|
23770
|
-
if (
|
|
23771
|
-
this.fsw._remove(parent, item,
|
|
23769
|
+
const isDirectory2 = info.type === FSEVENT_TYPE_DIRECTORY;
|
|
23770
|
+
if (isDirectory2 || watchedDir.has(item)) {
|
|
23771
|
+
this.fsw._remove(parent, item, isDirectory2);
|
|
23772
23772
|
}
|
|
23773
23773
|
} else {
|
|
23774
23774
|
if (event === EV_ADD) {
|
|
@@ -24550,13 +24550,13 @@ var require_chokidar = __commonJS((exports) => {
|
|
|
24550
24550
|
const it = Number.parseInt(st.toString(8)[0], 10);
|
|
24551
24551
|
return Boolean(4 & it);
|
|
24552
24552
|
}
|
|
24553
|
-
_remove(directory, item,
|
|
24553
|
+
_remove(directory, item, isDirectory2) {
|
|
24554
24554
|
const path4 = sysPath.join(directory, item);
|
|
24555
24555
|
const fullPath = sysPath.resolve(path4);
|
|
24556
|
-
|
|
24556
|
+
isDirectory2 = isDirectory2 != null ? isDirectory2 : this._watched.has(path4) || this._watched.has(fullPath);
|
|
24557
24557
|
if (!this._throttle("remove", path4, 100))
|
|
24558
24558
|
return;
|
|
24559
|
-
if (!
|
|
24559
|
+
if (!isDirectory2 && !this.options.useFsEvents && this._watched.size === 1) {
|
|
24560
24560
|
this.add(directory, item, true);
|
|
24561
24561
|
}
|
|
24562
24562
|
const wp = this._getWatchedDir(path4);
|
|
@@ -24578,7 +24578,7 @@ var require_chokidar = __commonJS((exports) => {
|
|
|
24578
24578
|
}
|
|
24579
24579
|
this._watched.delete(path4);
|
|
24580
24580
|
this._watched.delete(fullPath);
|
|
24581
|
-
const eventName =
|
|
24581
|
+
const eventName = isDirectory2 ? EV_UNLINK_DIR : EV_UNLINK;
|
|
24582
24582
|
if (wasTracked && !this._isIgnored(path4))
|
|
24583
24583
|
this._emit(eventName, path4);
|
|
24584
24584
|
if (!this.options.useFsEvents) {
|
|
@@ -26000,6 +26000,7 @@ var require_slugify = __commonJS((exports, module) => {
|
|
|
26000
26000
|
// src/utils/file-utils.ts
|
|
26001
26001
|
var {Glob } = globalThis.Bun;
|
|
26002
26002
|
import path from "path";
|
|
26003
|
+
import { mkdir } from "fs/promises";
|
|
26003
26004
|
async function findFilesByPattern(pattern, directory, absolute = true) {
|
|
26004
26005
|
const glob = new Glob(pattern);
|
|
26005
26006
|
const files = [];
|
|
@@ -26012,8 +26013,20 @@ async function findFilesByPattern(pattern, directory, absolute = true) {
|
|
|
26012
26013
|
return files;
|
|
26013
26014
|
}
|
|
26014
26015
|
async function fileExists(filePath) {
|
|
26015
|
-
|
|
26016
|
-
|
|
26016
|
+
try {
|
|
26017
|
+
const file = Bun.file(filePath);
|
|
26018
|
+
return await file.exists();
|
|
26019
|
+
} catch {
|
|
26020
|
+
return false;
|
|
26021
|
+
}
|
|
26022
|
+
}
|
|
26023
|
+
async function isDirectory(dirPath) {
|
|
26024
|
+
try {
|
|
26025
|
+
const stat = await Bun.file(dirPath).stat();
|
|
26026
|
+
return stat?.isDirectory() ?? false;
|
|
26027
|
+
} catch {
|
|
26028
|
+
return false;
|
|
26029
|
+
}
|
|
26017
26030
|
}
|
|
26018
26031
|
async function readFileAsText(filePath) {
|
|
26019
26032
|
try {
|
|
@@ -26030,18 +26043,33 @@ async function readFileAsText(filePath) {
|
|
|
26030
26043
|
function getBaseFilename(filePath, extension = ".md") {
|
|
26031
26044
|
return path.basename(filePath, extension);
|
|
26032
26045
|
}
|
|
26033
|
-
async function
|
|
26046
|
+
async function createDir(dirPath) {
|
|
26034
26047
|
try {
|
|
26035
|
-
await
|
|
26036
|
-
} catch (error) {
|
|
26048
|
+
await mkdir(dirPath, { recursive: true });
|
|
26049
|
+
} catch (error) {
|
|
26050
|
+
if (await isDirectory(dirPath)) {
|
|
26051
|
+
return;
|
|
26052
|
+
}
|
|
26053
|
+
if (await fileExists(dirPath)) {
|
|
26054
|
+
throw new Error(`Path exists but is not a directory: ${dirPath}`);
|
|
26055
|
+
}
|
|
26056
|
+
console.error(`Error creating directory ${dirPath}:`, error);
|
|
26057
|
+
throw error;
|
|
26058
|
+
}
|
|
26059
|
+
}
|
|
26060
|
+
async function ensureDir(dirPath) {
|
|
26061
|
+
return createDir(dirPath);
|
|
26037
26062
|
}
|
|
26038
26063
|
async function copyFile(sourcePath, targetPath) {
|
|
26039
26064
|
try {
|
|
26040
26065
|
const sourceFile = Bun.file(sourcePath);
|
|
26041
|
-
|
|
26042
|
-
|
|
26066
|
+
if (!await sourceFile.exists()) {
|
|
26067
|
+
throw new Error(`Source file does not exist: ${sourcePath}`);
|
|
26068
|
+
}
|
|
26069
|
+
await Bun.write(targetPath, sourceFile);
|
|
26043
26070
|
} catch (error) {
|
|
26044
26071
|
console.error(`Error copying file from ${sourcePath} to ${targetPath}:`, error);
|
|
26072
|
+
throw error;
|
|
26045
26073
|
}
|
|
26046
26074
|
}
|
|
26047
26075
|
|
|
@@ -30576,7 +30604,7 @@ function getDefaultConfig() {
|
|
|
30576
30604
|
return base;
|
|
30577
30605
|
}
|
|
30578
30606
|
async function createDefaultConfig(configPath = DEFAULT_CONFIG_FILE) {
|
|
30579
|
-
if (await configExists()) {
|
|
30607
|
+
if (await configExists(configPath)) {
|
|
30580
30608
|
console.log(`Config file already exists`);
|
|
30581
30609
|
return false;
|
|
30582
30610
|
}
|
|
@@ -30775,15 +30803,6 @@ async function processCSS(options2) {
|
|
|
30775
30803
|
} catch (error) {
|
|
30776
30804
|
throw new Error(`CSS input file not found: ${inputPath}`);
|
|
30777
30805
|
}
|
|
30778
|
-
let postcssConfigExists = false;
|
|
30779
|
-
try {
|
|
30780
|
-
await fs2.promises.access(postcssConfigPath);
|
|
30781
|
-
postcssConfigExists = true;
|
|
30782
|
-
} catch (error) {
|
|
30783
|
-
if (verbose) {
|
|
30784
|
-
console.log(`PostCSS config not found at ${postcssConfigPath}, will fallback to simple copy`);
|
|
30785
|
-
}
|
|
30786
|
-
}
|
|
30787
30806
|
const outputDirPath = path4.dirname(outputPath);
|
|
30788
30807
|
await fs2.promises.mkdir(outputDirPath, { recursive: true });
|
|
30789
30808
|
if (verbose) {
|
|
@@ -30792,71 +30811,40 @@ async function processCSS(options2) {
|
|
|
30792
30811
|
console.log(`Output: ${outputPath}`);
|
|
30793
30812
|
console.log(`Config: ${postcssConfigPath}`);
|
|
30794
30813
|
}
|
|
30795
|
-
|
|
30796
|
-
|
|
30797
|
-
|
|
30798
|
-
|
|
30799
|
-
|
|
30800
|
-
|
|
30801
|
-
|
|
30802
|
-
|
|
30803
|
-
|
|
30804
|
-
|
|
30805
|
-
|
|
30806
|
-
|
|
30807
|
-
|
|
30808
|
-
|
|
30809
|
-
|
|
30814
|
+
await runPostCSS(inputPath, outputPath, postcssConfigPath, projectRoot, verbose);
|
|
30815
|
+
}
|
|
30816
|
+
function runPostCSS(inputPath, outputPath, configPath, projectRoot, verbose) {
|
|
30817
|
+
return new Promise((resolve, reject) => {
|
|
30818
|
+
const args = [
|
|
30819
|
+
"postcss",
|
|
30820
|
+
inputPath,
|
|
30821
|
+
"-o",
|
|
30822
|
+
outputPath,
|
|
30823
|
+
"--config",
|
|
30824
|
+
configPath
|
|
30825
|
+
];
|
|
30826
|
+
const postcss = spawn("bunx", args, {
|
|
30827
|
+
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
30828
|
+
cwd: projectRoot
|
|
30829
|
+
});
|
|
30830
|
+
let errorOutput = "";
|
|
30831
|
+
if (!verbose) {
|
|
30832
|
+
postcss.stderr?.on("data", (data) => {
|
|
30833
|
+
errorOutput += data.toString();
|
|
30810
30834
|
});
|
|
30811
|
-
|
|
30812
|
-
|
|
30813
|
-
|
|
30814
|
-
|
|
30815
|
-
|
|
30835
|
+
}
|
|
30836
|
+
postcss.on("close", (code) => {
|
|
30837
|
+
if (code === 0) {
|
|
30838
|
+
if (verbose)
|
|
30839
|
+
console.log("\u2705 CSS build completed successfully!");
|
|
30840
|
+
return resolve();
|
|
30816
30841
|
}
|
|
30817
|
-
|
|
30818
|
-
if (code === 0) {
|
|
30819
|
-
if (verbose)
|
|
30820
|
-
console.log("\u2705 CSS build completed successfully!");
|
|
30821
|
-
return resolve();
|
|
30822
|
-
}
|
|
30823
|
-
if (/module is not defined in ES module scope/i.test(errorOutput) && configPathToUse.endsWith(".js")) {
|
|
30824
|
-
const cjsPath = configPathToUse.replace(/\.js$/, ".cjs");
|
|
30825
|
-
try {
|
|
30826
|
-
if (!fs2.existsSync(cjsPath)) {
|
|
30827
|
-
const original = await fs2.promises.readFile(configPathToUse, "utf-8");
|
|
30828
|
-
await fs2.promises.writeFile(cjsPath, original, "utf-8");
|
|
30829
|
-
if (verbose) {
|
|
30830
|
-
console.log(`Retrying PostCSS with converted CommonJS config at ${cjsPath}`);
|
|
30831
|
-
}
|
|
30832
|
-
}
|
|
30833
|
-
return resolve(runPostCSS(cjsPath));
|
|
30834
|
-
} catch (e) {
|
|
30835
|
-
if (verbose)
|
|
30836
|
-
console.warn("CJS fallback failed, copying CSS.");
|
|
30837
|
-
await fs2.promises.copyFile(inputPath, outputPath);
|
|
30838
|
-
return resolve();
|
|
30839
|
-
}
|
|
30840
|
-
}
|
|
30841
|
-
if (verbose) {
|
|
30842
|
-
console.warn(`PostCSS failed (code ${code}). Falling back to simple copy. Error: ${errorOutput.trim()}`);
|
|
30843
|
-
}
|
|
30844
|
-
try {
|
|
30845
|
-
await fs2.promises.copyFile(inputPath, outputPath);
|
|
30846
|
-
resolve();
|
|
30847
|
-
} catch (copyErr) {
|
|
30848
|
-
reject(new Error(`CSS build failed with code ${code} and fallback copy also failed: ${copyErr.message}`));
|
|
30849
|
-
}
|
|
30850
|
-
});
|
|
30851
|
-
postcss.on("error", (err) => {
|
|
30852
|
-
if (verbose) {
|
|
30853
|
-
console.warn(`Failed to start PostCSS process (${err.message}). Falling back to copy.`);
|
|
30854
|
-
}
|
|
30855
|
-
fs2.promises.copyFile(inputPath, outputPath).then(() => resolve()).catch((copyErr) => reject(new Error(`Failed to start PostCSS and fallback copy failed: ${copyErr.message}`)));
|
|
30856
|
-
});
|
|
30842
|
+
reject(new Error(`PostCSS failed with exit code ${code}: ${errorOutput.trim()}`));
|
|
30857
30843
|
});
|
|
30858
|
-
|
|
30859
|
-
|
|
30844
|
+
postcss.on("error", (err) => {
|
|
30845
|
+
reject(new Error(`Failed to start PostCSS: ${err.message}`));
|
|
30846
|
+
});
|
|
30847
|
+
});
|
|
30860
30848
|
}
|
|
30861
30849
|
function getDefaultCSSConfig() {
|
|
30862
30850
|
return {
|
|
@@ -31521,8 +31509,11 @@ class S3Uploader {
|
|
|
31521
31509
|
}
|
|
31522
31510
|
}
|
|
31523
31511
|
}
|
|
31524
|
-
async uploadImages(imagesDir) {
|
|
31512
|
+
async uploadImages(imagesDir, minYear) {
|
|
31525
31513
|
console.log(`[S3] Uploading all images from ${imagesDir} to bucket ${this.s3Config.bucket}...`);
|
|
31514
|
+
if (minYear) {
|
|
31515
|
+
console.log(`[S3] Filtering images from year ${minYear} onwards`);
|
|
31516
|
+
}
|
|
31526
31517
|
const imageUrls = {};
|
|
31527
31518
|
try {
|
|
31528
31519
|
console.log(`[S3] Checking if directory exists: ${imagesDir}`);
|
|
@@ -31565,8 +31556,19 @@ class S3Uploader {
|
|
|
31565
31556
|
cwd: imagesDir,
|
|
31566
31557
|
absolute: false
|
|
31567
31558
|
})) {
|
|
31568
|
-
|
|
31569
|
-
|
|
31559
|
+
if (minYear) {
|
|
31560
|
+
const yearMatch = file.match(/^(\d{4})\//);
|
|
31561
|
+
if (yearMatch) {
|
|
31562
|
+
const fileYear = parseInt(yearMatch[1], 10);
|
|
31563
|
+
if (fileYear >= minYear) {
|
|
31564
|
+
console.log(`[S3] Found image file: ${file}`);
|
|
31565
|
+
files.push(file);
|
|
31566
|
+
}
|
|
31567
|
+
}
|
|
31568
|
+
} else {
|
|
31569
|
+
console.log(`[S3] Found image file: ${file}`);
|
|
31570
|
+
files.push(file);
|
|
31571
|
+
}
|
|
31570
31572
|
}
|
|
31571
31573
|
const imageFiles = files;
|
|
31572
31574
|
if (imageFiles.length === 0) {
|
|
@@ -31641,8 +31643,11 @@ async function uploadImages(options2 = {}) {
|
|
|
31641
31643
|
};
|
|
31642
31644
|
}
|
|
31643
31645
|
console.log(`Uploading images from ${imagesDir} to bucket ${s3Config.bucket}`);
|
|
31646
|
+
if (options2.minYear) {
|
|
31647
|
+
console.log(`Filtering images from year ${options2.minYear} onwards`);
|
|
31648
|
+
}
|
|
31644
31649
|
const uploader = createUploader(s3Config);
|
|
31645
|
-
const imageUrlMap = await uploader.uploadImages(imagesDir);
|
|
31650
|
+
const imageUrlMap = await uploader.uploadImages(imagesDir, options2.minYear);
|
|
31646
31651
|
if (options2.outputJson) {
|
|
31647
31652
|
const outputFile = path7.resolve(options2.outputJson);
|
|
31648
31653
|
await Bun.write(outputFile, JSON.stringify(imageUrlMap, null, 2));
|
|
@@ -31660,7 +31665,7 @@ Image upload completed successfully!`);
|
|
|
31660
31665
|
return imageUrlMap;
|
|
31661
31666
|
} catch (error) {
|
|
31662
31667
|
console.error("Error uploading images:", error);
|
|
31663
|
-
|
|
31668
|
+
throw error;
|
|
31664
31669
|
}
|
|
31665
31670
|
}
|
|
31666
31671
|
export {
|