Skip to content

Commit

Permalink
feat(evalCodeBlock): handle JS; closes #40
Browse files Browse the repository at this point in the history
  • Loading branch information
pskfyi authored and AustinArey committed Jun 10, 2023
1 parent c527586 commit 72de5d8
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 27 deletions.
12 changes: 11 additions & 1 deletion md/codeBlock/eval.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as fenced from "./fenced.ts";
import * as indented from "./indented.ts";

const throws = "throw new Error()";
const logs = 'console.log("logged")';

describe("evaluate", () => {
test("no lang", () => {
Expand All @@ -32,7 +33,7 @@ describe("evaluate", () => {

test("unknown lang", () =>
void assertRejects(
async () => void await evaluate(fenced.create(throws, { lang: "js" })),
async () => void await evaluate(fenced.create(throws, { lang: "ZZZ" })),
UnknownLanguageError,
));

Expand All @@ -44,6 +45,15 @@ describe("evaluate", () => {
assertEquals(result.stdout, "");
assert(result.stderr.includes("throw new Error()"));
});

test("javascript", async () => {
assertEquals(await evaluate(fenced.create(logs, { lang: "js" })), {
success: true,
code: 0,
stderr: "",
stdout: "logged",
});
});
});

describe("evaluateAll", () => {
Expand Down
50 changes: 25 additions & 25 deletions md/codeBlock/eval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ import { parse as parseCodeBlock } from "./parse.ts";
import { findAll as findAllCodeBlocks } from "./findAll.ts";
import type { CmdResult } from "../../cli/cmd.ts";
import { evaluate as evalTS } from "../../ts/evaluate.ts";
import { evaluate as evalJS } from "../../js/evaluate.ts";
import type { CodeBlockDetails } from "./types.ts";
import type { TextLocation } from "../../string/Text.ts";

const LANGS = {
ts: evalTS,
js: evalJS,
};

function _isRegistered(lang: string): lang is keyof typeof LANGS {
return lang in LANGS;
}

export class IndentedCodeBlockError extends Error {
constructor() {
super("Indented code blocks are not supported");
Expand All @@ -30,33 +40,25 @@ export type EvaluateOptions = {
replace?: [string | RegExp, string][];
};

function _getCode(
details: CodeBlockDetails,
replace: Exclude<EvaluateOptions["replace"], undefined>,
): string {
/** Evaluate a TS or JS code block. Uses `ts/evaluate` and `js/evaluate`. */
export async function evaluate(
codeBlock: string | CodeBlockDetails,
{ replace = [] }: EvaluateOptions = {},
): Promise<CmdResult> {
const details = typeof codeBlock === "string"
? parseCodeBlock(codeBlock)
: codeBlock;

if (details.type === "indented") throw new IndentedCodeBlockError();

const { lang, code } = details;
const lang = details.lang;
let code = details.code;

if (!lang) throw new NoLanguageError();
if (!_isRegistered(lang)) throw new UnknownLanguageError(lang);
for (const [before, after] of replace) code = code.replaceAll(before, after);

if (lang !== "ts") throw new UnknownLanguageError(lang);

return replace.reduce(
(code, [search, replace]) => code.replaceAll(search, replace),
code,
);
}

/** Passes a code block to `deno eval`. */
export async function evaluate(
codeBlock: string,
{ replace = [] }: EvaluateOptions = {},
): Promise<CmdResult> {
const details = parseCodeBlock(codeBlock);
const code = _getCode(details, replace);

return await evalTS(code);
return await LANGS[lang](code);
}

export type EvaluateAllResult = [
Expand All @@ -80,9 +82,7 @@ export async function evaluateAll(

for (const [details, location] of findAllCodeBlocks(markdown)) {
try {
const code = _getCode(details, replace);

results.push([details, location, await evalTS(code)]);
results.push([details, location, await evaluate(details, { replace })]);
} catch (error) {
if (
error instanceof IndentedCodeBlockError ||
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ codeBlock.evaluate(

### `script/evalCodeBlocks`

For a markdown file, execute each TS code block in the file. Useful for checking imports and examples in a readme.
For a markdown file, execute each TS or JS code block in the file. Useful for checking imports and examples in a readme.

```ts
import { evalCodeBlocks } from "https://deno.land/x/handy/md/script/evalCodeBlocks.ts";
Expand Down

0 comments on commit 72de5d8

Please sign in to comment.