included obj lib

Massimo Melina committed Dec 17, 2021 at 10:46 UTC c3eff9638fc84d88875830129211ff02e55a2085
3 files changed +109 -4
src/misc.ts
+5
@@ -1,5 +1,6 @@
1 import { stat } from 'fs/promises'
2 import glob from 'fast-glob'
3 +import { objSameKeys } from './obj'
4
5 export function enforceFinal(sub:string, s:string) {
6 return s.endsWith(sub) ? s : s+sub
@@ -32,3 +33,7 @@ export async function globDir(path: string, ignore?: any[]) {
33 ignore: ignore?.flat().filter(Boolean).map(x => path!+x),
34 })
35 }
36 +
37 +export function setHidden(dest: object, src:object) {
38 + Object.defineProperties(dest, objSameKeys(src, value => ({ enumerable:false, value })))
39 +}
src/obj.ts new
+102
@@ -0,0 +1,102 @@
1 +/** creates an object iterating an array or an object.
2 + * The callback(val,key/index) should return [val,key] to set both, or just [val] and they key is kept, or just the key (no array) and val will be kept,
3 + * or an object to merge with the result, or undefined to skip.
4 + */
5 +type Key = string | number
6 +type Mapper = (v?: any, k?: Key, src?:any, dst?:object) => any
7 +
8 +export function obj(src:any, cb: string | Mapper, skipUndefined:boolean=true, dst:any={}) {
9 + const short = (typeof cb==='string')
10 + let i = 0
11 + if (Array.isArray(src))
12 + for (const e of src)
13 + work(e, i++)
14 + else
15 + for (const k in src)
16 + work(src[k], k)
17 + return dst
18 +
19 + function work(entry:any, k: Key) {
20 + const r = short ? entry[cb] : cb(entry,k,src,dst)
21 + if (short)
22 + add(k, r)
23 + else if (Array.isArray(r))
24 + if (r.length===1)
25 + add(k, r[0])
26 + else
27 + add(r[1], r[0])
28 + else if (r instanceof Object)
29 + Object.assign(dst, r)
30 + else
31 + add(r, entry)
32 + }
33 +
34 + function add(k: Key | string[], v: any) {
35 + if (k === undefined || (skipUndefined && v === undefined))
36 + return
37 + let o = dst
38 + if (Array.isArray(k))
39 + if (k.length === 1)
40 + k = k[0]
41 + else {
42 + const a = k
43 + k = a.pop() as Key
44 + for (const k1 of a) // @ts-ignore
45 + o = o[k1] instanceof Object ? o[k1] : (o[k1] = {})
46 + }
47 + o[k] = v
48 + }
49 +}
50 +
51 +export function objFilter(src:any, cb:Mapper) {
52 + return obj(src, function(v,k){ // @ts-ignore
53 + return cb.apply(this,arguments) ? k : undefined
54 + })
55 +}
56 +
57 +export function objSameKeys(src:any, cb:Mapper | string) {
58 + return obj(src, typeof cb === 'string' ? cb : (...args)=> [cb(...args)])
59 +}
60 +
61 +export function objFromKeys(keys: string[], returnValueFromKey:(k:string)=>any, skipUndefined=true) {
62 + return obj(keys, k => [returnValueFromKey(k), k], skipUndefined)
63 +}
64 +
65 +// useful only in the extent of making clear your intentions
66 +export const objSameValues = obj
67 +
68 +//** replace object's (or array's) values with those returned by callback
69 +export function remap(obj:any, map:Mapper, skipUndefined=true) {
70 + if (!obj) return
71 + if (Array.isArray(obj)) {
72 + let k = obj.length
73 + while (k--) {
74 + const v = map(obj[k], k)
75 + if (v !== undefined || !skipUndefined)
76 + obj[k] = v
77 + else
78 + obj.splice(k, 1) // will this cause problems if we remove in the middle?
79 + }
80 + return
81 + }
82 + for (const k in obj) {
83 + const v = map(obj[k], k)
84 + if (v !== undefined || !skipUndefined)
85 + obj[k] = v
86 + else
87 + delete obj[k]
88 + }
89 +}
90 +
91 +// replace object's keys using map object. If undefined the key will be removed.
92 +export function remapKeys(obj:any, map:Record<string,string>) {
93 + if (obj)
94 + for (const k in obj)
95 + if (obj.hasOwnProperty(k) && map.hasOwnProperty(k)) {
96 + const newK = map[k]
97 + if (newK !== undefined)
98 + obj[newK] = obj[k]
99 + delete obj[k]
100 + }
101 + return obj
102 +}
src/perm.ts
+2 -4
@@ -4,6 +4,7 @@ import _ from 'lodash'
4 import yaml from 'yaml'
5 import { hashPassword } from './crypt'
6 import { argv } from './const'
7 +import { setHidden } from './misc'
8
9 const PATH = argv.accounts || 'accounts.yaml'
10
@@ -44,10 +45,7 @@ async function load() {
45 accounts = res.accounts
46 let changed = false
47 await Promise.all(_.map(accounts, async (rec,k) => {
47 - Object.defineProperty(rec, 'user', {
48 - enumerable: false, // sneak it in
49 - value: k,
50 - })
48 + setHidden(rec, { user: k })
49 if (rec.password) {
50 rec.hashedPassword = await hashPassword(rec.password)
51 delete rec.password