Skip to content

Commit

Permalink
feat: Add getPosAtLineNumber
Browse files Browse the repository at this point in the history
  • Loading branch information
HoldYourWaffle committed Dec 5, 2020
1 parent 3efd12e commit 7cecfd6
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/common/lib/ts-morph-common.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ export declare class StringUtils {
static endsWithNewLine(str: string | undefined): boolean;
static insertAtLastNonWhitespace(str: string, insertText: string): string;
static getLineNumberAtPos(str: string, pos: number): number;
static getPosAtLineNumber(str: string, line: number): number;
static getLengthFromLineStartAtPos(str: string, pos: number): number;
static getLineStartFromPos(str: string, pos: number): number;
static getLineEndFromPos(str: string, pos: number): number;
Expand Down
51 changes: 51 additions & 0 deletions packages/common/src/tests/utils/stringUtilsTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,57 @@ describe(nameof(StringUtils), () => {
});
});

describe(nameof(StringUtils.getPosAtLineNumber), () => {
it("should throw if providing a negative line number", () => {
expect(() => StringUtils.getPosAtLineNumber("", -1)).to.throw(errors.ArgumentOutOfRangeError);
});

it("should not throw if providing a line number the amount of lines", () => {
expect(() => StringUtils.getPosAtLineNumber("", 1)).to.not.throw();
});

it("should throw if providing a line number greater than the length + 1", () => {
expect(() => StringUtils.getPosAtLineNumber("", 2)).to.throw(errors.ArgumentOutOfRangeError);
});

function doTest(newLineType: string) {
let str = `testing${newLineType}this${newLineType}out${newLineType}`;
const pos = str.length;
str += `more and more${newLineType}and more`;
expect(StringUtils.getPosAtLineNumber(str, 4)).to.equal(pos);
}

it("should get the pos for the specified line number when using \\n newlines", () => {
doTest("\n");
});

it("should get the pos for the specified line number when using \\r\\n newlines", () => {
doTest("\r\n");
});

it("should get the pos for the specified line number when right after the newline when mixing newlines", () => {
let str = "testing\r\nthis\nout\nmore\r\nandmore\n";
const pos = str.length;
str += "out\r\nmore and more";
expect(StringUtils.getPosAtLineNumber(str, 6)).to.equal(pos);
});

function testSymmetry(newLineType: string) {
let str = `testing${newLineType}this${newLineType}out`;
const posAtLine = StringUtils.getPosAtLineNumber(str, 2);
const lineAtPos = StringUtils.getLineNumberAtPos(str, posAtLine);
expect(lineAtPos).to.equal(2);
}

it("should be symmetric with getLineNumberAtPos when using \\n newlines", () => {
testSymmetry("\n");
});

it("should be symmetric with getLineNumberAtPos when using \\r\\n newlines", () => {
testSymmetry("\r\n");
});
});

describe(nameof(StringUtils.getLengthFromLineStartAtPos), () => {
it("should throw if providing a negative pos", () => {
expect(() => StringUtils.getLengthFromLineStartAtPos("", -1)).to.throw(errors.ArgumentOutOfRangeError);
Expand Down
12 changes: 12 additions & 0 deletions packages/common/src/utils/StringUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ export class StringUtils {
return count + 1; // convert count to line number
}

static getPosAtLineNumber(str: string, line: number) {
const lines = str.split('\n');
errors.throwIfOutOfRange(line, [1, lines.length], nameof(line));
let count = 0;

for (let i = 0; i < line - 1; i++) { // line number is 1-indexed
count += lines[i].length + 1; // include newline
}

return count; // convert count to pos
}

static getLengthFromLineStartAtPos(str: string, pos: number) {
errors.throwIfOutOfRange(pos, [0, str.length], nameof(pos));
return pos - StringUtils.getLineStartFromPos(str, pos);
Expand Down
6 changes: 6 additions & 0 deletions packages/ts-morph/lib/ts-morph.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7203,6 +7203,12 @@ export declare class SourceFile extends SourceFileBase<ts.SourceFile> {
line: number;
column: number;
};
/**
* Gets the position (1-indexed) at the provided line and column number.
* @param line - Line number in the source file.
* @param col - Column number in the source file.
*/
getPosAtLineAndColumn(line: number, col: number): number;
/**
* Gets the character count from the start of the line to the provided position.
* @param pos - Position.
Expand Down
12 changes: 11 additions & 1 deletion packages/ts-morph/src/compiler/ast/module/SourceFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class SourceFile extends SourceFileBase<ts.SourceFile> {
}

/**
* Gets the line and column number at the provided position (1-indexed).
* Gets the line and column number (1-indexed) at the provided position.
* @param pos - Position in the source file.
*/
getLineAndColumnAtPos(pos: number) {
Expand All @@ -173,6 +173,16 @@ export class SourceFile extends SourceFileBase<ts.SourceFile> {
};
}

/**
* Gets the position at the provided line and column number (1-indexed).
* @param line - Line number in the source file.
* @param col - Column number in the source file.
*/
getPosAtLineAndColumn(line: number, col: number) {
const fullText = this.getFullText();
return StringUtils.getPosAtLineNumber(fullText, line) + col;
}

/**
* Gets the character count from the start of the line to the provided position.
* @param pos - Position.
Expand Down

0 comments on commit 7cecfd6

Please sign in to comment.