Skip to content

Commit b83a9fe

Browse files
getBlockStringIndentation: simplify implementation (#2748)
1 parent 6e0bc20 commit b83a9fe

File tree

4 files changed

+65
-51
lines changed

4 files changed

+65
-51
lines changed

src/language/__tests__/blockString-test.js

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,33 +96,32 @@ describe('dedentBlockStringValue', () => {
9696
});
9797

9898
describe('getBlockStringIndentation', () => {
99-
it('returns zero for an empty array', () => {
100-
expect(getBlockStringIndentation([])).to.equal(0);
99+
it('returns zero for an empty string', () => {
100+
expect(getBlockStringIndentation('')).to.equal(0);
101101
});
102102

103103
it('do not take first line into account', () => {
104-
expect(getBlockStringIndentation([' a'])).to.equal(0);
105-
expect(getBlockStringIndentation([' a', ' b'])).to.equal(2);
104+
expect(getBlockStringIndentation(' a')).to.equal(0);
105+
expect(getBlockStringIndentation(' a\n b')).to.equal(2);
106106
});
107107

108108
it('returns minimal indentation length', () => {
109-
expect(getBlockStringIndentation(['', ' a', ' b'])).to.equal(1);
110-
expect(getBlockStringIndentation(['', ' a', ' b'])).to.equal(1);
111-
expect(getBlockStringIndentation(['', ' a', ' b', 'c'])).to.equal(0);
109+
expect(getBlockStringIndentation('\n a\n b')).to.equal(1);
110+
expect(getBlockStringIndentation('\n a\n b')).to.equal(1);
111+
expect(getBlockStringIndentation('\n a\n b\nc')).to.equal(0);
112112
});
113113

114114
it('count both tab and space as single character', () => {
115-
expect(getBlockStringIndentation(['', '\ta', ' b'])).to.equal(1);
116-
expect(getBlockStringIndentation(['', '\t a', ' b'])).to.equal(2);
117-
expect(getBlockStringIndentation(['', ' \t a', ' b'])).to.equal(3);
115+
expect(getBlockStringIndentation('\n\ta\n b')).to.equal(1);
116+
expect(getBlockStringIndentation('\n\t a\n b')).to.equal(2);
117+
expect(getBlockStringIndentation('\n \t a\n b')).to.equal(3);
118118
});
119119

120120
it('do not take empty lines into account', () => {
121-
expect(getBlockStringIndentation(['a', '\t'])).to.equal(0);
122-
expect(getBlockStringIndentation(['a', ' '])).to.equal(0);
123-
expect(getBlockStringIndentation(['a', ' ', ' b'])).to.equal(2);
124-
expect(getBlockStringIndentation(['a', ' ', ' b'])).to.equal(2);
125-
expect(getBlockStringIndentation(['a', '', ' b'])).to.equal(1);
121+
expect(getBlockStringIndentation('a\n ')).to.equal(0);
122+
expect(getBlockStringIndentation('a\n\t')).to.equal(0);
123+
expect(getBlockStringIndentation('a\n\n b')).to.equal(1);
124+
expect(getBlockStringIndentation('a\n \n b')).to.equal(2);
126125
});
127126
});
128127

src/language/blockString.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function dedentBlockStringValue(rawString: string): string;
99
/**
1010
* @internal
1111
*/
12-
export function getBlockStringIndentation(lines: ReadonlyArray<string>): number;
12+
export function getBlockStringIndentation(body: string): number;
1313

1414
/**
1515
* Print a block string in the indented block form by adding a leading and

src/language/blockString.js

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function dedentBlockStringValue(rawString: string): string {
1111
const lines = rawString.split(/\r\n|[\n\r]/g);
1212

1313
// Remove common indentation from all lines but first.
14-
const commonIndent = getBlockStringIndentation(lines);
14+
const commonIndent = getBlockStringIndentation(rawString);
1515

1616
if (commonIndent !== 0) {
1717
for (let i = 1; i < lines.length; i++) {
@@ -20,52 +20,68 @@ export function dedentBlockStringValue(rawString: string): string {
2020
}
2121

2222
// Remove leading and trailing blank lines.
23-
while (lines.length > 0 && isBlank(lines[0])) {
24-
lines.shift();
23+
let startLine = 0;
24+
while (startLine < lines.length && isBlank(lines[startLine])) {
25+
++startLine;
2526
}
26-
while (lines.length > 0 && isBlank(lines[lines.length - 1])) {
27-
lines.pop();
27+
28+
let endLine = lines.length;
29+
while (endLine > startLine && isBlank(lines[endLine - 1])) {
30+
--endLine;
2831
}
2932

3033
// Return a string of the lines joined with U+000A.
31-
return lines.join('\n');
34+
return lines.slice(startLine, endLine).join('\n');
3235
}
36+
37+
function isBlank(str) {
38+
for (let i = 0; i < str.length; ++i) {
39+
if (str[i] !== ' ' && str[i] !== '\t') {
40+
return false;
41+
}
42+
}
43+
44+
return true;
45+
}
46+
3347
/**
3448
* @internal
3549
*/
36-
export function getBlockStringIndentation(
37-
lines: $ReadOnlyArray<string>,
38-
): number {
50+
export function getBlockStringIndentation(value: string): number {
51+
let isFirstLine = true;
52+
let isEmptyLine = true;
53+
let indent = 0;
3954
let commonIndent = null;
4055

41-
for (let i = 1; i < lines.length; i++) {
42-
const line = lines[i];
43-
const indent = leadingWhitespace(line);
44-
if (indent === line.length) {
45-
continue; // skip empty lines
46-
}
47-
48-
if (commonIndent === null || indent < commonIndent) {
49-
commonIndent = indent;
50-
if (commonIndent === 0) {
56+
for (let i = 0; i < value.length; ++i) {
57+
switch (value.charCodeAt(i)) {
58+
case 13: // \r
59+
if (value.charCodeAt(i + 1) === 10) {
60+
++i; // skip \r\n as one symbol
61+
}
62+
// falls through
63+
case 10: // \n
64+
isFirstLine = false;
65+
isEmptyLine = true;
66+
indent = 0;
67+
break;
68+
case 9: // \t
69+
case 32: // <space>
70+
++indent;
5171
break;
52-
}
72+
default:
73+
if (
74+
isEmptyLine &&
75+
!isFirstLine &&
76+
(commonIndent === null || indent < commonIndent)
77+
) {
78+
commonIndent = indent;
79+
}
80+
isEmptyLine = false;
5381
}
5482
}
5583

56-
return commonIndent === null ? 0 : commonIndent;
57-
}
58-
59-
function leadingWhitespace(str) {
60-
let i = 0;
61-
while (i < str.length && (str[i] === ' ' || str[i] === '\t')) {
62-
i++;
63-
}
64-
return i;
65-
}
66-
67-
function isBlank(str) {
68-
return leadingWhitespace(str) === str.length;
84+
return commonIndent ?? 0;
6985
}
7086

7187
/**

src/utilities/stripIgnoredCharacters.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ function dedentBlockString(blockStr) {
107107
const rawStr = blockStr.slice(3, -3);
108108
let body = dedentBlockStringValue(rawStr);
109109

110-
const lines = body.split(/\r\n|[\n\r]/g);
111-
if (getBlockStringIndentation(lines) > 0) {
110+
if (getBlockStringIndentation(body) > 0) {
112111
body = '\n' + body;
113112
}
114113

0 commit comments

Comments
 (0)