@mdfriday/foundry
Version:
The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.
193 lines • 5.81 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MutableTrees = exports.WalkableTrees = exports.WalkContext = exports.Event = exports.LockType = void 0;
exports.validateKey = validateKey;
exports.cleanKey = cleanKey;
exports.mustValidateKey = mustValidateKey;
const radix_1 = require("../radix");
var LockType;
(function (LockType) {
LockType[LockType["LockTypeNone"] = 0] = "LockTypeNone";
LockType[LockType["LockTypeRead"] = 1] = "LockTypeRead";
LockType[LockType["LockTypeWrite"] = 2] = "LockTypeWrite";
})(LockType || (exports.LockType = LockType = {}));
// Event is used to communicate events in the tree.
class Event {
constructor(name, path, source) {
this.stopPropagationFlag = false;
this.name = name;
this.path = path;
this.source = source;
}
// StopPropagation stops the propagation of the event.
stopPropagation() {
this.stopPropagationFlag = true;
}
get shouldStopPropagation() {
return this.stopPropagationFlag;
}
}
exports.Event = Event;
// WalkContext is passed to the Walk callback.
class WalkContext {
constructor() {
this.dataInitialized = false;
this.events = [];
this.hooksPost = [];
}
// AddEventListener adds an event listener to the tree.
// Note that the handler func may not add listeners.
addEventListener(event, path, handler) {
if (!this.eventHandlers) {
this.eventHandlers = new Map();
}
if (!this.eventHandlers.has(event)) {
this.eventHandlers.set(event, []);
}
// We want to match all above the path, so we need to exclude any similar named siblings.
let targetPath = path;
if (!targetPath.endsWith('/')) {
targetPath += '/';
}
this.eventHandlers.get(event).push((e) => {
// Propagate events up the tree only.
if (e.path.startsWith(targetPath)) {
handler(e);
}
});
}
// AddPostHook adds a post hook to the tree.
// This will be run after the tree has been walked.
addPostHook(handler) {
this.hooksPost.push(handler);
}
data() {
if (!this.dataInitialized) {
this.dataInstance = {
tree: new radix_1.Tree()
};
this.dataInitialized = true;
}
return this.dataInstance;
}
// SendEvent sends an event up the tree.
sendEvent(event) {
this.events.push(event);
}
async handleEvents() {
while (this.events.length > 0) {
const event = this.events.shift();
if (this.eventHandlers && this.eventHandlers.has(event.name)) {
const handlers = this.eventHandlers.get(event.name);
// Loop the event handlers in reverse order so
// that events created by the handlers themselves will
// be picked up further up the tree.
for (let i = handlers.length - 1; i >= 0; i--) {
handlers[i](event);
if (event.shouldStopPropagation) {
break;
}
}
}
}
}
async handleEventsAndHooks() {
await this.handleEvents();
for (const hook of this.hooksPost) {
await hook();
}
}
}
exports.WalkContext = WalkContext;
class WalkableTrees {
constructor(trees) {
this.trees = trees;
}
walkPrefixRaw(prefix, walker) {
for (const tree of this.trees) {
tree.walkPrefixRaw(prefix, walker);
}
}
}
exports.WalkableTrees = WalkableTrees;
class MutableTrees {
constructor(trees) {
this.trees = trees;
}
delete(key) {
for (const tree of this.trees) {
tree.delete(key);
}
}
deleteAll(key) {
for (const tree of this.trees) {
tree.deleteAll(key);
}
}
async deletePrefix(prefix) {
let count = 0;
for (const tree of this.trees) {
count += await tree.deletePrefix(prefix);
}
return Promise.resolve(count);
}
async deletePrefixAll(prefix) {
let count = 0;
for (const tree of this.trees) {
count += await tree.deletePrefixAll(prefix);
}
return count;
}
lock(writable) {
const commits = this.trees.map(tree => tree.lock(writable));
return () => {
for (const commit of commits) {
commit();
}
};
}
canLock() {
for (const tree of this.trees) {
if (!tree.canLock()) {
return false;
}
}
return true;
}
}
exports.MutableTrees = MutableTrees;
// ValidateKey returns an error if the key is not valid.
function validateKey(key) {
if (key === '') {
// Root node.
return null;
}
if (key.length < 2) {
return new Error(`too short key: "${key}"`);
}
if (key[0] !== '/') {
return new Error(`key must start with '/': "${key}"`);
}
if (key[key.length - 1] === '/') {
return new Error(`key must not end with '/': "${key}"`);
}
return null;
}
function cleanKey(key) {
if (key === '/') {
// The path to the home page is logically "/",
// but for technical reasons, it's stored as "".
// This allows us to treat the home page as a section,
// and a prefix search for "/" will return the home page's descendants.
return '';
}
return key;
}
function mustValidateKey(key) {
const err = validateKey(key);
if (err) {
throw err;
}
return key;
}
//# sourceMappingURL=support.js.map