Skip to content

Commit f15cf56

Browse files
committed
fix scrammaps
1 parent e8ff38b commit f15cf56

File tree

4 files changed

+105
-80
lines changed

4 files changed

+105
-80
lines changed

src/client/shared/function.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ function rewriteFunction(ctx: ProxyCtx, client: ScramjetClient) {
55
const stringifiedFunction = ctx.call().toString();
66

77
const content = rewriteJs(
8-
`return ${stringifiedFunction}`,
8+
stringifiedFunction,
99
"(function proxy)",
1010
client.meta
1111
);
12-
ctx.return(ctx.fn(content)());
12+
ctx.return(ctx.fn(`return ${content}`)());
1313
}
1414

1515
export default function (client: ScramjetClient, _self: Self) {

src/client/shared/sourcemaps.ts

Lines changed: 92 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,28 @@ enum RewriteType {
66
Replace = 1,
77
}
88

9-
type Rewrite =
9+
type Rewrite = {
10+
start: number;
11+
} & (
1012
| {
1113
type: RewriteType.Insert;
12-
// offset before this rewrite
13-
offset: number;
14-
// start of insertion
15-
start: number;
16-
// size of insertion
1714
size: number;
1815
}
1916
| {
2017
type: RewriteType.Replace;
21-
// offset before this rewrite
22-
offset: number;
23-
// start of replacement
24-
start: number;
25-
// end of replacement
2618
end: number;
27-
// old string
2819
str: string;
29-
};
20+
}
21+
);
22+
23+
function getEnd(rewrite: Rewrite): number {
24+
if (rewrite.type === RewriteType.Insert) {
25+
return rewrite.start + rewrite.size;
26+
} else if (rewrite.type === RewriteType.Replace) {
27+
return rewrite.end;
28+
}
29+
throw "unreachable";
30+
}
3031

3132
const sourcemaps: Record<string, Rewrite[]> = {};
3233

@@ -35,49 +36,53 @@ export const enabled = (client: ScramjetClient) =>
3536

3637
export default function (client: ScramjetClient, self: Self) {
3738
// every script will push a sourcemap
38-
Object.defineProperty(self, $scramjet.config.globals.pushsourcemapfn, {
39-
value: (buf: Array<number>, tag: string) => {
40-
const sourcemap = Uint8Array.from(buf);
41-
const view = new DataView(sourcemap.buffer);
42-
const decoder = new TextDecoder("utf-8");
43-
44-
const rewrites = [];
45-
46-
const rewritelen = view.getUint32(0, true);
47-
let cursor = 0;
48-
for (let i = 0; i < rewritelen; i++) {
49-
const type = view.getUint8(cursor) as RewriteType;
50-
cursor += 1;
51-
52-
if (type == RewriteType.Insert) {
53-
const offset = view.getUint32(cursor, true);
54-
cursor += 4;
55-
const start = view.getUint32(cursor, true);
56-
cursor += 4;
57-
const size = view.getUint32(cursor, true);
58-
cursor += 4;
59-
60-
rewrites.push({ type, offset, start, size });
61-
} else if (type == RewriteType.Replace) {
62-
const offset = view.getUint32(cursor, true);
63-
cursor += 4;
64-
const start = view.getUint32(cursor, true);
65-
cursor += 4;
66-
const end = view.getUint32(cursor, true);
67-
cursor += 4;
68-
69-
const str = decoder.decode(sourcemap.subarray(start, end));
70-
71-
rewrites.push({ type, offset, start, end, str });
39+
Object.defineProperty(
40+
self,
41+
globalThis.$scramjet.config.globals.pushsourcemapfn,
42+
{
43+
value: (buf: Array<number>, tag: string) => {
44+
const sourcemap = Uint8Array.from(buf);
45+
const view = new DataView(sourcemap.buffer);
46+
const decoder = new TextDecoder("utf-8");
47+
48+
const rewrites: Rewrite[] = [];
49+
50+
const rewritelen = view.getUint32(0, true);
51+
let cursor = 4;
52+
for (let i = 0; i < rewritelen; i++) {
53+
const type = view.getUint8(cursor) as RewriteType;
54+
cursor += 1;
55+
56+
if (type == RewriteType.Insert) {
57+
const start = view.getUint32(cursor, true);
58+
cursor += 4;
59+
const size = view.getUint32(cursor, true);
60+
cursor += 4;
61+
62+
rewrites.push({ type, start, size });
63+
} else if (type == RewriteType.Replace) {
64+
const start = view.getUint32(cursor, true);
65+
cursor += 4;
66+
const end = view.getUint32(cursor, true);
67+
cursor += 4;
68+
const len = view.getUint32(cursor, true);
69+
cursor += 4;
70+
71+
const str = decoder.decode(
72+
sourcemap.subarray(cursor, cursor + len)
73+
);
74+
75+
rewrites.push({ type, start, end, str });
76+
}
7277
}
73-
}
7478

75-
sourcemaps[tag] = rewrites;
76-
},
77-
enumerable: false,
78-
writable: false,
79-
configurable: false,
80-
});
79+
sourcemaps[tag] = rewrites;
80+
},
81+
enumerable: false,
82+
writable: false,
83+
configurable: false,
84+
}
85+
);
8186

8287
const scramtag_ident = "/*scramtag ";
8388

@@ -86,7 +91,6 @@ export default function (client: ScramjetClient, self: Self) {
8691
client.Proxy("Function.prototype.toString", {
8792
apply(ctx) {
8893
let stringified: string = ctx.fn.call(ctx.this);
89-
let newString = "";
9094

9195
// every function rewritten will have a scramtag comment
9296
// it will look like this:
@@ -106,39 +110,50 @@ export default function (client: ScramjetClient, self: Self) {
106110

107111
// subtracting that from the index of the scramtag gives us the starting index of the function relative to the entire file
108112
const absindex = abstagindex - scramtagstart;
113+
const endindex = absindex + stringified.length;
109114

110115
const scramtagend = stringified.indexOf("*/", scramtagstart);
111116
const tag = stringified.substring(firstspace + 1, scramtagend);
112117

113-
// delete all scramtags inside the function (and nested ones!!)
114-
stringified = stringified.replace(/\/\*scramtag.*?\*\//g, "");
118+
const rewrites = sourcemaps[tag];
115119

116-
const maps = sourcemaps[tag];
120+
if (!rewrites) {
121+
console.warn("failed to get rewrites for tag", tag);
122+
return ctx.return(stringified);
123+
}
117124

118125
let i = 0;
119-
let offset = 0;
120-
121-
let j = 0;
122-
while (j < maps.length) {
123-
/* TODO
124-
const [str, start, end] = maps[j];
125-
if (start < absindex) {
126-
j++;
127-
continue;
128-
}
129-
if (start - absindex + offset > stringified.length) break;
126+
// skip all rewrites in the file before the fn
127+
while (i < rewrites.length) {
128+
if (rewrites[i].start < absindex) i++;
129+
else break;
130+
}
131+
132+
let end = i;
133+
while (end < rewrites.length) {
134+
if (getEnd(rewrites[end]) < endindex) end++;
135+
else break;
136+
}
130137

131-
// ooh i should really document this before i forget how it works
132-
newString += stringified.slice(i, start - absindex + offset);
133-
newString += str;
134-
offset += end - start - str.length;
135-
i = start - absindex + offset + str.length;
138+
const fnrewrites = rewrites.slice(i, end);
136139

137-
j++;
138-
*/
140+
let newString = "";
141+
let lastpos = absindex;
142+
143+
for (const rewrite of fnrewrites) {
144+
newString += stringified.slice(lastpos, rewrite.start);
145+
146+
if (rewrite.type === RewriteType.Insert) {
147+
lastpos = rewrite.start + rewrite.size;
148+
} else if (rewrite.type === RewriteType.Replace) {
149+
newString += rewrite.str;
150+
lastpos = rewrite.end;
151+
} else {
152+
throw "unreachable";
153+
}
139154
}
140155

141-
newString += stringified.slice(i);
156+
newString += stringified.slice(lastpos);
142157

143158
return ctx.return(newString);
144159
},

src/shared/rewriters/js.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,14 @@ function rewriteJsWrapper(
6262
return input;
6363
}
6464
const after = performance.now();
65-
const { js, errors, duration } = out;
65+
const { js, map, scramtag, errors, duration } = out;
66+
67+
if ((flagEnabled("sourcemaps", meta.base), !globalThis.clients)) {
68+
globalThis[globalThis.$scramjet.config.globals.pushsourcemapfn](
69+
Array.from(map),
70+
scramtag
71+
);
72+
}
6673

6774
if (flagEnabled("rewriterLogs", meta.base)) {
6875
for (const error of errors) {

static/ui.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ const scramjet = new ScramjetController({
66
shared: "/scram/scramjet.shared.js",
77
sync: "/scram/scramjet.sync.js",
88
},
9+
flags: {
10+
sourcemaps: true,
11+
},
912
siteFlags: {
1013
"https://worker-playground.glitch.me/.*": {
1114
serviceworkers: true,

0 commit comments

Comments
 (0)