twing
Version:
First-class Twig engine for Node.js
271 lines (270 loc) • 9.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSynchronousFilesystemLoader = exports.createFilesystemLoader = void 0;
const path_1 = require("path");
const source_1 = require("../source");
const rtrim = require('locutus/php/strings/rtrim');
const createFilesystemLoader = (filesystem) => {
const namespacedPaths = new Map();
const stat = (path) => {
return new Promise((resolve) => {
filesystem.stat(path, (error, stats) => {
if (error) {
resolve(null);
}
else {
resolve(stats);
}
});
});
};
const resolvePathFromSource = (name, from) => {
if (name && !(0, path_1.isAbsolute)(name) && name.startsWith('.')) {
name = (0, path_1.join)((0, path_1.dirname)(from), name);
}
return name;
};
// todo: rework
// * if no slash, resolve from "from"
// * if contains a slash, extract namespace and check if registered:
// * if so, resolve from namespace
// * if not found yet, resolve from "from"
const resolve = (name, from) => {
name = (0, path_1.normalize)(from ? resolvePathFromSource(name, from) : name);
const findTemplateInPath = async (path) => {
const stats = await stat(path);
if (stats && stats.isFile()) {
return Promise.resolve(path);
}
else {
return Promise.resolve(null);
}
};
// first search for the template from its fully qualified name
return findTemplateInPath(name)
.then((templatePath) => {
if (templatePath) {
return templatePath;
}
else {
// then, search for the template from its namespaced name
const [namespace, shortname] = parseName(name);
const paths = namespacedPaths.get(namespace) || ['.'];
const findTemplateInPathAtIndex = async (index) => {
if (index < paths.length) {
const path = paths[index];
const templatePath = await findTemplateInPath((0, path_1.join)(path, shortname));
if (templatePath) {
return Promise.resolve(templatePath);
}
else {
// let's continue searching
return findTemplateInPathAtIndex(index + 1);
}
}
else {
return Promise.resolve(null);
}
};
return findTemplateInPathAtIndex(0);
}
});
};
const parseName = (name) => {
// only non-relative names can be namespace references
if (name[0] !== '.') {
const position = name.indexOf('/');
if (position >= 0) {
const namespace = name.substring(0, position);
const shortname = name.substring(position + 1);
return [namespace, shortname];
}
}
return [null, name];
};
const addPath = (path, namespace = null) => {
let namespacePaths = namespacedPaths.get(namespace);
if (!namespacePaths) {
namespacePaths = [];
namespacedPaths.set(namespace, namespacePaths);
}
namespacePaths.push(rtrim(path, '\/\\\\'));
};
const prependPath = (path, namespace = null) => {
path = rtrim(path, '\/\\\\');
const namespacePaths = namespacedPaths.get(namespace);
if (!namespacePaths) {
namespacedPaths.set(namespace, [path]);
}
else {
namespacePaths.unshift(path);
}
};
return {
addPath,
exists: (name, from) => {
return resolve(name, from)
.then((path) => {
return path !== null;
});
},
resolve,
getSource: (name, from) => {
return resolve(name, from)
.then((path) => {
if (path === null) {
return null;
}
else {
return new Promise((resolve, reject) => {
filesystem.readFile(path, (error, data) => {
if (error) {
reject(error);
}
else {
resolve((0, source_1.createSource)(path, data.toString()));
}
});
});
}
});
},
isFresh: (name, time, from) => {
return resolve(name, from)
.then((path) => {
if (path === null) {
return true;
}
else {
return stat(path)
.then((stats) => {
return stats.mtime.getTime() <= time;
});
}
});
},
prependPath
};
};
exports.createFilesystemLoader = createFilesystemLoader;
const createSynchronousFilesystemLoader = (filesystem) => {
const namespacedPaths = new Map();
const stat = (path) => {
try {
return filesystem.statSync(path);
}
catch (error) {
return null;
}
};
const resolvePathFromSource = (name, from) => {
if (name && !(0, path_1.isAbsolute)(name) && name.startsWith('.')) {
name = (0, path_1.join)((0, path_1.dirname)(from), name);
}
return name;
};
// todo: rework
// * if no slash, resolve from "from"
// * if contains a slash, extract namespace and check if registered:
// * if so, resolve from namespace
// * if not found yet, resolve from "from"
const resolve = (name, from) => {
name = (0, path_1.normalize)(from ? resolvePathFromSource(name, from) : name);
const findTemplateInPath = (path) => {
const stats = stat(path);
if (stats && stats.isFile()) {
return path;
}
else {
return null;
}
};
// first search for the template from its fully qualified name
const templatePath = findTemplateInPath(name);
if (templatePath) {
return templatePath;
}
else {
// then, search for the template from its namespaced name
const [namespace, shortname] = parseName(name);
const paths = namespacedPaths.get(namespace) || ['.'];
const findTemplateInPathAtIndex = (index) => {
if (index < paths.length) {
const path = paths[index];
const templatePath = findTemplateInPath((0, path_1.join)(path, shortname));
if (templatePath) {
return templatePath;
}
else {
// let's continue searching
return findTemplateInPathAtIndex(index + 1);
}
}
else {
return null;
}
};
return findTemplateInPathAtIndex(0);
}
};
const parseName = (name) => {
// only non-relative names can be namespace references
if (name[0] !== '.') {
const position = name.indexOf('/');
if (position >= 0) {
const namespace = name.substring(0, position);
const shortname = name.substring(position + 1);
return [namespace, shortname];
}
}
return [null, name];
};
const addPath = (path, namespace = null) => {
let namespacePaths = namespacedPaths.get(namespace);
if (!namespacePaths) {
namespacePaths = [];
namespacedPaths.set(namespace, namespacePaths);
}
namespacePaths.push(rtrim(path, '\/\\\\'));
};
const prependPath = (path, namespace = null) => {
path = rtrim(path, '\/\\\\');
const namespacePaths = namespacedPaths.get(namespace);
if (!namespacePaths) {
namespacedPaths.set(namespace, [path]);
}
else {
namespacePaths.unshift(path);
}
};
return {
addPath,
exists: (name, from) => {
const path = resolve(name, from);
return path !== null;
},
resolve,
getSource: (name, from) => {
const path = resolve(name, from);
if (path === null) {
return null;
}
else {
const data = filesystem.readFileSync(path);
return (0, source_1.createSource)(path, data.toString());
}
},
isFresh: (name, time, from) => {
const path = resolve(name, from);
if (path === null) {
return true;
}
else {
const stats = stat(path);
return stats.mtime.getTime() <= time;
}
},
prependPath
};
};
exports.createSynchronousFilesystemLoader = createSynchronousFilesystemLoader;