Skip to content

Commit e258af0

Browse files
committed
Preserve source map markers across package targets
1 parent f7ca25e commit e258af0

5 files changed

Lines changed: 57 additions & 35 deletions

File tree

compiler/core/js_implementation.ml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,18 @@ let after_parsing_impl ppf outputprefix (ast : Parsetree.structure) =
141141
let typedtree_coercion = (typedtree, coercion) in
142142
print_if ppf Clflags.dump_typedtree
143143
Printtyped.implementation_with_coercion typedtree_coercion;
144-
(if !Js_config.cmi_only then Warnings.check_fatal ()
145-
else
146-
let lambda, exports =
147-
Translmod.transl_implementation modulename typedtree_coercion
148-
in
149-
let js_program =
150-
print_if_pipe ppf Clflags.dump_rawlambda Printlambda.lambda lambda
151-
|> Lam_compile_main.compile outputprefix exports
152-
in
153-
if not !Js_config.cmj_only then
154-
Lam_compile_main.lambda_as_module js_program outputprefix);
144+
Js_source_map.with_marker_scope (fun () ->
145+
if !Js_config.cmi_only then Warnings.check_fatal ()
146+
else
147+
let lambda, exports =
148+
Translmod.transl_implementation modulename typedtree_coercion
149+
in
150+
let js_program =
151+
print_if_pipe ppf Clflags.dump_rawlambda Printlambda.lambda lambda
152+
|> Lam_compile_main.compile outputprefix exports
153+
in
154+
if not !Js_config.cmj_only then
155+
Lam_compile_main.lambda_as_module js_program outputprefix);
155156
process_with_gentype (outputprefix ^ ".cmt"))
156157

157158
let implementation ~parser ppf ?outputprefix fname =

compiler/core/js_source_map.ml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ let comment_of_loc (loc : Location.t) =
4646
Hashtbl.replace marker_locs id loc;
4747
Some (marker_prefix ^ string_of_int id)
4848

49+
let with_marker_scope f =
50+
let first_marker = !next_marker in
51+
Ext_pervasives.finally ()
52+
~clean:(fun () ->
53+
for id = first_marker to !next_marker - 1 do
54+
Hashtbl.remove marker_locs id
55+
done)
56+
f
57+
4958
let with_builder builder f =
5059
let old = !current in
5160
current := builder;
@@ -182,21 +191,14 @@ let add_mapping builder ~generated_line ~generated_column (loc : Location.t) =
182191
:: builder.mappings;
183192
builder.last_generated <- Some (generated_line, generated_column)
184193

185-
let take_marker_loc id =
186-
match Hashtbl.find_opt marker_locs id with
187-
| None -> None
188-
| Some loc ->
189-
Hashtbl.remove marker_locs id;
190-
Some loc
191-
192194
let mark_comment fmt comment =
193195
if is_prefix ~prefix:marker_prefix comment then (
194196
let prefix_len = String.length marker_prefix in
195197
let id =
196198
int_of_string
197199
(String.sub comment prefix_len (String.length comment - prefix_len))
198200
in
199-
(match (!current, take_marker_loc id) with
201+
(match (!current, Hashtbl.find_opt marker_locs id) with
200202
| Some builder, Some loc ->
201203
let generated_line, generated_column = Ext_pp.position fmt in
202204
add_mapping builder ~generated_line ~generated_column loc

compiler/core/js_source_map.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ type t
33
val make :
44
generated_file:string -> source_root:string -> sources_content:bool -> t
55

6+
val with_marker_scope : (unit -> 'a) -> 'a
7+
68
val with_builder : t option -> (unit -> 'a) -> 'a
79

810
val comment_of_loc : Location.t -> string option

tests/build_tests/source_map/input.js

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,28 @@ const { execBuildOrThrow, execClean } = setup(import.meta.dirname);
99

1010
await execBuildOrThrow();
1111

12-
const jsPath = path.join(import.meta.dirname, "lib", "bs", "src", "Demo.js");
13-
const mapPath = `${jsPath}.map`;
12+
for (const filename of ["Demo.cjs", "Demo.mjs"]) {
13+
const jsPath = path.join(import.meta.dirname, "lib", "bs", "src", filename);
14+
const mapPath = `${jsPath}.map`;
1415

15-
const js = await fs.readFile(jsPath, "utf8");
16-
assert.match(js, /\/\/# sourceMappingURL=Demo\.js\.map/);
16+
const js = await fs.readFile(jsPath, "utf8");
17+
assert.match(
18+
js,
19+
new RegExp(`//# sourceMappingURL=${filename.replace(".", "\\.")}\\.map`),
20+
);
1721

18-
const map = JSON.parse(await fs.readFile(mapPath, "utf8"));
19-
assert.equal(map.version, 3);
20-
assert.equal(map.file, "Demo.js");
21-
assert.ok(map.mappings.length > 0, "source map should include mappings");
22-
assert.ok(
23-
map.sources.some(source => source.endsWith("Demo.res")),
24-
`source map should include Demo.res, got ${map.sources.join(", ")}`,
25-
);
26-
assert.ok(
27-
map.sourcesContent.some(content => content.includes("let add = (a, b)")),
28-
"source map should include source contents",
29-
);
22+
const map = JSON.parse(await fs.readFile(mapPath, "utf8"));
23+
assert.equal(map.version, 3);
24+
assert.equal(map.file, filename);
25+
assert.ok(map.mappings.length > 0, `${filename}.map should include mappings`);
26+
assert.ok(
27+
map.sources.some(source => source.endsWith("Demo.res")),
28+
`${filename}.map should include Demo.res, got ${map.sources.join(", ")}`,
29+
);
30+
assert.ok(
31+
map.sourcesContent.some(content => content.includes("let add = (a, b)")),
32+
`${filename}.map should include source contents`,
33+
);
34+
}
3035

3136
await execClean();

tests/build_tests/source_map/rescript.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
{
22
"name": "source_map",
33
"sources": ["src"],
4+
"package-specs": [
5+
{
6+
"module": "commonjs",
7+
"in-source": true,
8+
"suffix": ".cjs"
9+
},
10+
{
11+
"module": "esmodule",
12+
"in-source": true,
13+
"suffix": ".mjs"
14+
}
15+
],
416
"sourceMap": {
517
"enabled": "always",
618
"mode": "linked",

0 commit comments

Comments
 (0)