UNPKG

twing

Version:

First-class Twig engine for Node.js

271 lines (270 loc) 9.58 kB
"use strict"; 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;