@coderich/sandman 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderich/sandman",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "main": "index.js",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,5 +1,7 @@
1
1
  const Merge = require('lodash.merge');
2
2
 
3
+ function shq(s) { return `'${String(s).replace(/'/g, `'"'"'`)}'`; }
4
+
3
5
  exports.fetch = (req) => {
4
6
  return new Promise((resolve, reject) => {
5
7
  const { url, ...params } = exports.normalizeRequest({ ...req });
@@ -57,3 +59,48 @@ exports.decorateRequest = (mergeData, key, request) => {
57
59
 
58
60
  return Merge({}, toMerge, request);
59
61
  };
62
+
63
+ exports.toCURL = (request, { pretty = true, redactAuth = false } = {}) => {
64
+ if (!request) return '<no request>';
65
+
66
+ const { url, path, method, headers, params, data } = request;
67
+
68
+ const base = new URL(url);
69
+ const full = new URL(path || '', base);
70
+
71
+ // append query params
72
+ for (const [k, v] of Object.entries(params || {})) {
73
+ if (v == null) continue;
74
+ Array.isArray(v) ? v.forEach(x => full.searchParams.append(k, String(x))) : full.searchParams.append(k, String(v));
75
+ }
76
+
77
+ const parts = ['curl', '-sS'];
78
+ if (method) parts.push('-X', method.toUpperCase());
79
+
80
+ // headers
81
+ const hdrs = { ...headers };
82
+ for (const k of Object.keys(hdrs)) {
83
+ if (redactAuth && /^authorization$/i.test(k)) {
84
+ hdrs[k] = hdrs[k].replace(/(?<=^.{6}).+/, '***REDACTED***');
85
+ }
86
+ parts.push('-H', shq(`${k}: ${hdrs[k]}`));
87
+ }
88
+
89
+ // body (skip for GET)
90
+ if (data != null && !/^GET$/i.test(method)) {
91
+ if (typeof data === 'string') {
92
+ parts.push('--data-raw', shq(data));
93
+ } else if (data instanceof URLSearchParams) {
94
+ parts.push('-H', shq('Content-Type: application/x-www-form-urlencoded'));
95
+ parts.push('--data', shq(data.toString()));
96
+ } else if (typeof data === 'object') {
97
+ // JSON by default
98
+ const hasCT = Object.keys(hdrs).some(h => /^content-type$/i.test(h));
99
+ if (!hasCT) parts.push('-H', shq('Content-Type: application/json'));
100
+ parts.push('--data-raw', shq(JSON.stringify(data)));
101
+ }
102
+ }
103
+
104
+ parts.push(shq(full.toString()));
105
+ return pretty ? parts.join(' \\\n ') : parts.join(' ');
106
+ };
package/src/Sandman.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const Path = require('path');
2
+ const Merge = require('lodash.merge');
2
3
  const Readline = require('readline');
3
4
  const Chokidar = require('chokidar');
4
5
  const EventEmitter = require('events');
@@ -10,7 +11,7 @@ const resolveSymbol = Symbol('resolve');
10
11
 
11
12
  module.exports = class Sandman extends EventEmitter {
12
13
  #configClient; #configDir; #options; #watcher; #readline; #mergeData = {}; #cli;
13
- #captureCandidates = false; #candidates = []; #tabCounter = 0; #candidateIndex = 0; #line; #lastToken;
14
+ #captureCandidates = false; #candidates = []; #tabCounter = 0; #candidateIndex; #line; #lastToken;
14
15
 
15
16
  constructor(configDir, options) {
16
17
  super();
@@ -36,7 +37,6 @@ module.exports = class Sandman extends EventEmitter {
36
37
  resolve: {
37
38
  value: (...args) => {
38
39
  this.#configClient.resolve(...args);
39
- this.#prompt();
40
40
  return this.#cli;
41
41
  },
42
42
  configurable: true,
@@ -71,10 +71,10 @@ module.exports = class Sandman extends EventEmitter {
71
71
  const value = get(config, key);
72
72
 
73
73
  if (value?.request) {
74
- const request = FetchService.decorateRequest(this.#mergeData, key, value.request);
75
- const $request = this.#configClient.set(resolveSymbol, request).get(resolveSymbol);
74
+ const $request = FetchService.decorateRequest(this.#mergeData, key, value.request);
75
+ const request = this.#configClient.set(resolveSymbol, $request).get(resolveSymbol);
76
76
  this.#configClient.del(resolveSymbol);
77
- return $request;
77
+ return Merge({}, value, { request });
78
78
  }
79
79
 
80
80
  return this.#configClient.get(key, ...rest);
@@ -88,6 +88,7 @@ module.exports = class Sandman extends EventEmitter {
88
88
  get: (...args) => this.#get(...args),
89
89
  set: (key = '', value = null) => this.#configClient.set(key, value),
90
90
  del: (key = '') => this.#configClient.del(key),
91
+ curl: key => FetchService.toCURL(this.#get(key, {}).request),
91
92
  quit: () => process.exit(),
92
93
  }, {
93
94
  get(obj, prop, receiver) {
@@ -95,8 +96,9 @@ module.exports = class Sandman extends EventEmitter {
95
96
 
96
97
  if (typeof value === 'function') {
97
98
  return (...args) => {
99
+ self.#readline.pause();
98
100
  const result = value(...args);
99
- setImmediate(() => self.#prompt());
101
+ Promise.resolve().then(() => result).catch(() => null).finally(() => self.#prompt());
100
102
  return result;
101
103
  };
102
104
  }
@@ -153,7 +155,8 @@ module.exports = class Sandman extends EventEmitter {
153
155
  });
154
156
 
155
157
  const candidates = Array.from(new Set(startsWithCandidates.concat(requestKeyCandidates)));
156
- if (this.#captureCandidates) { this.#candidates = candidates; this.#line = line; this.#lastToken = lastToken; }
158
+ if (this.#captureCandidates) { this.#candidates = candidates; this.#line = line; this.#lastToken = lastToken; this.#candidateIndex = -1; }
159
+ if (candidates.length === 1 && candidates[0] === lastToken) return [[], lastToken];
157
160
  return [candidates, lastToken];
158
161
  },
159
162
  });
@@ -168,14 +171,8 @@ module.exports = class Sandman extends EventEmitter {
168
171
  Readline.clearLine(process.stdout, 0);
169
172
  this.#readline.prompt();
170
173
  } else if (this.#tabCounter > 2 && this.#candidates.length) {
171
- let value = this.#candidates.at(this.#candidateIndex++);
172
-
173
- if (!value) {
174
- this.#candidateIndex = 0;
175
- value = this.#candidates.at(this.#candidateIndex++);
176
- }
177
-
178
- value = this.#line.replace(this.#lastToken, value);
174
+ const candidate = this.#candidates[this.#candidateIndex = ++this.#candidateIndex % this.#candidates.length];
175
+ const value = this.#line.replace(this.#lastToken, candidate);
179
176
  this.#readline.line = value;
180
177
  this.#readline.cursor = value.length;
181
178
  this.#readline.prompt(true);
@@ -196,7 +193,7 @@ module.exports = class Sandman extends EventEmitter {
196
193
  if (['add', 'change'].includes(event)) {
197
194
  const api = ConfigClient.parseFile(path);
198
195
  if (key) this.#configClient.set(key, api);
199
- else this.#configClient.merge(api);
196
+ else this.#configClient.merge(api); // index.yaml
200
197
  if (api.request) this.emit('save', { key, api });
201
198
  this.#prompt();
202
199
  } else if (['unlink', 'unlinkDir'].includes(event)) {