servez 1.14.1 → 2.0.0

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.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/bin/servez +127 -141
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -12,6 +12,10 @@
12
12
 
13
13
  # Installing globally:
14
14
 
15
+ !!!Note!!!: you need to install [node.js](https://nodejs.org).
16
+ I recommend installing node via [nvm](https://github.com/nvm-sh/nvm)(mac/linux)
17
+ or [nvm-windows](https://github.com/coreybutler/nvm-windows)(windows)
18
+
15
19
  Installation via `npm`:
16
20
 
17
21
  npm install servez -g
package/bin/servez CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const makeOptions = require('optionator');
5
+ const { program } = require('commander');
6
+ const pkg = require('../package.json');
6
7
  const colorSupport = require('color-support') || {};
7
8
  const c = require('ansi-colors');
8
9
  c.enabled = colorSupport.hasBasic;
@@ -19,153 +20,138 @@ const log = {
19
20
  },
20
21
  };
21
22
 
22
- function genQRCode(s) {
23
-
24
- const qr = QrCode.encodeText(s, Ecc.MEDIUM);
25
- const size = qr.size + 2;
26
-
27
- const lines = [];
28
- for (let y = -2; y < size; ++y) {
29
- const line = [];
30
- for (let x = -2; x < size; ++x) {
31
- line.push(c[qr.getModule(x, y) ? 'bgBlack' : 'bgWhite'](' '));
32
- }
33
- lines.push(line.join(''));
23
+ const fixedParseInt = v => parseInt(v);
24
+ const parseHeader = (v, oldV) => {
25
+ console.log('v:', `'${v}'`);
26
+ console.log('oldV:', `'${JSON.stringify(oldV)}'`);
27
+ const m = /^(.*?):(.*?)$/.exec(v);
28
+ if (!m) {
29
+ throw new Error('bad header argument: format is --header=<header>:<value>');
34
30
  }
35
- return lines.join('\n');
36
- }
37
-
38
- const optionSpec = {
39
- options: [
40
- { option: 'help', alias: 'h', type: 'Boolean', description: 'displays help' },
41
- { option: 'port', alias: 'p', type: 'Int', description: 'port', default: '8080' },
42
- { option: 'version', type: 'Boolean', description: 'print version' },
43
- { option: 'scan', type: 'Boolean', description: 'scan for open port', default: 'true', },
44
- { option: 'qr', type: 'Boolean', description: 'print QR Code for root url' },
45
- { option: 'dirs', type: 'Boolean', description: 'show directory listing', default: 'true', },
46
- { option: 'cors', type: 'Boolean', description: 'send CORS headers', default: 'true', },
47
- { option: 'local', type: 'Boolean', description: 'local machine only', default: 'false', },
48
- { option: 'index', type: 'Boolean', description: 'serve index.html for directories', default: 'true', },
49
- { option: 'extensions', type: '[String]', description: 'extensions to try if path does not exist', default: '["html"]', },
50
- { option: 'unity-hack', type: 'Boolean', description: 'ignore .gz and .br when computing content type', default: 'true', },
51
- { option: 'shared-array-buffers', type: 'Boolean', description: "include headers 'Cross-Origin-Opener-Policy': 'same-origin' and 'Cross-Origin-Embedder-Policy': 'require-corp'", default: 'false', },
52
- { option: 'header', type: 'Object', description: 'extra headers to include eg --header=Content-Language:de-DE', mergeRepeatedObjects: true},
53
- { option: 'gzip', type: 'Boolean', description: 'serve .gz files if they exist', default: 'false', },
54
- { option: 'brotli', type: 'Boolean', description: 'serve .br files if they exist', default: 'false', },
55
- { option: 'robots', type: 'Boolean', description: 'serve a robots.txt if one does not exist', default: 'true', },
56
- { option: 'hidden', type: 'Boolean', description: 'show hidden dotfiles', default: 'false', },
57
- { option: 'username', type: 'String', description: 'username for basic auth' },
58
- { option: 'password', type: 'String', description: 'password for basic auth' },
59
- { option: 'ssl', alias: 'S', type: 'Boolean', description: 'enable https (will use fake cert if not specified)', },
60
- { option: 'cert', alias: 'C', type: 'String', description: 'Path to ssl cert file', },
61
- { option: 'key', alias: 'K', type: 'String', description: 'Path to ssl key file', },
62
- ],
63
- prepend: `Usage: servez [options] [path-to-serve]`,
64
- helpStyle: {
65
- typeSeparator: '=',
66
- descriptionSeparator: ' : ',
67
- initialIndent: 4,
68
- },
31
+ const newV = {...oldV};
32
+ newV[m[1]] = m[2];
33
+ return newV;
69
34
  };
70
- /* eslint-enable object-curly-newline */
71
- const optionator = makeOptions(optionSpec);
72
-
73
- let args;
74
- try {
75
- args = optionator.parse(process.argv);
76
- } catch (e) {
77
- log.error(e);
78
- printHelp();
79
- }
80
35
 
81
- function printHelp() {
82
- log.info(optionator.generateHelp());
83
- process.exit(1); // eslint-disable-line
84
- }
85
-
86
- if (args.help) {
87
- printHelp();
88
- }
89
-
90
- if (args.version) {
91
- const pkg = require('../package.json');
92
- log.info(pkg.version);
93
- process.exit(0);
94
- }
95
-
96
- args.headers = args.header;
97
- delete args.header;
98
-
99
- const fs = require('fs');
100
- const path = require('path');
101
- const {QrCode, Ecc} = require('../lib/qrcodegen');
102
- const hosts = [];
103
-
104
- const root = path.resolve(args._[0] || process.cwd());
105
- try {
106
- const stat = fs.statSync(root);
107
- if (!stat.isDirectory()) {
108
- log.error(`'${root}' is not a directory`);
109
- process.exit(1); // eslint-disable-line
110
- }
111
- } catch (e) {
112
- if (e.code === 'ENOENT') {
113
- log.warn(c.bold.yellow(`!!!!!!!!!!!!!!!\n\n WARNING: '${root}' does not exist!\n\n!!!!!!!!!!!!!!!`));
114
- } else {
115
- log.error(e, e.stack);
116
- process.exit(1); // eslint-disable-line
36
+ program
37
+ .name('servez')
38
+ .version(pkg.version)
39
+ .usage('[options] [path-to-serve]')
40
+ .argument('[path-to-serve]', 'path to serve')
41
+ .option('-p, --port <port>', 'port', fixedParseInt, 8080)
42
+ .option('--no-scan', 'do not scan for open port')
43
+ .option('--qr', 'print QR Code for root url')
44
+ .option('--no-dirs', 'do not show directory listing')
45
+ .option('--no-cors', 'do not send CORS headers')
46
+ .option('--local', 'local machine only')
47
+ .option('--no-index', 'do not serve index.html for directories')
48
+ .option('--extensions <extensions...>','extensions to try if path does not exist', ['html'])
49
+ .option('--no-unity-hack', 'do not ignore .gz and .br when computing content type')
50
+ .option('--shared-array-buffers', "include headers 'Cross-Origin-Opener-Policy': 'same-origin' and 'Cross-Origin-Embedder-Policy': 'require-corp'", false)
51
+ .option('--header <header>', 'extra headers to include eg --header=Content-Language:de-DE', parseHeader, {})
52
+ .option('--gzip', 'serve .gz files if they exist', false)
53
+ .option('--brotli', 'serve .br files if they exist', false)
54
+ .option('--no-robots', 'do not serve a robots.txt if one does not exist', true)
55
+ .option('--hidden', 'show hidden dotfiles', false)
56
+ .option('--username <username>', 'username for basic auth')
57
+ .option('--password <password>', 'password for basic auth')
58
+ .option('-S, --ssl', 'enable https (will use fake cert if not specified)', false)
59
+ .option('-C, --cert <cert>', 'Path to ssl cert file')
60
+ .option('-K, --key <key>', 'Path to ssl key file')
61
+ .action(main);
62
+
63
+ program.showHelpAfterError('(add --help for additional information)');
64
+ program.parse();
65
+
66
+ function main(pathToServe, args) {
67
+ args.headers = args.header;
68
+ delete args.header;
69
+
70
+ const fs = require('fs');
71
+ const path = require('path');
72
+ const {QrCode, Ecc} = require('../lib/qrcodegen');
73
+ const hosts = [];
74
+
75
+ function genQRCode(s) {
76
+ const qr = QrCode.encodeText(s, Ecc.MEDIUM);
77
+ const size = qr.size + 2;
78
+
79
+ const lines = [];
80
+ for (let y = -2; y < size; ++y) {
81
+ const line = [];
82
+ for (let x = -2; x < size; ++x) {
83
+ line.push(c[qr.getModule(x, y) ? 'bgBlack' : 'bgWhite'](' '));
84
+ }
85
+ lines.push(line.join(''));
86
+ }
87
+ return lines.join('\n');
117
88
  }
118
- }
119
89
 
120
- process.stdin.destroy(); // this allows control-c to not print "Terminate Batch?"
121
- process.title = `servez ${root.split(/\\|\//g).slice(-3).join(path.sep)}`;
122
-
123
- const commands = {
124
- log(args) {
125
- console.log(...args);
126
- },
127
- error(args) {
128
- console.error(c.red(args.join(' ')));
129
- },
130
- host(args) {
131
- const localRE = /\D0\.0\.0\.0.\D|\D127\.0\.0\.|\Wlocalhost\W/
132
- const [data] = args;
133
- const {root} = data;
134
- if (!localRE.test(root)) {
135
- hosts.push(root);
90
+ const root = path.resolve(pathToServe || process.cwd());
91
+ try {
92
+ const stat = fs.statSync(root);
93
+ if (!stat.isDirectory()) {
94
+ log.error(`'${root}' is not a directory`);
95
+ process.exit(1); // eslint-disable-line
136
96
  }
137
- },
138
- start(data) {
139
- if (args.qr) {
140
- for (const host of hosts) {
141
- log.info(`--------------\nQR code for: ${host}`);
142
- log.info(genQRCode(host));
143
- log.info('');
144
- }
97
+ } catch (e) {
98
+ if (e.code === 'ENOENT') {
99
+ log.warn(c.bold.yellow(`!!!!!!!!!!!!!!!\n\n WARNING: '${root}' does not exist!\n\n!!!!!!!!!!!!!!!`));
100
+ } else {
101
+ log.error(e, e.stack);
102
+ process.exit(1); // eslint-disable-line
145
103
  }
146
- log.info('press CTRL-C to stop the server.');
147
- },
148
- };
149
-
150
- const {Worker} = require('worker_threads');
151
- const worker = new Worker(path.join(__dirname, '..', 'src', 'server-worker.js'), {
152
- workerData: {
153
- root,
154
- args,
155
- useColors: colorSupport.hasBasic,
156
- },
157
- });
158
- worker.on('message', (msg) => {
159
- const cmd = msg.cmd;
160
- const fn = commands[cmd];
161
- if (!fn) {
162
- throw new Error(`unknown cmd: ${cmd}`);
163
104
  }
164
- fn(msg.data);
165
- });
166
105
 
167
- process.on('SIGINT', function () {
168
- console.log(c.red('servez stopped.'));
169
- process.exit(0);
170
- });
106
+ process.stdin.destroy(); // this allows control-c to not print "Terminate Batch?"
107
+ process.title = `servez ${root.split(/\\|\//g).slice(-3).join(path.sep)}`;
108
+
109
+ const commands = {
110
+ log(args) {
111
+ console.log(...args);
112
+ },
113
+ error(args) {
114
+ console.error(c.red(args.join(' ')));
115
+ },
116
+ host(args) {
117
+ const localRE = /\D0\.0\.0\.0.\D|\D127\.0\.0\.|\Wlocalhost\W/
118
+ const [data] = args;
119
+ const {root} = data;
120
+ if (!localRE.test(root)) {
121
+ hosts.push(root);
122
+ }
123
+ },
124
+ start(data) {
125
+ if (args.qr) {
126
+ for (const host of hosts) {
127
+ log.info(`--------------\nQR code for: ${host}`);
128
+ log.info(genQRCode(host));
129
+ log.info('');
130
+ }
131
+ }
132
+ log.info('press CTRL-C to stop the server.');
133
+ },
134
+ };
135
+
136
+ const {Worker} = require('worker_threads');
137
+ const worker = new Worker(path.join(__dirname, '..', 'src', 'server-worker.js'), {
138
+ workerData: {
139
+ root,
140
+ args,
141
+ useColors: colorSupport.hasBasic,
142
+ },
143
+ });
144
+ worker.on('message', (msg) => {
145
+ const cmd = msg.cmd;
146
+ const fn = commands[cmd];
147
+ if (!fn) {
148
+ throw new Error(`unknown cmd: ${cmd}`);
149
+ }
150
+ fn(msg.data);
151
+ });
171
152
 
153
+ process.on('SIGINT', function () {
154
+ console.log(c.red('servez stopped.'));
155
+ process.exit(0);
156
+ });
157
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "servez",
3
- "version": "1.14.1",
3
+ "version": "2.0.0",
4
4
  "description": "A simple command line server to replace http-server",
5
5
  "scripts": {
6
6
  "start": "node ./bin/servez"
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "ansi-colors": "^4.1.1",
27
27
  "color-support": "^1.1.3",
28
- "optionator": "^0.8.2",
28
+ "commander": "^11.0.0",
29
29
  "servez-lib": "^2.6.0"
30
30
  },
31
31
  "bin": {