Skip to content
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

Add sourcemap markings for each line of a string #12086

Merged
merged 4 commits into from Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 43 additions & 19 deletions packages/babel-generator/src/buffer.js
Expand Up @@ -116,30 +116,54 @@ export default class Buffer {
filename: ?string,
force?: boolean,
): void {
// If there the line is ending, adding a new mapping marker is redundant
if (this._map && str[0] !== "\n") {
this._map.mark(
this._position.line,
this._position.column,
line,
column,
identifierName,
filename,
force,
);
}

this._buf.push(str);
this._last = str[str.length - 1];

for (let i = 0; i < str.length; i++) {
if (str[i] === "\n") {
this._position.line++;
this._position.column = 0;
} else {
this._position.column++;
// Search for newline chars. We search only for `\n`, since both `\r` and
// `\r\n` are normalized to `\n` during parse. We exclude `\u2028` and
// `\u2029` for performance reasons, they're so uncommon that it's probably
// ok. It's also unclear how other sourcemap utilities handle them...
let i = str.indexOf("\n");
JLHwung marked this conversation as resolved.
Show resolved Hide resolved
let last = 0;

// If the string starts with a newline char, then adding a mark is redundant.
// This catches both "no newlines" and "newline after several chars".
if (i !== 0) {
this._mark(line, column, identifierName, filename, force);
}

// Now, find each reamining newline char in the string.
while (i !== -1) {
this._position.line++;
this._position.column = 0;
last = i + 1;

// We mark the start of each line, which happens directly after this newline char
// unless this is the last char.
if (last < str.length) {
this._mark(++line, 0, identifierName, filename, force);
}
i = str.indexOf("\n", last);
}
this._position.column += str.length - last;
}

_mark(
line: number,
column: number,
identifierName: ?string,
filename: ?string,
force?: boolean,
): void {
this._map?.mark(
this._position.line,
this._position.column,
line,
column,
identifierName,
filename,
force,
);
}

removeTrailingNewline(): void {
Expand Down
@@ -0,0 +1,6 @@
"before\
after";

"before\
\
after";
@@ -0,0 +1,5 @@
"before\
after";
"before\
\
after";
@@ -0,0 +1,9 @@
{
"mappings": "AAAA;AACA,MADA;AAGA;AACA;AACA,MAFA",
"names": [],
"sources": ["fixtures/sourcemaps/string-literal-newline/input.js"],
"sourcesContent": [
"\"before\\\nafter\";\n\n\"before\\\n\\\nafter\";"
],
"version": 3
}
@@ -0,0 +1,27 @@
// Newline
`before
after`;

// Newline newline
`before

after`;

// Newline LineContinuation
`before
\
after`;

// LineContinuation
`before\
after`;

// LineContinuation newline
`before\

after`;

// LineContinuation LineContinuation
`before\
\
after`;
@@ -0,0 +1,22 @@
// Newline
`before
after`; // Newline newline

`before

after`; // Newline LineContinuation

`before
\
after`; // LineContinuation

`before\
after`; // LineContinuation newline

`before\

after`; // LineContinuation LineContinuation

`before\
\
after`;
@@ -0,0 +1,9 @@
{
"mappings": "AAAA;AACC;AACD,MADA,C,CAGA;;AACC;AACD;AACA,MAFA,C,CAIA;;AACC;AACD;AACA,MAFA,C,CAIA;;AACC;AACD,MADA,C,CAGA;;AACC;AACD;AACA,MAFA,C,CAIA;;AACC;AACD;AACA,MAFA",
"names": [],
"sources": ["fixtures/sourcemaps/template-literal-newline/input.js"],
"sourcesContent": [
"// Newline\n`before\nafter`;\n\n// Newline newline\n`before\n\nafter`;\n\n// Newline LineContinuation\n`before\n\\\nafter`;\n\n// LineContinuation\n`before\\\nafter`;\n\n// LineContinuation newline\n`before\\\n\nafter`;\n\n// LineContinuation LineContinuation\n`before\\\n\\\nafter`;"
],
"version": 3
}
43 changes: 43 additions & 0 deletions packages/babel-generator/test/index.js
Expand Up @@ -5,6 +5,7 @@ import * as t from "@babel/types";
import fs from "fs";
import path from "path";
import fixtures from "@babel/helper-fixtures";
import sourcemap from "source-map";

describe("generation", function () {
it("completeness", function () {
Expand Down Expand Up @@ -277,6 +278,48 @@ describe("generation", function () {
expect(generated.code).toBe("function foo2() {\n bar2;\n}");
});

it("newline in template literal", () => {
const code = "`before\n\nafter`;";
const ast = parse(code, { filename: "inline" }).program;
const generated = generate(
ast,
{
filename: "inline",
sourceFileName: "inline",
sourceMaps: true,
},
code,
);

const consumer = new sourcemap.SourceMapConsumer(generated.map);
const loc = consumer.originalPositionFor({ line: 2, column: 1 });
expect(loc).toMatchObject({
column: 0,
line: 2,
});
});

it("newline in string literal", () => {
const code = "'before\\\n\\\nafter';";
const ast = parse(code, { filename: "inline" }).program;
const generated = generate(
ast,
{
filename: "inline",
sourceFileName: "inline",
sourceMaps: true,
},
code,
);

const consumer = new sourcemap.SourceMapConsumer(generated.map);
const loc = consumer.originalPositionFor({ line: 2, column: 1 });
expect(loc).toMatchObject({
column: 0,
line: 2,
});
});

it("lazy source map generation", function () {
const code = "function hi (msg) { console.log(msg); }\n";

Expand Down