forked from dsherret/ts-morph
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStringUtils.ts
More file actions
151 lines (121 loc) · 4.49 KB
/
Copy pathStringUtils.ts
File metadata and controls
151 lines (121 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { QuoteKind } from "../compiler";
import * as errors from "../errors";
const isSpaces = /^ +$/;
const isWhitespace = /^\s*$/;
const startsWithNewLine = /^\r?\n/;
const endsWithNewLine = /\r?\n$/;
export class StringUtils {
private constructor() {
}
static hasBom(text: string) {
return text.charCodeAt(0) === 0xFEFF;
}
static stripBom(text: string) {
if (StringUtils.hasBom(text))
return text.slice(1);
return text;
}
static isNullOrWhitespace(str: string | undefined): str is undefined {
return typeof str !== "string" || StringUtils.isWhitespace(str);
}
static isNullOrEmpty(str: string | undefined): str is undefined {
return typeof str !== "string" || str.length === 0;
}
static isWhitespace(str: string) {
return isWhitespace.test(str);
}
static startsWithNewLine(str: string) {
return startsWithNewLine.test(str);
}
static endsWithNewLine(str: string) {
return endsWithNewLine.test(str);
}
static insertAtLastNonWhitespace(str: string, insertText: string) {
let i = str.length;
while (i > 0 && isWhitespace.test(str[i - 1]))
i--;
return str.substring(0, i) + insertText + str.substring(i);
}
static getLineNumberAtPos(str: string, pos: number) {
errors.throwIfOutOfRange(pos, [0, str.length], nameof(pos));
// do not allocate a string in this method
let count = 0;
for (let i = 0; i < pos; i++) {
if (str[i] === "\n" || (str[i] === "\r" && str[i + 1] !== "\n"))
count++;
}
return count + 1; // convert count to line number
}
static getLengthFromLineStartAtPos(str: string, pos: number) {
errors.throwIfOutOfRange(pos, [0, str.length], nameof(pos));
return pos - StringUtils.getLineStartFromPos(str, pos);
}
static getLineStartFromPos(str: string, pos: number) {
errors.throwIfOutOfRange(pos, [0, str.length], nameof(pos));
while (pos > 0) {
const previousChar = str[pos - 1];
if (previousChar === "\n" || previousChar === "\r")
break;
pos--;
}
return pos;
}
static getLineEndFromPos(str: string, pos: number) {
errors.throwIfOutOfRange(pos, [0, str.length], nameof(pos));
while (pos < str.length) {
const currentChar = str[pos];
if (currentChar === "\n" || currentChar === "\r")
break;
pos++;
}
return pos;
}
static escapeForWithinString(str: string, quoteKind: QuoteKind) {
return StringUtils.escapeChar(str, quoteKind).replace(/(\r?\n)/g, "\\$1");
}
/**
* Escapes all the occurrences of the char in the string.
*/
static escapeChar(str: string, char: string) {
if (char.length !== 1)
throw new errors.InvalidOperationError(`Specified char must be one character long.`);
let result = "";
for (let i = 0; i < str.length; i++) {
if (str[i] === char)
result += "\\";
result += str[i];
}
return result;
}
static indent(str: string, times: number, indentText: string, isInStringAtPos: (pos: number) => boolean) {
// todo: unit test this (right now it's somewhat tested indirectly)
const unIndentRegex = times > 0 ? undefined : new RegExp(getDeIndentRegexText());
const newLines: string[] = [];
let pos = 0;
for (const line of str.split("\n")) {
if (isInStringAtPos(pos))
newLines.push(line);
else if (times > 0)
newLines.push(indentText.repeat(times) + line);
else // negative
newLines.push(line.replace(unIndentRegex!, ""));
pos += line.length + 1; // +1 for \n char
}
return newLines.join("\n");
function getDeIndentRegexText() {
let text = "^";
for (let i = 0; i < Math.abs(times); i++) {
text += "(";
if (isSpaces.test(indentText)) {
// the optional string makes it possible to unindent when a line doesn't have the full number of spaces
for (let j = 0; j < indentText.length; j++)
text += " ?";
}
else
text += indentText;
text += "|\t)?";
}
return text;
}
}
}