UNPKG

peri-templating-api

Version:
552 lines (466 loc) 17.7 kB
/** * PERI Templating API (for Javascript) 0.1.0. * * Copyright (c) 2014-2021 Platforme International. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var fs = require('fs'); var path = require('path'); var process$1 = require('process'); var fetch = require('node-fetch'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); /** * Yonius 0.5.8. * * Copyright (c) 2008-2021 Hive Solutions Lda. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE file in the root directory of this source tree. */ class Observable { constructor() { this.callbacks = {}; } bind(event, callback) { const callbacks = this.callbacks[event] || []; callbacks.push(callback); this.callbacks[event] = callbacks; return callback; } unbind(event, callback) { const callbacks = this.callbacks[event] || []; if (!callback) { delete this.callbacks[event]; return; } const index = callbacks.indexOf(callback); if (index === -1) { return; } callbacks.splice(index, 1); this.callbacks[event] = callbacks; } trigger(event) { const callbacks = this.callbacks[event] || []; const results = []; for (const callback of callbacks) { const result = callback.apply(this, Array.prototype.slice.call(arguments, 1)); result !== undefined && result !== null && results.push(result); } return Promise.all(results); } } const verify = function( condition, message = null, code = null, exception = null, kwargs = {} ) { if (condition) return; message = message || "Verification failed"; const Exception = exception || Error; kwargs = Object.assign({}, kwargs); if (message !== null && message !== undefined) kwargs.message = message; if (code !== null && message !== undefined) kwargs.code = code; const throwable = new Exception(kwargs.message || undefined); throwable.kwargs = kwargs; for (const [key, value] of Object.entries(kwargs)) { if (throwable[key] !== undefined) continue; throwable[key] = value; } throw throwable; }; let HOME_DIR = null; const pathExists = async function(path) { try { await fs.promises.access(path); } catch (error) { return false; } return true; }; const expandUser = function(path$1) { if (!path$1) return path$1; if (path$1 === "~") return _homeDir(); if (path$1.slice(0, 2) !== "~/") return path$1; return path.join(HOME_DIR, path$1.slice(2)); }; const getEnv = function(name) { // eslint-disable-next-line no-undef if (typeof Deno !== "undefined") return Deno.env.get(name); return process$1.env[name]; }; const getEnvObject = function() { // eslint-disable-next-line no-undef if (typeof Deno !== "undefined") return Deno.env.toObject(); return process$1.env; }; const _homeDir = function() { if (HOME_DIR !== null) return HOME_DIR; const isWindows = Boolean(typeof process !== "undefined" && process.platform === "win32"); HOME_DIR = getEnv(isWindows ? "USERPROFILE" : "HOME") || "/"; return HOME_DIR; }; const FILE_NAME = "yonius.json"; const HOME_FILE = "~/.home"; const IMPORT_NAMES = ["$import", "$include", "$IMPORT", "$INCLUDE"]; const CASTS = { int: v => (typeof v === "number" ? v : parseInt(v)), float: v => (typeof v === "number" ? v : parseFloat(v)), bool: v => (typeof v === "boolean" ? v : ["1", "true", "True"].includes(v)), list: v => (Array.isArray(v) ? v : v.split(";")), tuple: v => (Array.isArray(v) ? v : v.split(";")) }; const globals = typeof global === "undefined" ? typeof window === "undefined" ? typeof self === "undefined" ? {} : self : window : global; globals.CONFIGS = globals.CONFIGS === undefined ? {} : globals.CONFIGS; globals.CONFIG_F = globals.CONFIG_F === undefined ? [] : globals.CONFIG_F; globals.HOMES = globals.HOMES === undefined ? [] : globals.HOMES; globals.LOADED = globals.LOADED === undefined ? false : globals.LOADED; const conf = function(name, fallback = undefined, cast = null, ctx = null) { const configs = ctx ? ctx.configs : globals.CONFIGS; cast = _castR(cast); let value = configs[name] === undefined ? fallback : configs[name]; if (cast && value !== undefined && value !== null) value = cast(value); return value; }; const load = async function( names = [FILE_NAME], path$1 = null, encoding = "utf-8", force = false, ctx = null ) { if (globals.LOADED && !force) return; let paths = []; const homes = await getHomes(); for (const home of homes) { paths = paths.concat([path.join(home), path.join(home, ".config")]); } paths.push(path$1); for (const path of paths) { for (const name of names) { await loadFile(name, path, encoding, ctx); } } await loadEnv(ctx); globals.LOADED = true; }; const loadFile = async function( name = FILE_NAME, path$1 = null, encoding = "utf-8", ctx = null ) { const configs = ctx ? ctx.configs : globals.CONFIGS; const configF = ctx ? ctx.configF : globals.CONFIG_F; let key; let value; let exists; let filePath; if (path$1) path$1 = path.normalize(path$1); if (path$1) filePath = path.join(path$1, name); else filePath = name; filePath = path.resolve(filePath); filePath = path.normalize(filePath); const basePath = path.dirname(filePath); exists = await pathExists(filePath); if (!exists) return; exists = configF.includes(filePath); if (exists) configF.splice(configF.indexOf(filePath), 1); configF.push(filePath); const data = await fs.promises.readFile(filePath, { encoding: encoding }); const dataJ = JSON.parse(data); await _loadIncludes(basePath, dataJ, encoding); for ([key, value] of Object.entries(dataJ)) { if (!_isValid(key)) continue; configs[key] = value; } }; const loadEnv = async function(ctx = null) { const env = getEnvObject(); const configs = ctx ? ctx.configs : globals.CONFIGS; if (env === undefined || env === null) return; Object.entries(env).forEach(function([key, value]) { configs[key] = value; }); }; const getHomes = async function( filePath = HOME_FILE, fallback = "~", encoding = "utf-8", forceDefault = false ) { if (globals.HOMES.length > 0) return globals.HOMES; const env = getEnvObject(); globals.HOMES = env.HOMES === undefined ? null : env.HOMES; globals.HOMES = globals.HOMES ? globals.HOMES.split(";") : globals.HOMES; if (globals.HOMES !== null) return globals.HOMES; fallback = expandUser(fallback); fallback = path.normalize(fallback); globals.HOMES = [fallback]; filePath = expandUser(filePath); filePath = path.normalize(filePath); const exists = await pathExists(filePath); if (!exists) return globals.HOMES; if (!forceDefault) globals.HOMES.splice(0, globals.HOMES.length); let data = await fs.promises.readFile(filePath, { encoding: encoding }); data = data.trim(); let paths = data.split(/\r?\n/); paths = paths.map(v => v.trim()); for (let path$1 of paths) { path$1 = path$1.trim(); if (!path$1) continue; path$1 = expandUser(path$1); path$1 = path.normalize(path$1); globals.HOMES.push(path$1); } return globals.HOMES; }; const _castR = function(cast) { return CASTS[cast] === undefined ? cast : CASTS[cast]; }; const _loadIncludes = async function(basePath, config, encoding = "utf-8") { let includes = []; for (const alias of IMPORT_NAMES) { includes = config[alias] === undefined ? includes : config[alias]; } if (typeof includes === "string") { includes = includes.split(";"); } for (const include of includes) { await loadFile(include, basePath, encoding); } }; const _isValid = function(key) { if (IMPORT_NAMES.includes(key)) return false; return true; }; /** * Encodes the multiple values as and encoded URI component, the * values can be wither defined as an array (order is preserved) * or as an object (where sequence order is not preserved). * * The value of each item can be either a primitive type or a sequence * in case it's of sequence the values are going to be encoded as * multiple parameters separated by the '&' character. * * @param {(Array|Object[])} values The values to be encoded as an * URI component (like GET params). * @returns {String} A string with the query encoded values. */ const urlEncode = function(values) { // constructs the parts array that is going to // store the multiple and values const parts = []; // in case the provided value is not an array // then assumes it's an object and retrieve entries if (!Array.isArray(values)) { values = Object.entries(values); } // iterates over the complete set of pairs available // from the key value pairs to be able to encode them // properly, notice that the values themselves can be // sequences allowing multiple repetition of key values.forEach(([key, value]) => { if (!Array.isArray(value)) { value = [value]; } const keyEncoded = encodeURIComponent(key); value.forEach(_value => { if (_value === undefined || _value === null) { return; } const valueEncoded = encodeURIComponent(_value); parts.push(`${keyEncoded}=${valueEncoded}`); }); }); // joins the complete set of parts with the and // separator and then returns the final string value return parts.join("&"); }; const AUTH_ERRORS = [401, 403, 440, 499]; class API extends Observable { constructor(kwargs = {}) { super(); this.kwargs = kwargs; } async build(method, url, options = {}) {} async authCallback(params, headers) {} async get(url, options = {}) { const result = await this.methodBasic("GET", url, options); return result; } async post(url, options = {}) { const result = await this.methodPayload("POST", url, options); return result; } async put(url, options = {}) { const result = await this.methodPayload("PUT", url, options); return result; } async delete(url, options = {}) { const result = await this.methodBasic("DELETE", url, options); return result; } async patch(url, options = {}) { const result = await this.methodPayload("PATCH", url, options); return result; } async options(url, options = {}) { const result = await this.methodBasic("OPTIONS", url, options); return result; } async methodBasic(method, url, options = {}) { options.params = options.params !== undefined ? options.params : {}; options.headers = options.headers !== undefined ? options.headers : {}; try { return await this._methodBasic(method, url, options); } catch (err) { if (AUTH_ERRORS.includes(err.code)) { await this.authCallback(options.params, options.headers); return await this._methodBasic(method, url, options); } else { throw err; } } } async methodPayload(method, url, options = {}) { options.params = options.params !== undefined ? options.params : {}; options.headers = options.headers !== undefined ? options.headers : {}; try { return await this._methodPayload(method, url, options); } catch (err) { if (AUTH_ERRORS.includes(err.code)) { await this.authCallback(options.params, options.headers); return await this._methodPayload(method, url, options); } else { throw err; } } } async _methodBasic(method, url, options = {}) { const params = options.params !== undefined ? options.params : {}; const headers = options.headers !== undefined ? options.headers : {}; const kwargs = options.kwargs !== undefined ? options.kwargs : {}; const handle = options.handle !== undefined ? options.handle : true; await this.build(method, url, { params: params, headers: headers, kwargs: kwargs }); const query = urlEncode(params || {}); if (query) url += url.includes("?") ? "&" + query : "?" + query; const response = await fetch__default['default'](url, { method: method, headers: headers || {} }); const result = handle ? await this._handleResponse(response) : response; return result; } async _methodPayload(method, url, options = {}) { const params = options.params !== undefined ? options.params : {}; let headers = options.headers !== undefined ? options.headers : {}; let data = options.data !== undefined ? options.data : null; const dataJ = options.dataJ !== undefined ? options.dataJ : null; const dataM = options.dataM !== undefined ? options.dataM : null; let mime = options.mime !== undefined ? options.mime : null; const kwargs = options.kwargs !== undefined ? options.kwargs : {}; const handle = options.handle !== undefined ? options.handle : true; await this.build(method, url, { params: params, headers: headers, data: data, dataJ: dataJ, dataM: dataM, mime: mime, kwargs: kwargs }); const query = urlEncode(params || {}); if (data !== null) { if (query) url += url.includes("?") ? "&" + query : "?" + query; } else if (dataJ !== null) { data = JSON.stringify(dataJ); if (query) url += url.includes("?") ? "&" + query : "?" + query; mime = mime || "application/json"; } else if (dataM !== null) { if (query) url += url.includes("?") ? "&" + query : "?" + query; } else if (query) { data = query; mime = mime || "application/x-www-form-urlencoded"; } headers = Object.assign({}, headers); if (mime) headers["Content-Type"] = mime; const response = await fetch__default['default'](url, { method: method, headers: headers || {}, body: data }); const result = handle ? await this._handleResponse(response) : response; return result; } async _handleResponse(response, errorMessage = "Problem in request") { let result = null; if ( response.headers.get("content-type") && response.headers.get("content-type").toLowerCase().startsWith("application/json") ) { result = await response.json(); } else if ( response.headers.get("content-type") && response.headers.get("content-type").toLowerCase().startsWith("text/") ) { result = await response.text(); } else { result = await response.blob(); } verify(response.ok, result.error || errorMessage, response.status || 500); return result; } } const load$1 = async function() { await load(); }; const BASE_URL = "http://localhost:3000/"; class API$1 extends API { constructor(kwargs = {}) { super(kwargs); this.baseUrl = conf("PERI_TEMPLATING_BASE_URL", BASE_URL); this.token = conf("PERI_TEMPLATING_TOKEN", null); this.baseUrl = kwargs.baseUrl === undefined ? this.baseUrl : kwargs.baseUrl; this.token = kwargs.token === undefined ? this.token : kwargs.token; } static async load() { await load$1(); } async build(method, url, options = {}) { await super.build(method, url, options); options.headers = options.params !== undefined ? options.headers : {}; options.kwargs = options.kwargs !== undefined ? options.kwargs : {}; const auth = options.kwargs.auth === undefined ? true : options.kwargs.auth; delete options.kwargs.auth; if (auth) { options.headers.Authorization = `Bearer ${this.token}`; } } async render(template, payload) { const url = this.baseUrl + template; return await this.post(url, { dataJ: payload }); } } exports.API = API$1; //# sourceMappingURL=peri-templating-api.cjs.js.map