2020-09-21 08:26:41 -04:00
|
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
2020-01-30 21:02:14 -05:00
|
|
|
import { parse } from "../flags/mod.ts";
|
2020-02-17 19:51:13 -05:00
|
|
|
import { readStringDelim } from "../io/bufio.ts";
|
2020-01-30 21:02:14 -05:00
|
|
|
|
|
|
|
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction.
|
2020-03-28 13:03:49 -04:00
|
|
|
const AsyncFunction = Object.getPrototypeOf(async function (): Promise<void> {})
|
2020-01-30 21:02:14 -05:00
|
|
|
.constructor;
|
|
|
|
|
|
|
|
const HELP_MSG = `xeval
|
|
|
|
|
2020-02-17 19:51:13 -05:00
|
|
|
Run a script for each new-line or otherwise delimited chunk of standard input.
|
2020-01-30 21:02:14 -05:00
|
|
|
|
|
|
|
Print all the usernames in /etc/passwd:
|
2020-05-07 07:48:48 -04:00
|
|
|
cat /etc/passwd | deno run -A https://deno.land/std/examples/xeval.ts "a = $.split(':'); if (a) console.log(a[0])"
|
2020-01-30 21:02:14 -05:00
|
|
|
|
|
|
|
A complicated way to print the current git branch:
|
2020-05-07 07:48:48 -04:00
|
|
|
git branch | deno run -A https://deno.land/std/examples/xeval.ts -I 'line' "if (line.startsWith('*')) console.log(line.slice(2))"
|
2020-01-30 21:02:14 -05:00
|
|
|
|
|
|
|
Demonstrates breaking the input up by space delimiter instead of by lines:
|
2020-05-07 07:48:48 -04:00
|
|
|
cat LICENSE | deno run -A https://deno.land/std/examples/xeval.ts -d " " "if ($ === 'MIT') console.log('MIT licensed')",
|
2020-01-30 21:02:14 -05:00
|
|
|
|
|
|
|
USAGE:
|
2020-05-07 07:48:48 -04:00
|
|
|
deno run -A https://deno.land/std/examples/xeval.ts [OPTIONS] <code>
|
2020-01-30 21:02:14 -05:00
|
|
|
OPTIONS:
|
|
|
|
-d, --delim <delim> Set delimiter, defaults to newline
|
|
|
|
-I, --replvar <replvar> Set variable name to be used in eval, defaults to $
|
|
|
|
ARGS:
|
|
|
|
<code>`;
|
|
|
|
|
|
|
|
export type XevalFunc = (v: string) => void;
|
|
|
|
|
|
|
|
export interface XevalOptions {
|
|
|
|
delimiter?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
const DEFAULT_DELIMITER = "\n";
|
|
|
|
|
|
|
|
export async function xeval(
|
2020-06-12 15:23:38 -04:00
|
|
|
reader: Deno.Reader,
|
2020-01-30 21:02:14 -05:00
|
|
|
xevalFunc: XevalFunc,
|
2020-07-14 15:24:17 -04:00
|
|
|
{ delimiter = DEFAULT_DELIMITER }: XevalOptions = {},
|
2020-01-30 21:02:14 -05:00
|
|
|
): Promise<void> {
|
2020-02-17 19:51:13 -05:00
|
|
|
for await (const chunk of readStringDelim(reader, delimiter)) {
|
2020-01-30 21:02:14 -05:00
|
|
|
// Ignore empty chunks.
|
|
|
|
if (chunk.length > 0) {
|
|
|
|
await xevalFunc(chunk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function main(): Promise<void> {
|
2020-06-12 15:23:38 -04:00
|
|
|
const parsedArgs = parse(Deno.args, {
|
2020-01-30 21:02:14 -05:00
|
|
|
boolean: ["help"],
|
|
|
|
string: ["delim", "replvar"],
|
|
|
|
alias: {
|
|
|
|
delim: ["d"],
|
|
|
|
replvar: ["I"],
|
2020-03-28 13:03:49 -04:00
|
|
|
help: ["h"],
|
2020-01-30 21:02:14 -05:00
|
|
|
},
|
|
|
|
default: {
|
|
|
|
delim: DEFAULT_DELIMITER,
|
2020-03-28 13:03:49 -04:00
|
|
|
replvar: "$",
|
|
|
|
},
|
2020-01-30 21:02:14 -05:00
|
|
|
});
|
|
|
|
if (parsedArgs._.length != 1) {
|
|
|
|
console.error(HELP_MSG);
|
2020-02-17 19:51:13 -05:00
|
|
|
console.log(parsedArgs._);
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.exit(1);
|
2020-01-30 21:02:14 -05:00
|
|
|
}
|
|
|
|
if (parsedArgs.help) {
|
|
|
|
return console.log(HELP_MSG);
|
|
|
|
}
|
|
|
|
|
|
|
|
const delimiter = parsedArgs.delim;
|
|
|
|
const replVar = parsedArgs.replvar;
|
|
|
|
const code = parsedArgs._[0];
|
|
|
|
|
|
|
|
// new AsyncFunction()'s error message for this particular case isn't great.
|
|
|
|
if (!replVar.match(/^[_$A-z][_$A-z0-9]*$/)) {
|
|
|
|
console.error(`Bad replvar identifier: "${replVar}"`);
|
2020-06-12 15:23:38 -04:00
|
|
|
Deno.exit(1);
|
2020-01-30 21:02:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const xEvalFunc = new AsyncFunction(replVar, code);
|
|
|
|
|
2020-06-12 15:23:38 -04:00
|
|
|
await xeval(Deno.stdin, xEvalFunc, { delimiter });
|
2020-01-30 21:02:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (import.meta.main) {
|
|
|
|
main();
|
|
|
|
}
|