@mdfriday/foundry
Version:
The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.
216 lines • 7.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Walkway = void 0;
exports.newWalkway = newWalkway;
const path = __importStar(require("path"));
const type_1 = require("../type");
const fileinfo_1 = require("./fileinfo");
const filemeta_1 = require("./filemeta");
const log_1 = require("../../../../pkg/log");
// Create domain-specific logger for fs operations
const log = (0, log_1.getDomainLogger)('fs', { component: 'walkway' });
/**
* Walkway represents a filesystem walker
* TypeScript version of Go's Walkway struct
*/
class Walkway {
constructor(fs, cb) {
this.walked = false;
if (!fs) {
throw new Error('fs must be set');
}
if (!cb.walkFn) {
throw new Error('walkFn must be set');
}
this.fs = fs;
this.cb = cb;
this.root = '';
this.cfg = {};
}
/**
* WalkWith performs walk with specified root and configuration
*/
async walkWith(root, cfg) {
this.cfg = cfg;
this.root = root;
return await this.walk();
}
/**
* Walk performs the filesystem walk
*/
async walk() {
if (this.walked) {
throw new Error('this walkway is already walked');
}
this.walked = true;
return await this.walkRecursive(this.root, this.cfg.info, this.cfg.dirEntries);
}
/**
* Check if error should be handled gracefully
*/
checkErr(filename, err) {
if (this.isNotExistError(err) && !this.cfg.failOnNotExist) {
// The file may be removed in process
// This may be an ERROR situation, but it is not possible
// to determine as a general case
log.warn(`File "${filename}" not found, skipping.`);
return true;
}
return false;
}
/**
* Check if error is a "not exist" error
*/
isNotExistError(err) {
return err.message.includes('ENOENT') ||
err.message.includes('no such file') ||
err.code === 'ENOENT';
}
/**
* Walk recursively descends path, calling walkFn
*/
async walkRecursive(filePath, info, dirEntries) {
// Get file info if not provided
if (!info) {
try {
const fi = await this.fs.stat(filePath);
// Create FileMetaInfo from FileInfo
const meta = (0, filemeta_1.newFileMeta)(filePath);
meta.setOpenFunc(async () => await this.fs.open(filePath));
info = (0, fileinfo_1.newFileInfoWithMeta)(fi, meta);
}
catch (err) {
if (filePath === this.root && this.isNotExistError(err)) {
if (this.cfg.failOnNotExist) {
throw new type_1.FsError(`walk: root not found: ${err.message}`, 'WALK_ROOT_NOT_FOUND');
}
return;
}
if (this.checkErr(filePath, err)) {
return;
}
throw new type_1.FsError(`walk: stat: ${err.message}`, 'WALK_STAT_FAILED');
}
}
// Call the walk function
try {
const result = await this.cb.walkFn(filePath, info);
if (result instanceof Error) {
throw result;
}
}
catch (err) {
if (info.isDir() && err === type_1.ErrSkipDir) {
return;
}
throw err;
}
// If not a directory, we're done
if (!info.isDir()) {
return;
}
// Read directory entries if not provided
if (!dirEntries) {
try {
const file = await this.fs.open(filePath);
const entries = await file.readdir(-1);
await file.close();
// Convert to FileMetaInfo array
dirEntries = entries.map(entry => {
return entry;
});
// Sort if requested
if (this.cfg.sortDirEntries) {
dirEntries.sort((a, b) => a.name().localeCompare(b.name()));
}
}
catch (err) {
if (this.checkErr(filePath, err)) {
return;
}
throw new type_1.FsError(`walk: readdir: ${err.message}`, 'WALK_READDIR_FAILED');
}
}
// Apply ignore filter if provided
if (this.cfg.ignoreFile) {
dirEntries = dirEntries.filter(entry => !this.cfg.ignoreFile(entry.fileName()));
}
// Call pre-hook if provided
if (this.cb.hookPre) {
try {
dirEntries = await this.cb.hookPre(info, filePath, dirEntries);
}
catch (err) {
if (err === type_1.ErrSkipDir) {
return;
}
throw err;
}
}
// Recursively walk directory entries
for (const entry of dirEntries) {
const nextPath = path.join(filePath, entry.name());
try {
await this.walkRecursive(nextPath, entry);
}
catch (err) {
if (!entry.isDir() || err !== type_1.ErrSkipDir) {
throw err;
}
}
}
// Call post-hook if provided
if (this.cb.hookPost) {
try {
await this.cb.hookPost(info, filePath, dirEntries);
}
catch (err) {
if (err === type_1.ErrSkipDir) {
return;
}
throw err;
}
}
}
}
exports.Walkway = Walkway;
/**
* Creates a new Walkway instance
*/
function newWalkway(fs, cb) {
return new Walkway(fs, cb);
}
//# sourceMappingURL=walkway.js.map