fauxnix-cli 0.2.1 → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  import { wordToString } from '../ast.js';
2
2
  import { parseWords, psStr } from '../registry.js';
3
- import { exprOfWord, operandExpr } from '../translator.js';
3
+ import { argListExpr, exprOfWord, operandExpr } from '../translator.js';
4
4
  /* ------------------------------------------------------------------ */
5
5
  /* Shared PS snippets */
6
6
  /* ------------------------------------------------------------------ */
@@ -45,9 +45,7 @@ const PS_HSIZE_FN = [
45
45
  ].join('\n');
46
46
  /** Operand Words → PS array expression of string exprs. */
47
47
  function psArray(words, fn = operandExpr) {
48
- if (words.length === 0)
49
- return '@()';
50
- return '@(' + words.map(fn).join(', ') + ')';
48
+ return argListExpr(words, fn);
51
49
  }
52
50
  /* ------------------------------------------------------------------ */
53
51
  /* ls */
@@ -63,7 +61,7 @@ const ls = (args) => {
63
61
  const sortByTime = flags.has('t');
64
62
  const sortBySize = flags.has('S');
65
63
  const reverse = flags.has('r');
66
- const targets = operandWords.length ? operandWords.map((w) => operandExpr(w)) : ["'.'"];
64
+ const targets = operandWords.length ? argListExpr(operandWords) : "@('.')";
67
65
  return [
68
66
  PS_GLOB_FN,
69
67
  PS_FTIME_FN,
@@ -84,7 +82,7 @@ const ls = (args) => {
84
82
  ' }',
85
83
  ' return $n',
86
84
  '}',
87
- '$fx_targets = @(' + targets.join(', ') + ')',
85
+ '$fx_targets = ' + targets,
88
86
  '$fx_all = @()',
89
87
  'foreach ($fx_t in $fx_targets) {',
90
88
  ' foreach ($fx_g in (fx-glob $fx_t)) {',
@@ -126,12 +124,10 @@ const cp = (args) => {
126
124
  const { flags, longs, operandWords } = parseWords(args);
127
125
  const recurse = flags.has('r') || flags.has('R') || longs.has('--recursive');
128
126
  const verbose = flags.has('v') || longs.has('--verbose');
129
- const srcs = psArray(operandWords.slice(0, -1));
130
- const dst = operandWords.length >= 2 ? operandExpr(operandWords[operandWords.length - 1]) : "''";
131
127
  return [
132
128
  PS_GLOB_FN,
133
- '$fx_srcs = ' + srcs,
134
- '$fx_dst = ' + dst,
129
+ '$fx_all = ' + argListExpr(operandWords),
130
+ "if ($fx_all.Count -lt 2) { $fx_srcs = @(); $fx_dst = '' } else { $fx_dst = [string]$fx_all[$fx_all.Count - 1]; $fx_srcs = @($fx_all[0..($fx_all.Count - 2)]) }",
135
131
  "if ($fx_srcs.Count -eq 0) { [Console]::Error.WriteLine('cp: missing file operand'); $script:fx_exit = 1 }",
136
132
  "elseif ($fx_dst -eq '') { [Console]::Error.WriteLine('cp: missing destination file operand'); $script:fx_exit = 1 }",
137
133
  'else {',
@@ -154,12 +150,10 @@ const cp = (args) => {
154
150
  const mv = (args) => {
155
151
  const { flags, longs, operandWords } = parseWords(args);
156
152
  const verbose = flags.has('v') || longs.has('--verbose');
157
- const srcs = psArray(operandWords.slice(0, -1));
158
- const dst = operandWords.length >= 2 ? operandExpr(operandWords[operandWords.length - 1]) : "''";
159
153
  return [
160
154
  PS_GLOB_FN,
161
- '$fx_srcs = ' + srcs,
162
- '$fx_dst = ' + dst,
155
+ '$fx_all = ' + argListExpr(operandWords),
156
+ "if ($fx_all.Count -lt 2) { $fx_srcs = @(); $fx_dst = '' } else { $fx_dst = [string]$fx_all[$fx_all.Count - 1]; $fx_srcs = @($fx_all[0..($fx_all.Count - 2)]) }",
163
157
  "if ($fx_srcs.Count -eq 0) { [Console]::Error.WriteLine('mv: missing file operand'); $script:fx_exit = 1 }",
164
158
  "elseif ($fx_dst -eq '') { [Console]::Error.WriteLine('mv: missing destination file operand'); $script:fx_exit = 1 }",
165
159
  'elseif ($fx_srcs.Count -gt 1 -and -not (Test-Path -LiteralPath $fx_dst -PathType Container)) { [Console]::Error.WriteLine("mv: target \'" + $fx_dst + "\' is not a directory"); $script:fx_exit = 1 }',
@@ -274,13 +268,11 @@ const mktemp = (args) => {
274
268
  const ln = (args) => {
275
269
  const { flags, operandWords } = parseWords(args);
276
270
  const sym = flags.has('s');
277
- const src = operandWords.length >= 2 ? operandExpr(operandWords[0]) : "''";
278
- const dst = operandWords.length >= 2 ? operandExpr(operandWords[1]) : "''";
279
271
  const kind = sym ? 'SymbolicLink' : 'HardLink';
280
272
  const label = sym ? 'symbolic link' : 'hard link';
281
273
  return [
282
- '$fx_src = ' + src,
283
- '$fx_dst = ' + dst,
274
+ '$fx_ops = ' + argListExpr(operandWords),
275
+ "if ($fx_ops.Count -lt 2) { $fx_src = ''; $fx_dst = '' } else { $fx_src = [string]$fx_ops[0]; $fx_dst = [string]$fx_ops[1] }",
284
276
  "if ($fx_src -eq '' -or $fx_dst -eq '') { [Console]::Error.WriteLine('ln: missing file operand'); $script:fx_exit = 1 }",
285
277
  'else {',
286
278
  ' if (Test-Path -LiteralPath $fx_dst -PathType Container) { $fx_dst = Join-Path $fx_dst (Split-Path $fx_src -Leaf) }',
@@ -321,29 +313,28 @@ const realpath = (args) => {
321
313
  /* basename / dirname */
322
314
  /* ------------------------------------------------------------------ */
323
315
  const basename = (args) => {
324
- if (args.length === 2) {
325
- return [
326
- '$fx_p = ' + exprOfWord(args[0]),
327
- '$fx_sfx = ' + exprOfWord(args[1]),
328
- "$fx_n = [IO.Path]::GetFileName(($fx_p.TrimEnd('/')).TrimEnd('\\'))",
329
- "if ($fx_n -eq '') { $fx_n = '/' }",
330
- "if ($fx_sfx -ne '' -and $fx_n.EndsWith($fx_sfx) -and ($fx_n.Length -gt $fx_sfx.Length)) { $fx_n = $fx_n.Substring(0, $fx_n.Length - $fx_sfx.Length) }",
331
- '$fx_n',
332
- ].join('\n');
333
- }
334
316
  return [
335
- '$fx_ps = @(' + args.map(exprOfWord).join(', ') + ')',
317
+ '$fx_ps = ' + argListExpr(args, exprOfWord),
336
318
  "if ($fx_ps.Count -eq 0) { [Console]::Error.WriteLine('basename: missing operand'); $script:fx_exit = 1 }",
337
- 'foreach ($fx_p in $fx_ps) {',
319
+ 'elseif ($fx_ps.Count -eq 2) {',
320
+ ' $fx_p = [string]$fx_ps[0]',
321
+ ' $fx_sfx = [string]$fx_ps[1]',
338
322
  " $fx_n = [IO.Path]::GetFileName(($fx_p.TrimEnd('/')).TrimEnd('\\'))",
339
323
  " if ($fx_n -eq '') { $fx_n = '/' }",
324
+ " if ($fx_sfx -ne '' -and $fx_n.EndsWith($fx_sfx) -and ($fx_n.Length -gt $fx_sfx.Length)) { $fx_n = $fx_n.Substring(0, $fx_n.Length - $fx_sfx.Length) }",
340
325
  ' $fx_n',
326
+ '} else {',
327
+ ' foreach ($fx_p in $fx_ps) {',
328
+ " $fx_n = [IO.Path]::GetFileName(($fx_p.TrimEnd('/')).TrimEnd('\\'))",
329
+ " if ($fx_n -eq '') { $fx_n = '/' }",
330
+ ' $fx_n',
331
+ ' }',
341
332
  '}',
342
333
  ].join('\n');
343
334
  };
344
335
  const dirname = (args) => {
345
336
  return [
346
- '$fx_ps = @(' + args.map(exprOfWord).join(', ') + ')',
337
+ '$fx_ps = ' + argListExpr(args, exprOfWord),
347
338
  "if ($fx_ps.Count -eq 0) { [Console]::Error.WriteLine('dirname: missing operand'); $script:fx_exit = 1 }",
348
339
  'foreach ($fx_p in $fx_ps) {',
349
340
  " $fx_n = ($fx_p.TrimEnd('/')).TrimEnd('\\')",
@@ -428,7 +419,7 @@ const du = (args) => {
428
419
  const { flags, longs, operandWords } = parseWords(args, [], ['--max-depth']);
429
420
  const sum = flags.has('s') || longs.has('--summarize');
430
421
  const human = flags.has('h') || longs.has('--human-readable');
431
- const targets = operandWords.length ? operandWords.map((w) => operandExpr(w)) : ["'.'"];
422
+ const targets = operandWords.length ? argListExpr(operandWords) : "@('.')";
432
423
  return [
433
424
  PS_HSIZE_FN,
434
425
  'function fx-size($p) {',
@@ -436,7 +427,7 @@ const du = (args) => {
436
427
  ' Get-ChildItem -LiteralPath $p -Recurse -Force -File -ErrorAction SilentlyContinue | ForEach-Object { $t += $_.Length }',
437
428
  ' return [math]::Ceiling($t / 1KB)',
438
429
  '}',
439
- '$fx_ts = @(' + targets.join(', ') + ')',
430
+ '$fx_ts = ' + targets,
440
431
  'foreach ($fx_t in $fx_ts) {',
441
432
  ' if (-not (Test-Path -LiteralPath $fx_t)) { [Console]::Error.WriteLine("du: cannot access \'" + $fx_t + "\': No such file or directory"); $script:fx_exit = 1; continue }',
442
433
  ' if (' + (sum ? '$true' : '$false') + ') {',
@@ -500,7 +491,7 @@ const find = (args) => {
500
491
  const sizeExpr = extractValue(preds, ['-size']);
501
492
  const mtimeExpr = extractValue(preds, ['-mtime']);
502
493
  const wantDelete = preds.includes('-delete');
503
- const paths = pathWords.length ? pathWords.map((w) => operandExpr(w)) : ["'.'"];
494
+ const paths = pathWords.length ? argListExpr(pathWords) : "@('.')";
504
495
  const conditions = [];
505
496
  if (namePat !== null)
506
497
  conditions.push("($fx_i.Name -like '" + likeOf(namePat) + "')");
@@ -516,7 +507,7 @@ const find = (args) => {
516
507
  const sizeCond = sizeOf(sizeExpr);
517
508
  const mtimeCond = mtimeOf(mtimeExpr);
518
509
  return [
519
- '$fx_paths = @(' + paths.join(', ') + ')',
510
+ '$fx_paths = ' + paths,
520
511
  'foreach ($fx_p in $fx_paths) {',
521
512
  ' if (-not (Test-Path -LiteralPath $fx_p)) { [Console]::Error.WriteLine("find: \'" + $fx_p + "\': No such file or directory"); $script:fx_exit = 1; continue }',
522
513
  ' $fx_root = (Get-Item -LiteralPath $fx_p -Force).FullName',
@@ -632,13 +623,11 @@ const diff = (args) => {
632
623
  const unified = flags.has('u') || flags.has('U');
633
624
  const brief = flags.has('q') || flags.has('brief');
634
625
  void unified;
635
- const a = operandWords.length > 0 ? operandExpr(operandWords[0]) : "''";
636
- const b = operandWords.length > 1 ? operandExpr(operandWords[1]) : "''";
637
626
  return [
638
627
  PS_READTEXT_FN,
639
628
  'function fx-dr($x, $y) { if ($x -eq $y) { return [string]$x } else { return ([string]$x) + \',\' + ([string]$y) } }',
640
- '$fx_a = ' + a,
641
- '$fx_b = ' + b,
629
+ '$fx_ops = ' + argListExpr(operandWords),
630
+ "if ($fx_ops.Count -lt 2) { $fx_a = ''; $fx_b = '' } else { $fx_a = [string]$fx_ops[0]; $fx_b = [string]$fx_ops[1] }",
642
631
  "if ($fx_a -eq '' -or $fx_b -eq '') { [Console]::Error.WriteLine('diff: missing operand'); $script:fx_exit = 2 }",
643
632
  'elseif (-not (Test-Path -LiteralPath $fx_a)) { [Console]::Error.WriteLine("diff: " + $fx_a + ": No such file or directory"); $script:fx_exit = 2 }',
644
633
  'elseif (-not (Test-Path -LiteralPath $fx_b)) { [Console]::Error.WriteLine("diff: " + $fx_b + ": No such file or directory"); $script:fx_exit = 2 }',
@@ -1,6 +1,6 @@
1
1
  import { wordToString } from '../ast.js';
2
2
  import { parseWords, psErr, psStr } from '../registry.js';
3
- import { exprOfWord, literalOfWord, operandExpr } from '../translator.js';
3
+ import { argListExpr, exprOfWord, literalOfWord, operandExpr } from '../translator.js';
4
4
  /* ------------------------------------------------------------------ */
5
5
  /* Shared PS snippets */
6
6
  /* ------------------------------------------------------------------ */
@@ -94,7 +94,7 @@ const curl = (args) => {
94
94
  // refuses private/loopback URLs before the process is even started.
95
95
  return [
96
96
  PS_NETGUARD_FNS,
97
- "$fx_args = @(" + args.map(exprOfWord).join(', ') + ')',
97
+ '$fx_args = ' + argListExpr(args, exprOfWord),
98
98
  '$fx_bad = $false',
99
99
  "foreach ($fx_a in $fx_args) { if (fx-netguard 'curl' $fx_a) { $fx_bad = $true } }",
100
100
  'if ($fx_bad) { $script:fx_exit = 1 }',
@@ -212,11 +212,11 @@ function mapWgetArgs(args) {
212
212
  return { margs, sawOutput, urls };
213
213
  }
214
214
  const wget = (args) => {
215
- const orig = args.map(exprOfWord);
215
+ const orig = args.map((w) => exprOfWord(w));
216
216
  const mapped = mapWgetArgs(args);
217
217
  return [
218
218
  PS_NETGUARD_FNS,
219
- '$fx_args = @(' + orig.join(', ') + ')',
219
+ '$fx_args = ' + argListExpr(args, exprOfWord),
220
220
  '$fx_margs = @(' + mapped.margs.join(', ') + ')',
221
221
  '$fx_bad = $false',
222
222
  "foreach ($fx_a in $fx_args) { if (fx-netguard 'wget' $fx_a) { $fx_bad = $true } }",
@@ -456,7 +456,10 @@ const ifconfig = (args) => {
456
456
  /* ------------------------------------------------------------------ */
457
457
  /* nslookup / dig / host */
458
458
  /* ------------------------------------------------------------------ */
459
- const nslookup = (args) => nativeCall('nslookup.exe', args.map(exprOfWord).join(', '));
459
+ const nslookup = (args) => [
460
+ '$fx_args = ' + argListExpr(args, exprOfWord),
461
+ nativeCall('nslookup.exe', '$fx_args'),
462
+ ].join('\n');
460
463
  const dig = (args) => {
461
464
  const raw = args.map(wordToString);
462
465
  let short = false;