add some support for tickets, introspection method, minor fixes
[squeep-indieauth-helper] / lib / common.js
1 'use strict';
2
3 const path = require('path');
4
5 /**
6 * Return a function which combines a part of the filename with a scope, for use in logging.
7 * @param {string} filename
8 */
9 const fileScope = (filename) => {
10 let fScope = path.basename(filename, '.js');
11 if (fScope === 'index') {
12 fScope = path.basename(path.dirname(filename));
13 }
14 return (scope) => `${fScope}:${scope}`;
15 }
16
17
18 /**
19 * Pick out useful axios response fields.
20 * @param {AxiosResponse} res
21 * @returns {Object}
22 */
23 const axiosResponseLogData = (res) => {
24 const data = pick(res, [
25 'status',
26 'statusText',
27 'headers',
28 'elapsedTimeMs',
29 'data',
30 ]);
31 if (data.data) {
32 data.data = logTruncate(data.data, 100);
33 }
34 return data;
35 };
36
37
38 /**
39 * Limit length of string to keep logs sane
40 * @param {String} str
41 * @param {Number} len
42 * @returns {String}
43 */
44 const logTruncate = (str, len) => {
45 if (typeof str !== 'string' || str.toString().length <= len) {
46 return str;
47 }
48 return str.toString().slice(0, len) + `... (${str.toString().length} bytes)`;
49 };
50
51
52 /**
53 * Return a new object with selected props.
54 * @param {Object} obj
55 * @param {String[]} props
56 */
57 const pick = (obj, props) => {
58 return props.reduce((acc, prop) => {
59 if (prop in obj) {
60 acc[prop] = obj[prop]; // eslint-disable-line security/detect-object-injection
61 }
62 return acc;
63 }, {});
64 };
65
66
67 /**
68 * Return a set containing non-shared items between two sets.
69 * @param {Set} a
70 * @param {Set} b
71 * @returns {Set}
72 */
73 const setSymmetricDifference = (a, b) => {
74 const d = new Set(a);
75 for (const x of b) {
76 if (d.has(x)) {
77 d.delete(x);
78 } else {
79 d.add(x);
80 }
81 }
82 return d;
83 };
84
85
86 /**
87 * URL objects have weird names.
88 * @param {String} component
89 * @returns {String}
90 */
91 const properURLComponentName = (component) => {
92 // eslint-disable-next-line security/detect-object-injection
93 return {
94 hash: 'fragment',
95 protocol: 'scheme',
96 }[component] || component;
97 }
98
99
100 /**
101 * Encodes single-level object as form data string.
102 * @param {Object} data
103 */
104 const formData = (data) => {
105 const formData = new URLSearchParams();
106 Object.entries(data).forEach(([name, value]) => formData.set(name, value));
107 return formData.toString();
108 };
109
110
111 module.exports = {
112 fileScope,
113 axiosResponseLogData,
114 logTruncate,
115 pick,
116 setSymmetricDifference,
117 properURLComponentName,
118 formData,
119 };