Getting the line number calculated correctly, as well as adding some basic test cases.

This commit is contained in:
mike12345567 2025-01-16 18:15:54 +00:00
parent 7efe88dfda
commit e6d536bcc8
5 changed files with 74 additions and 17 deletions

View File

@ -102,7 +102,7 @@
<!-- eslint-disable-next-line svelte/no-at-html-tags--> <!-- eslint-disable-next-line svelte/no-at-html-tags-->
<span>{@html logLine.log}</span> <span>{@html logLine.log}</span>
{#if logLine.line} {#if logLine.line}
<span style="color: var(--blue)">line {logLine.line}</span> <span style="color: var(--blue)">:{logLine.line}</span>
{/if} {/if}
</div> </div>
{/each} {/each}

View File

@ -1,4 +1,9 @@
import { atob, isBackendService, isJSAllowed } from "../utilities" import {
atob,
frontendWrapJS,
isBackendService,
isJSAllowed,
} from "../utilities"
import { LITERAL_MARKER } from "../helpers/constants" import { LITERAL_MARKER } from "../helpers/constants"
import { getJsHelperList } from "./list" import { getJsHelperList } from "./list"
import { iifeWrapper } from "../iife" import { iifeWrapper } from "../iife"
@ -117,7 +122,21 @@ export function processJS(handlebars: string, context: any) {
const logs: Log[] = [] const logs: Log[] = []
// logging only supported on frontend // logging only supported on frontend
if (!isBackendService()) { if (!isBackendService()) {
const log = (log: string) => logs.push({ log }) // this counts the lines in the wrapped JS *before* the user's code, so that we can minus it
const jsLineCount = frontendWrapJS(js).split(js)[0].split("\n").length
const log = (log: string) => {
// quick way to find out what line this is being called from
// its an anonymous function and we look for the overall length to find the
// line number we care about (from the users function)
// JS stack traces are in the format function:line:column
const lineNumber = new Error().stack?.match(
/<anonymous>:(\d+):\d+/
)?.[1]
logs.push({
log,
line: lineNumber ? parseInt(lineNumber) - jsLineCount : undefined,
})
}
sandboxContext.console = { sandboxContext.console = {
log: log, log: log,
info: log, info: log,

View File

@ -8,6 +8,7 @@ import {
FIND_ANY_HBS_REGEX, FIND_ANY_HBS_REGEX,
FIND_HBS_REGEX, FIND_HBS_REGEX,
findDoubleHbsInstances, findDoubleHbsInstances,
frontendWrapJS,
isBackendService, isBackendService,
prefixStrings, prefixStrings,
} from "./utilities" } from "./utilities"
@ -511,20 +512,7 @@ export function browserJSSetup() {
setJSRunner((js: string, context: Record<string, any>) => { setJSRunner((js: string, context: Record<string, any>) => {
createContext(context) createContext(context)
const wrappedJs = ` const wrappedJs = frontendWrapJS(js)
result = {
result: null,
error: null,
};
try {
result.result = ${js};
} catch (e) {
result.error = e;
}
result;
`
const result = runInNewContext(wrappedJs, context, { timeout: 1000 }) const result = runInNewContext(wrappedJs, context, { timeout: 1000 })
if (result.error) { if (result.error) {

View File

@ -86,3 +86,20 @@ export const prefixStrings = (
const regexPattern = new RegExp(`\\b(${escapedStrings.join("|")})\\b`, "g") const regexPattern = new RegExp(`\\b(${escapedStrings.join("|")})\\b`, "g")
return baseString.replace(regexPattern, `${prefix}$1`) return baseString.replace(regexPattern, `${prefix}$1`)
} }
export function frontendWrapJS(js: string) {
return `
result = {
result: null,
error: null,
};
try {
result.result = ${js};
} catch (e) {
result.error = e;
}
result;
`
}

View File

@ -0,0 +1,33 @@
import {
processStringWithLogsSync,
encodeJSBinding,
defaultJSSetup,
} from "../src/index"
const processJS = (js: string, context?: object) => {
return processStringWithLogsSync(encodeJSBinding(js), context)
}
describe("Javascript", () => {
beforeAll(() => {
defaultJSSetup()
})
describe("Test logging in JS bindings", () => {
it("should execute a simple expression", () => {
const output = processJS(
`console.log("hello");
console.log("world");
console.log("foo");
return "hello"`
)
expect(output.result).toBe("hello")
expect(output.logs[0].log).toBe("hello")
expect(output.logs[0].line).toBe(1)
expect(output.logs[1].log).toBe("world")
expect(output.logs[1].line).toBe(2)
expect(output.logs[2].log).toBe("foo")
expect(output.logs[2].line).toBe(3)
})
})
})