Skip to content

Commit

Permalink
source
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxingbaoyu committed Sep 22, 2022
1 parent ae10b49 commit 0af98b6
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 73 deletions.
92 changes: 31 additions & 61 deletions packages/babel-generator/src/buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@ type QueueItem = {
filename: string | undefined;
};

function SourcePos(): SourcePos {
return {
identifierName: undefined,
line: undefined,
column: undefined,
filename: undefined,
};
}

export default class Buffer {
constructor(map?: SourceMap | null) {
this._map = map;
Expand All @@ -55,13 +46,11 @@ export default class Buffer {
line: 1,
column: 0,
};
_sourcePosition = SourcePos();
_disallowedPop: SourcePos & { objectReusable: boolean } = {
_sourcePosition: SourcePos = {
identifierName: undefined,
line: undefined,
column: undefined,
filename: undefined,
objectReusable: true, // To avoid deleting and re-creating objects, we reuse existing objects when they are not needed anymore.
};

_allocQueue() {
Expand Down Expand Up @@ -230,6 +219,7 @@ export default class Buffer {

_append(str: string, sourcePos: SourcePos, maybeNewline: boolean): void {
const len = str.length;
const position = this._position;

this._last = str.charCodeAt(len - 1);

Expand All @@ -243,7 +233,7 @@ export default class Buffer {
}

if (!maybeNewline && !this._map) {
this._position.column += len;
position.column += len;
return;
}

Expand All @@ -265,18 +255,18 @@ export default class Buffer {

// Now, find each reamining newline char in the string.
while (i !== -1) {
this._position.line++;
this._position.column = 0;
position.line++;
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) {
if (last < len) {
this._mark(++line, 0, identifierName, filename);
}
i = str.indexOf("\n", last);
}
this._position.column += str.length - last;
position.column += len - last;
}

_mark(
Expand Down Expand Up @@ -370,15 +360,7 @@ export default class Buffer {

cb();

// In cases where tokens are printed after this item, we want to
// ensure that they get the location of the _end_ of the identifier.
// To accomplish this, we assign the location and explicitly disable
// the standard Buffer withSource previous-position "reactivation"
// logic. This means that if another item calls '.source()' to set
// the location after the identifier, it is fine, but the position won't
// be automatically replaced with the previous value.
this.source("end", loc);
this._disallowPop("start", loc);
}

/**
Expand All @@ -394,53 +376,41 @@ export default class Buffer {
this._normalizePosition(prop, loc, this._sourcePosition);
}

/**
* Call a callback with a specific source location and restore on completion.
*/

withSource(prop: "start" | "end", loc: Loc, cb: () => void): void {
if (!this._map) return cb();

// Use the call stack to manage a stack of "source location" data because
// the _sourcePosition object is mutated over the course of code generation,
// and constantly copying it would be slower.
const originalLine = this._sourcePosition.line;
const originalColumn = this._sourcePosition.column;
const originalFilename = this._sourcePosition.filename;
const originalIdentifierName = this._sourcePosition.identifierName;
sourceWithOffset(
prop: "start" | "end",
loc: Loc | undefined,
lineOffset: number,
columnOffset: number,
): void {
if (!loc) return;

this.source(prop, loc);
const pos = loc[prop];

cb();
const sourcePosition = this._sourcePosition;

if (
// Verify if reactivating this specific position has been disallowed.
this._disallowedPop.objectReusable ||
this._disallowedPop.line !== originalLine ||
this._disallowedPop.column !== originalColumn ||
this._disallowedPop.filename !== originalFilename
) {
this._sourcePosition.line = originalLine;
this._sourcePosition.column = originalColumn;
this._sourcePosition.filename = originalFilename;
this._sourcePosition.identifierName = originalIdentifierName;
this._disallowedPop.objectReusable = true;
sourcePosition.identifierName =
(prop === "start" && loc.identifierName) || undefined;
if (pos) {
sourcePosition.line = pos.line + lineOffset;
sourcePosition.column = pos.column + columnOffset;
sourcePosition.filename = loc.filename;
} else {
sourcePosition.line = null;
sourcePosition.column = null;
sourcePosition.filename = null;
}
}

/**
* Allow printers to disable the default location-reset behavior of the
* sourcemap output, so that certain printers can be sure that the
* "end" location that they set is actually treated as the end position.
* Call a callback with a specific source location and restore on completion.
*/
_disallowPop(prop: "start" | "end", loc: Loc) {
if (!loc) return;

const disallowedPop = this._disallowedPop;
withSource(prop: "start" | "end", loc: Loc, cb: () => void): void {
if (!this._map) return cb();

this._normalizePosition(prop, loc, disallowedPop);
this.source(prop, loc);

disallowedPop.objectReusable = false;
cb();
}

_normalizePosition(prop: "start" | "end", loc: Loc, targetObj: SourcePos) {
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-generator/src/generators/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ export function BlockStatement(this: Printer, node: t.BlockStatement) {
this.printSequence(node.body, node, { indent: true });
this.removeTrailingNewline();

this.source("end", node.loc);
this.sourceWithOffset("end", node.loc, 0, -1);

if (!this.endsWith(charCodes.lineFeed)) this.newline();

this.rightBrace();
} else {
this.source("end", node.loc);
this.sourceWithOffset("end", node.loc, 0, -1);
this.token("}");
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/babel-generator/src/generators/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import type * as t from "@babel/types";
import jsesc from "jsesc";

export function Identifier(this: Printer, node: t.Identifier) {
this.exactSource(node.loc, () => {
this.word(node.name);
});
this.word(node.name);
}

export function ArgumentPlaceholder(this: Printer) {
Expand All @@ -32,6 +30,8 @@ export function ObjectExpression(this: Printer, node: t.ObjectExpression) {
this.space();
}

this.sourceWithOffset("end", node.loc, 0, -1);

this.token("}");
}

Expand Down
13 changes: 12 additions & 1 deletion packages/babel-generator/src/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,17 @@ class Printer {
this._buf.source(prop, loc);
}

sourceWithOffset(
prop: "start" | "end",
loc: Loc | undefined,
lineOffset: number,
columnOffset: number,
): void {
this._catchUp(prop, loc);

this._buf.sourceWithOffset(prop, loc, lineOffset, columnOffset);
}

withSource(
prop: "start" | "end",
loc: Loc | undefined,
Expand Down Expand Up @@ -558,7 +569,7 @@ class Printer {

const loc = nodeType === "Program" || nodeType === "File" ? null : node.loc;

this.withSource("start", loc, printMethod.bind(this, node, parent));
this.exactSource(loc, printMethod.bind(this, node, parent));

if (noLineTerminator && !this._noLineTerminator) {
this._noLineTerminator = true;
Expand Down
10 changes: 5 additions & 5 deletions packages/babel-helper-fixtures/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,12 @@ function pushTask(
const sourceMapLoc = taskDir + "/source-map.json";
if (fs.existsSync(sourceMapLoc)) {
test.sourceMap = JSON.parse(readFile(sourceMapLoc));
test.sourceMapFile = {
loc: sourceMapLoc,
code: test.sourceMap,
filename: "",
};
}
test.sourceMapFile = {
loc: sourceMapLoc,
code: test.sourceMap,
filename: "",
};

const inputMapLoc = taskDir + "/input-source-map.json";
if (fs.existsSync(inputMapLoc)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ async function run(task: Test) {
try {
expect(result.map).toEqual(task.sourceMap);
} catch (e) {
if (!process.env.OVERWRITE || !task.sourceMapFile) throw e;
if (!process.env.OVERWRITE && task.sourceMapFile) throw e;

console.log(`Updated test file: ${task.sourceMapFile.loc}`);
fs.writeFileSync(
Expand Down

0 comments on commit 0af98b6

Please sign in to comment.