Skip to content

WIP Console view #310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: hook-refactor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { lifecycle } from "vscode-lib";
import { CompiledCodeModel } from "../../../../../models/CompiledCodeModel";
import { getTypeCellResolver } from "../../../resolver/resolver";
import { ModelOutput } from "../../../components/ModelOutput";

import { ModelReceiver } from "./ModelReceiver";
import type { VisualizersByPath } from "../../../../extensions/visualizer/VisualizerExtension";
import { IframeBridgeMethods } from "./IframeBridgeMethods";
Expand Down
1 change: 1 addition & 0 deletions packages/engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"es-module-shims": "1.4.3",
"lodash": "^4.17.21",
"logdown": "^3.3.1",
"mobx": "^6.2.0",
"react": "^17.0.2",
"vscode-lib": "^0.1.2"
Expand Down
12 changes: 7 additions & 5 deletions packages/engine/src/CellEvaluator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TypeCellContext } from "./context";
import { ConsolePayload } from "./Engine";
import { ModuleExecution, runModule } from "./executor";
import { HookExecution } from "./HookExecution";
import { createExecutionScope, getModulesFromTypeCellCode } from "./modules";
Expand All @@ -10,7 +11,8 @@ export function createCellEvaluator(
typecellContext: TypeCellContext<any>,
resolveImport: (module: string) => Promise<any>,
setAndWatchOutput = true,
onOutputChanged: (output: any) => void,
onOutputEvent: (output: any) => void,
onConsoleEvent: (console: ConsolePayload) => void,
beforeExecuting: () => void
) {
function onExecuted(exports: any) {
Expand Down Expand Up @@ -42,15 +44,15 @@ export function createCellEvaluator(
});
}
}
onOutputChanged(newExports);
onOutputEvent(newExports);
}

function onError(error: any) {
// log.warn("cellEvaluator onError", cell.path, error);
onOutputChanged(error);
onOutputEvent(error);
}

const hookExecution = new HookExecution();
const hookExecution = new HookExecution(onConsoleEvent);
const executionScope = createExecutionScope(
typecellContext,
hookExecution.scopeHooks
Expand Down Expand Up @@ -84,7 +86,7 @@ export function createCellEvaluator(
} catch (e) {
console.error(e);
// log.warn("cellEvaluator error evaluating", cell.path, e);
onOutputChanged(e);
onOutputEvent(e);
}
}

Expand Down
215 changes: 155 additions & 60 deletions packages/engine/src/Engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,92 +7,187 @@ import {
toAMDFormat,
waitTillEvent,
} from "./tests/util/helpers";

const getModel1 = () =>
buildMockedModel(
"model1",
`let x = 4;
import { CodeModelMock } from "./tests/util/CodeModelMock";

describe("engine class execution", function () {
describe("basic model execution", () => {
const getModel1 = () =>
buildMockedModel(
"model1",
`let x = 4;
let y = 6;
let sum = x + y;
exports.sum = sum;
exports.default = sum;`
);
);

const getModel2 = () =>
buildMockedModel("model2", `exports.default = $.sum - 5;`);
const getModel2 = () =>
buildMockedModel("model2", `exports.default = $.sum - 5;`);

describe("engine class", () => {
it("should execute a single model", async () => {
const engine = new Engine<CodeModel>(importResolver);
engine.registerModel(getModel1());
it("should execute a single model", async () => {
const engine = new Engine<CodeModel>(importResolver);
engine.registerModel(getModel1());

const { model, output } = await event.Event.toPromise(engine.onOutput);
const { model, output } = await event.Event.toPromise(engine.onOutput);

expect(model.path).toBe("model1");
expect(output.sum).toBe(10);
expect(output.default).toBe(10);
});
expect(model.path).toBe("model1");
expect(output.sum).toBe(10);
expect(output.default).toBe(10);
});

it("should read exported variables from other models", async () => {
const engine = new Engine<CodeModel>(importResolver);
engine.registerModel(getModel1());
await event.Event.toPromise(engine.onOutput);
it("should read exported variables from other models", async () => {
const engine = new Engine<CodeModel>(importResolver);
engine.registerModel(getModel1());
await event.Event.toPromise(engine.onOutput);

engine.registerModel(getModel2());
const { model, output } = await event.Event.toPromise(engine.onOutput);
engine.registerModel(getModel2());
const { model, output } = await event.Event.toPromise(engine.onOutput);

expect(model.path).toBe("model2");
expect(output.default).toBe(5);
});
expect(model.path).toBe("model2");
expect(output.default).toBe(5);
});

it("should re-evaluate code after change", async () => {
const engine = new Engine<CodeModel>(importResolver);
const model1 = getModel1();
it("should re-evaluate code after change", async () => {
const engine = new Engine<CodeModel>(importResolver);
const model1 = getModel1();

engine.registerModel(model1);
await event.Event.toPromise(engine.onOutput);
engine.registerModel(model1);
await event.Event.toPromise(engine.onOutput);

model1.updateCode(
toAMDFormat(`let x = 0;
model1.updateCode(
toAMDFormat(`let x = 0;
let y = 6;
let sum = x + y;
exports.sum = sum;
exports.default = sum;`)
);
);

const { output } = await event.Event.toPromise(engine.onOutput);
const { output } = await event.Event.toPromise(engine.onOutput);

expect(output.sum).toBe(6);
expect(output.default).toBe(6);
});
expect(output.sum).toBe(6);
expect(output.default).toBe(6);
});

it("should re-evaluate other models when global variable changes", async () => {
const engine = new Engine<CodeModel>(importResolver);
// TODO: Expected 4 events. Figure out why model 2 re-evaluates.
const eventsPromise = waitTillEvent(engine.onOutput, 5);
const model1 = getModel1();
const model2 = getModel2();
it("should re-evaluate other models when global variable changes", async () => {
const engine = new Engine<CodeModel>(importResolver);
// TODO: Expected 4 events. Figure out why model 2 re-evaluates.
const eventsPromise = waitTillEvent(engine.onOutput, 5);
const model1 = getModel1();
const model2 = getModel2();

engine.registerModel(model1);
engine.registerModel(model2);
engine.registerModel(model1);
engine.registerModel(model2);

model1.updateCode(
toAMDFormat(`let x = 0;
model1.updateCode(
toAMDFormat(`let x = 0;
let y = 6;
let sum = x + y;
exports.sum = sum;
exports.default = sum;`)
);

const events = await eventsPromise;
const eventsSnapshot = events.map((event) => ({
path: event.model.path,
output: event.output,
}));
const finalEvent = eventsSnapshot[eventsSnapshot.length - 1];

expect(finalEvent.path).toBe("model2");
expect(finalEvent.output.default).toBe(1);
expect(eventsSnapshot).toMatchSnapshot();
);

const events = await eventsPromise;
const eventsSnapshot = events.map((event) => ({
path: event.model.path,
output: event.output,
}));
const finalEvent = eventsSnapshot[eventsSnapshot.length - 1];

expect(finalEvent.path).toBe("model2");
expect(finalEvent.output.default).toBe(1);
expect(eventsSnapshot).toMatchSnapshot();
});
});

describe("console messages", () => {
const getModel1 = () => buildMockedModel("model1", `console.log('hi!');`);
const getModel2 = () =>
buildMockedModel(
"model2",
`console.info('info'); console.warn('warn'); console.error('error');`
);
const getModel3 = () =>
buildMockedModel(
"model3",
`console.log('before');
await new Promise((resolve)=> {
setTimeout(()=> {
resolve();
}, 1)
});
console.log('after');`
);
const getModel4 = () =>
new CodeModelMock(
"javascript",
"model4",
`define(["require", "exports", "logdown"], function(require, exports, logdown) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

let logger = logdown("logger 1");
logger.state.isEnabled = true;
logger.log("message 1");

setTimeout(() => {
logger.state.isEnabled = true;
logger.log("message 2");
}, 1);
});`
);

it("should capture console.log message", async () => {
const engine = new Engine<CodeModel>(importResolver);
const eventsPromise = waitTillEvent(engine.onConsole, 1);
const model1 = getModel1();

engine.registerModel(model1);

const consoleEvents = await eventsPromise;

expect(consoleEvents[0].payload.level).toBe("info");
expect(consoleEvents[0].payload.message[0]).toBe("hi!");
});

it("should capture console.warn/info/error messages", async () => {
const engine = new Engine<CodeModel>(importResolver);
const eventsPromise = waitTillEvent(engine.onConsole, 3);
const model2 = getModel2();

engine.registerModel(model2);

const events = await eventsPromise;
const eventsSnapshot = events.map((event) => {
return {
path: event.model.path,
console: event.payload,
};
});
expect(eventsSnapshot).toMatchSnapshot();
});

it("should capture console.log messages after async", async () => {
const engine = new Engine<CodeModel>(importResolver);
const eventsPromise = waitTillEvent(engine.onConsole, 2);
const model3 = getModel3();

engine.registerModel(model3);

const events = await eventsPromise;
expect(events[0].payload.message[0]).toBe("before");
expect(events[1].payload.message[0]).toBe("after");
});

it("should capture console.log messages from library (sync only)", async () => {
const engine = new Engine<CodeModel>(importResolver);
const eventsPromise = waitTillEvent(engine.onConsole, 2);
const model4 = getModel4();

engine.registerModel(model4);

const events = await eventsPromise;
expect(events[0].payload.message[1]).toBe("message 1");
expect(events[1].payload.message[1]).toBe("message 2");
});
});
});
Loading