Skip to content

Commit

Permalink
added inlined source maps... vitest reports errors in proper places
Browse files Browse the repository at this point in the history
  • Loading branch information
azizghuloum committed Jan 2, 2025
1 parent e0d99ee commit a79a8fb
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 35 deletions.
2 changes: 1 addition & 1 deletion files.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async function compile_script(filename: string, test_name: string) {
function q(str: string): string {
return "`" + str + "`";
}
const prog = await pprint(result.loc, true);
const prog = await pprint(result.loc, { prettify: true });
const out =
`## ${q(test_name)}\n\n` +
`### Status: ${q(result.name)}\n\n` +
Expand Down
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.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
"lint": "eslint .",
"preview": "vite preview"
},
"overrides": {
"vite-plugin-node-polyfills": {
"vite": "^6.0.0"
}
},
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@codemirror/lang-javascript": "^6.2.2",
Expand All @@ -26,12 +31,14 @@
"commander": "^12.1.0",
"ignore": "^6.0.2",
"index-to-position": "^1.0.0",
"js-base64": "^3.7.7",
"json-stable-stringify": "^1.2.1",
"json-stringify-pretty-compact": "^4.0.0",
"prettier": "^3.4.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router-dom": "^7.1.1",
"source-map": "^0.7.4",
"typescript": "^5.5.3",
"zipper": "github:azizghuloum/zipper"
},
Expand Down
17 changes: 15 additions & 2 deletions src/library-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import stringify from "json-stringify-pretty-compact";
import { init_global_context } from "./global-module";
import { parse_dts } from "./parse-dts";

const cookie = "rewrite-ts-020";
const cookie = "rewrite-ts-021";

type module_state =
| { type: "initial" }
Expand Down Expand Up @@ -402,7 +402,20 @@ class RtsModule extends Module {
};
const code_path = this.get_generated_code_absolute_path();
await fs.mkdir(dirname(code_path), { recursive: true });
await fs.writeFile(code_path, await pprint(loc, false));
await fs.writeFile(
code_path,
await pprint(loc, {
prettify: false,
map: {
filename: basename(code_path),
resolve: async (cuid: string) => {
const mod = this.find_module_by_cid(cuid);
assert(mod !== undefined);
return relative(dirname(code_path), mod.path);
},
},
}),
);
await fs.writeFile(this.get_proxy_path(), proxy_code);
const mtime = Date.now();
await fs.writeFile(this.get_json_path(), stringify(json_content));
Expand Down
129 changes: 101 additions & 28 deletions src/pprint.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { AST, source } from "./ast";
import { llmap, llreverse, ll_to_array } from "./llhelpers";
import { Loc, STX } from "./syntax-structures";
import { list_tag } from "./tags";
import * as prettier from "prettier/standalone";
import * as prettier_ts from "prettier/plugins/typescript";
import * as prettier_estree from "prettier/plugins/estree";
import { SourceMapGenerator } from "source-map";
import { Base64 } from "js-base64";
import { assert } from "./assert";
import { AST } from "./ast";

type ns = string | ns[];
type n = { val: string; src: source | false };
type ns = n | ns[];

const children_need_semi: { [k in list_tag]?: boolean } = {
program: true,
Expand All @@ -19,29 +22,28 @@ function loc_to_ns(loc: Loc): ns {
/* */

function push_semi(ns: ns, semi: string): ns {
if (typeof ns === "string") {
return ns.endsWith(";") ? ns : [ns, semi];
} else {
if (Array.isArray(ns)) {
if (ns.length === 0) {
return semi;
return { val: semi, src: false };
} else {
return ns.map((x, i) => (i === ns.length - 1 ? push_semi(x, semi) : x));
}
} else {
return ns.val.endsWith(";") ? ns : [ns, { val: semi, src: false }];
}
}
type src = (AST | STX)["src"];
function wrap_src(src: src, content: string): ns {
if (!src) return content;
if (!src) return { val: content, src: false };
if (src.type !== "origin") return wrap_src(src.src, content);
// add src
return content;
return { val: content, src };
}
function stx_to_ns(stx: AST | STX, semi: boolean): ns {
if (stx.tag === "empty_statement") return [];
if (stx.tag === "slice")
return ll_to_array(stx.content)
.map((x) => stx_to_ns(x, true))
.filter((x) => x.length > 0);
.filter((x) => (Array.isArray(x) ? x.length > 0 : x.val.length > 0));
if (semi && stx.tag !== "other") return push_semi(stx_to_ns(stx, false), `;`);
switch (stx.type) {
case "list": {
Expand All @@ -59,7 +61,11 @@ function loc_to_ns(loc: Loc): ns {
case "other":
return wrap_src(stx.src, stx.content);
case "ERROR":
return ["!!!ERROR!!!", wrap_src(stx.src, stx.content), "!!!ERROR!!!"];
return [
wrap_src(stx.src, "!!!ERROR!!!"),
wrap_src(stx.src, stx.content),
wrap_src(stx.src, "!!!ERROR!!!"),
];
default:
const invalid: never = stx;
throw invalid;
Expand All @@ -77,15 +83,12 @@ function loc_to_ns(loc: Loc): ns {
case "binary_expression":
case "unary_expression":
case "ternary_expression":
return ["(", ls, ")"];
return [lparen, ls, rparen];
default:
return ls;
}
}

const lp = "/*>>>*/";
const rp = "/*<<<*/";

function path_to_ns(path: Loc["p"], ns: ns): ns {
switch (path.type) {
case "top":
Expand All @@ -103,11 +106,11 @@ function loc_to_ns(loc: Loc): ns {
}

function mark_top(ns: ns): ns {
return [lp, ns, rp];
return [lpointer, ns, rpointer];
}

function strip_top(ns: ns): ns {
if (Array.isArray(ns) && ns.length === 3 && ns[0] === lp && ns[2] === rp) {
if (Array.isArray(ns) && ns.length === 3 && ns[0] === lpointer && ns[2] === rpointer) {
return ns[1];
} else {
return ns;
Expand All @@ -120,26 +123,86 @@ function loc_to_ns(loc: Loc): ns {
}
}

const lparen: n = { val: "(", src: false };
const rparen: n = { val: ")", src: false };
const space: n = { val: " ", src: false };
const newline: n = { val: "\n", src: false };
const lpointer: n = { val: "/*>>>*/", src: false };
const rpointer: n = { val: "/*<<<*/", src: false };

function ns_flatten(main_ns: ns) {
const ac: string[] = [];
const ac: n[] = [];

function push(x: string) {
ac.push(" ");
function push(x: n) {
ac.push(space);
ac.push(x);
}

function conv(ns: ns) {
if (typeof ns === "string") {
push(ns);
} else {
if (Array.isArray(ns)) {
ns.forEach(conv);
} else {
push(ns);
}
}

conv(main_ns);
ac.push("\n");

return ac[0] === " " ? ac.slice(1) : ac;
return ac[0] === space ? ac.slice(1) : ac;
}

type map_options = {
filename: string;
resolve: (cuid: string) => Promise<string>;
};

function uniq(ls: string[]): string[] {
return Object.keys(Object.fromEntries(ls.map((x) => [x, x])));
}

async function add_src_map(code: string, ls: n[], options: map_options): Promise<string> {
const srcmap = new SourceMapGenerator({
file: options.filename,
});
let line = 0;
let column = 0;

const paths: { [cuid: string]: string } = Object.fromEntries(
await Promise.all(
uniq(ls.map((x) => (x.src ? x.src.cuid : "")).filter((x) => x.length > 0)).map(
async (cuid) => [cuid, await options.resolve(cuid)],
),
),
);

function emit_src(src: source) {
assert(typeof src.s !== "number");
const source = paths[src.cuid];
assert(source !== undefined);
srcmap.addMapping({
generated: { line: line + 1, column },
original: { line: src.s.line + 1, column: src.s.column },
source,
name: src.name,
});
return;
}
function advance_loc(val: string) {
const lines = val.split(/\(\r\n\)|\r|\n/g);
if (lines.length === 1) {
column += lines[0].split("").length;
} else {
line += lines.length - 1;
column = lines[lines.length - 1].split("").length;
}
}
ls.forEach(({ src, val }) => {
if (src) emit_src(src);
advance_loc(val);
});
const map_string = srcmap.toString();
const base64 = Base64.encode(map_string);
return `${code}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64}\n`;
}

export async function pretty_print(code: string) {
Expand All @@ -155,7 +218,17 @@ export async function pretty_print(code: string) {
}
}

export async function pprint(loc: Loc, prettify: boolean) {
const src = ns_flatten(loc_to_ns(loc)).join("");
return prettify ? await pretty_print(src) : src;
type options = {
prettify: boolean;
map?: map_options;
};

export async function pprint(loc: Loc, options: options): Promise<string> {
const ls = ns_flatten(loc_to_ns(loc));
const code = ls.map((x) => x.val).join("");
return options.prettify
? await pretty_print(code)
: options.map
? add_src_map(code, ls, options.map)
: code;
}
2 changes: 1 addition & 1 deletion test-project/.rts/main.rts.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"cid": "test-project/main.rts rewrite-ts-visualized 0.0.0",
"cookie": "rewrite-ts-020",
"cookie": "rewrite-ts-021",
"imports": [
{
"pkg": {"name": "rewrite-ts-visualized", "version": "0.0.0"},
Expand Down
1 change: 1 addition & 0 deletions test-project/.rts/main.rts.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import { type t_2 as t_2 , x_1 as x_3 , f_3 as f_4 } from "./mod.rts.ts" ; import { expect as expect_5 } from "vitest" ; export const y_1 : t_2 = ( x_3 + f_4 ) ; console . log ( expect_5 ) ; console . log ( y_1 ) ;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL21haW4ucnRzIiwiLi4vbW9kLnJ0cyJdLCJuYW1lcyI6WyJ5IiwidCIsIngiLCJmIiwiY29uc29sZSIsImxvZyIsImV4cGVjdCJdLCJtYXBwaW5ncyI6ImdJQUVBLE1BQU1BLElBQUMsRUFBRUMsSUFBRSxJQUFFQyxJQUFFLEVDR3lCQyxRREZ4Q0MsUUFBTyxFQUFDQyxJQUFHLEVBQUNDLFNBQU0sSUFDbEJGLFFBQU8sRUFBQ0MsSUFBRyxFQUFDTCxJQUFDIiwiZmlsZSI6Im1haW4ucnRzLnRzIn0=
2 changes: 1 addition & 1 deletion test-project/.rts/mod.rts.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"cid": "test-project/mod.rts rewrite-ts-visualized 0.0.0",
"cookie": "rewrite-ts-020",
"cookie": "rewrite-ts-021",
"imports": [],
"exported_identifiers": {
"x": [
Expand Down
1 change: 1 addition & 0 deletions test-project/.rts/mod.rts.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const x_1 = 12 ; export type t_2 = number ; export const f_3 = 13 ;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL21vZC5ydHMiXSwibmFtZXMiOlsieCIsInQiLCJmIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLE1BQU1BLElBQUUsRUFBRSxHQUFFLEVBQ25CLE9BQU8sS0FBS0MsSUFBRSxFQUFFLE9BQU0sU0FFdEIsTUFBTUMsSUFBRSxFQUFFIiwiZmlsZSI6Im1vZC5ydHMudHMifQ==
2 changes: 1 addition & 1 deletion test-project/.rts/test1.test.rts.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"cid": "test-project/test1.test.rts rewrite-ts-visualized 0.0.0",
"cookie": "rewrite-ts-020",
"cookie": "rewrite-ts-021",
"imports": [
{
"pkg": {"name": "vitest", "version": "2.1.8"},
Expand Down
1 change: 1 addition & 0 deletions test-project/.rts/test1.test.rts.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import { suite as suite_1 , test as test_2 , expect as expect_3 } from "vitest" ; suite_1 ( "sample test" , ( ( ) => { test_2 ( "should work" , ( ( ) => { expect_3 ( 5 ) . toBe ( 5 ) ; } ) ) ; } ) ) ;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3Rlc3QxLnRlc3QucnRzIl0sIm5hbWVzIjpbInN1aXRlIiwidGVzdCIsImV4cGVjdCIsInRvQmUiXSwibWFwcGluZ3MiOiJrRkFFQUEsUUFBSyxFQUFDLGNBQWEsSUFBRSxFQUFDLEVBQUUsR0FBRyxFQUN6QkMsT0FBSSxFQUFDLGNBQWEsSUFBRSxFQUFDLEVBQUUsR0FBRyxFQUN4QkMsU0FBTSxFQUFDLEVBQUMsRUFBQyxFQUFDQyxLQUFJLEVBQUMsRUFBQyxJQUNsQixJQUFDLElBQ0gsSUFBQyIsImZpbGUiOiJ0ZXN0MS50ZXN0LnJ0cy50cyJ9
5 changes: 4 additions & 1 deletion ui/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ function Example({ code, onChange }: ExampleProps) {
state.pointer === null || state.pointer >= state.prev_steps.length
? [state.last_step, state.step_number]
: [state.prev_steps[state.pointer], state.pointer];
const code_to_display = useMemo(() => pprint(display_step.loc, true), [display_step]);
const code_to_display = useMemo(
() => pprint(display_step.loc, { prettify: true }),
[display_step],
);
return (
<div>
<input
Expand Down

0 comments on commit a79a8fb

Please sign in to comment.