@zzzen/pyright-internal 1.2.0-dev.20251228 → 1.2.0-dev.20260111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer/backgroundAnalysisProgram.d.ts +3 -3
- package/dist/analyzer/backgroundAnalysisProgram.js +18 -5
- package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
- package/dist/analyzer/binder.d.ts +1 -0
- package/dist/analyzer/binder.js +22 -0
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/declaration.d.ts +1 -0
- package/dist/analyzer/declaration.js.map +1 -1
- package/dist/analyzer/docStringUtils.d.ts +1 -0
- package/dist/analyzer/docStringUtils.js +36 -0
- package/dist/analyzer/docStringUtils.js.map +1 -1
- package/dist/analyzer/importStatementUtils.d.ts +2 -1
- package/dist/analyzer/importStatementUtils.js +4 -3
- package/dist/analyzer/importStatementUtils.js.map +1 -1
- package/dist/analyzer/parseTreeUtils.js +2 -2
- package/dist/analyzer/parseTreeUtils.js.map +1 -1
- package/dist/analyzer/program.d.ts +5 -0
- package/dist/analyzer/program.js +39 -14
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/pythonPathUtils.d.ts +1 -1
- package/dist/analyzer/service.d.ts +3 -2
- package/dist/analyzer/service.js +42 -12
- package/dist/analyzer/service.js.map +1 -1
- package/dist/analyzer/sourceMapper.d.ts +1 -1
- package/dist/analyzer/typeDocStringUtils.d.ts +4 -1
- package/dist/analyzer/typeDocStringUtils.js +9 -6
- package/dist/analyzer/typeDocStringUtils.js.map +1 -1
- package/dist/analyzer/typeEvaluator.js +16 -0
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/types.d.ts +1 -1
- package/dist/backgroundAnalysisBase.d.ts +2 -0
- package/dist/backgroundAnalysisBase.js.map +1 -1
- package/dist/commands/dumpFileDebugInfoCommand.d.ts +0 -96
- package/dist/commands/dumpFileDebugInfoCommand.js +6 -966
- package/dist/commands/dumpFileDebugInfoCommand.js.map +1 -1
- package/dist/common/console.d.ts +16 -3
- package/dist/common/console.js +25 -4
- package/dist/common/console.js.map +1 -1
- package/dist/common/core.d.ts +2 -0
- package/dist/common/core.js +11 -0
- package/dist/common/core.js.map +1 -1
- package/dist/common/docStringService.d.ts +5 -2
- package/dist/common/docStringService.js +6 -2
- package/dist/common/docStringService.js.map +1 -1
- package/dist/common/languageInfoUtils.d.ts +114 -0
- package/dist/common/languageInfoUtils.js +1004 -0
- package/dist/common/languageInfoUtils.js.map +1 -0
- package/dist/common/logTracker.d.ts +6 -4
- package/dist/common/logTracker.js +9 -6
- package/dist/common/logTracker.js.map +1 -1
- package/dist/common/pathConsts.d.ts +1 -0
- package/dist/common/pathConsts.js +2 -1
- package/dist/common/pathConsts.js.map +1 -1
- package/dist/common/realFileSystem.js +16 -10
- package/dist/common/realFileSystem.js.map +1 -1
- package/dist/common/serviceProvider.d.ts +2 -0
- package/dist/common/serviceProvider.js +23 -1
- package/dist/common/serviceProvider.js.map +1 -1
- package/dist/common/serviceProviderExtensions.js +5 -0
- package/dist/common/serviceProviderExtensions.js.map +1 -1
- package/dist/common/uri/baseUri.d.ts +1 -1
- package/dist/common/uri/uri.d.ts +2 -50
- package/dist/common/uri/uri.js.map +1 -1
- package/dist/common/uri/uriInterface.d.ts +51 -0
- package/dist/common/uri/uriInterface.js +10 -0
- package/dist/common/uri/uriInterface.js.map +1 -0
- package/dist/languageServerBase.js +2 -2
- package/dist/languageServerBase.js.map +1 -1
- package/dist/localization/package.nls.cs.json +18 -18
- package/dist/localization/package.nls.de.json +18 -18
- package/dist/localization/package.nls.es.json +18 -18
- package/dist/localization/package.nls.fr.json +18 -18
- package/dist/localization/package.nls.it.json +18 -18
- package/dist/localization/package.nls.ja.json +18 -18
- package/dist/localization/package.nls.ko.json +18 -18
- package/dist/localization/package.nls.pl.json +18 -18
- package/dist/localization/package.nls.pt-br.json +18 -18
- package/dist/localization/package.nls.ru.json +18 -18
- package/dist/localization/package.nls.tr.json +18 -18
- package/dist/localization/package.nls.zh-cn.json +18 -18
- package/dist/localization/package.nls.zh-tw.json +18 -18
- package/dist/tests/completions.test.js +47 -0
- package/dist/tests/completions.test.js.map +1 -1
- package/dist/tests/fourSlashParser.test.js +259 -12
- package/dist/tests/fourSlashParser.test.js.map +1 -1
- package/dist/tests/fourslash/findDefinitions.typedDict.keys.fourslash.js +9 -0
- package/dist/tests/fourslash/findDefinitions.typedDict.keys.fourslash.js.map +1 -1
- package/dist/tests/harness/fourslash/fourSlashParser.js +484 -27
- package/dist/tests/harness/fourslash/fourSlashParser.js.map +1 -1
- package/dist/tests/harness/fourslash/fourSlashRawUtils.d.ts +12 -0
- package/dist/tests/harness/fourslash/fourSlashRawUtils.js +151 -0
- package/dist/tests/harness/fourslash/fourSlashRawUtils.js.map +1 -0
- package/dist/tests/harness/fourslash/fourSlashTypes.d.ts +73 -2
- package/dist/tests/harness/fourslash/fourSlashTypes.js +27 -1
- package/dist/tests/harness/fourslash/fourSlashTypes.js.map +1 -1
- package/dist/tests/harness/fourslash/testState.js +1 -1
- package/dist/tests/harness/fourslash/testState.js.map +1 -1
- package/dist/tests/harness/vfs/factory.js +3 -3
- package/dist/tests/harness/vfs/factory.js.map +1 -1
- package/dist/tests/languageServer.test.js +3 -3
- package/dist/tests/languageServer.test.js.map +1 -1
- package/dist/tests/lsp/languageServer.js +10 -1
- package/dist/tests/lsp/languageServer.js.map +1 -1
- package/dist/tests/lsp/languageServerTestUtils.d.ts +3 -1
- package/dist/tests/lsp/languageServerTestUtils.js +24 -2
- package/dist/tests/lsp/languageServerTestUtils.js.map +1 -1
- package/package.json +3 -3
|
@@ -14,6 +14,7 @@ const pathUtils_1 = require("../../../common/pathUtils");
|
|
|
14
14
|
const uriUtils_1 = require("../../../common/uri/uriUtils");
|
|
15
15
|
const factory_1 = require("../vfs/factory");
|
|
16
16
|
const fourSlashTypes_1 = require("./fourSlashTypes");
|
|
17
|
+
const fourSlashRawUtils_1 = require("./fourSlashRawUtils");
|
|
17
18
|
/**
|
|
18
19
|
* Parse given fourslash markup code and return content with markup/range data
|
|
19
20
|
*
|
|
@@ -24,17 +25,21 @@ const fourSlashTypes_1 = require("./fourSlashTypes");
|
|
|
24
25
|
*/
|
|
25
26
|
function parseTestData(basePath, contents, fileName) {
|
|
26
27
|
const normalizedBasePath = (0, pathUtils_1.normalizeSlashes)(basePath);
|
|
27
|
-
//
|
|
28
|
-
|
|
28
|
+
// Historically, many fourslash strings ended with a trailing newline (often from a closing backtick on its own
|
|
29
|
+
// line). Some parsing logic assumes line feeds exist for line-to-offset mapping. Normalize to ensure the
|
|
30
|
+
// input always ends with an LF, so callers don't need to add a trailing empty line.
|
|
31
|
+
const rawText = contents.endsWith('\n') ? contents : `${contents}\n`;
|
|
32
|
+
const rawTokens = [];
|
|
29
33
|
// List of all the subfiles we've parsed out
|
|
30
34
|
const files = [];
|
|
31
35
|
// Global options
|
|
32
36
|
const globalOptions = {};
|
|
37
|
+
const globalOptionsRawData = {};
|
|
33
38
|
// Marker positions
|
|
34
39
|
// Split up the input file by line
|
|
35
40
|
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
|
|
36
41
|
// we have to string-based splitting instead and try to figure out the delimiting chars
|
|
37
|
-
const lines =
|
|
42
|
+
const lines = rawText.split('\n');
|
|
38
43
|
let i = 0;
|
|
39
44
|
const markerPositions = new Map();
|
|
40
45
|
const markers = [];
|
|
@@ -43,6 +48,10 @@ function parseTestData(basePath, contents, fileName) {
|
|
|
43
48
|
let currentFileContent;
|
|
44
49
|
let currentFileName = (0, pathUtils_1.normalizeSlashes)(fileName);
|
|
45
50
|
let currentFileOptions = {};
|
|
51
|
+
let currentFileOptionsRawData = {};
|
|
52
|
+
let currentFileTokenRanges = [];
|
|
53
|
+
let currentFileContentToRawSegments = [];
|
|
54
|
+
let lastFourSlashLineLfOffset;
|
|
46
55
|
let normalizedProjectRoot = normalizedBasePath;
|
|
47
56
|
function nextFile() {
|
|
48
57
|
if (currentFileContent === undefined) {
|
|
@@ -55,38 +64,92 @@ function parseTestData(basePath, contents, fileName) {
|
|
|
55
64
|
currentFileName = (0, pathUtils_1.normalizePath)((0, pathUtils_1.combinePaths)(factory_1.distlibFolder.getFilePath(), (0, pathUtils_1.getRelativePath)(currentFileName, normalizedBasePath)));
|
|
56
65
|
}
|
|
57
66
|
const ignoreCase = (0, core_1.toBoolean)(globalOptions["ignorecase" /* GlobalMetadataOptionNames.ignoreCase */]);
|
|
58
|
-
const file = parseFileContent(currentFileContent, currentFileName, ignoreCase, markerPositions, markers, ranges);
|
|
67
|
+
const file = parseFileContent(currentFileContent, currentFileContentToRawSegments, rawTokens, currentFileName, ignoreCase, markerPositions, markers, ranges);
|
|
59
68
|
file.fileOptions = currentFileOptions;
|
|
69
|
+
const mappingRawData = file.rawData;
|
|
70
|
+
file.rawData = {
|
|
71
|
+
tokenRanges: currentFileTokenRanges,
|
|
72
|
+
fileOptionsRawData: currentFileOptionsRawData,
|
|
73
|
+
rawToContent: mappingRawData?.rawToContent,
|
|
74
|
+
contentToRaw: mappingRawData?.contentToRaw,
|
|
75
|
+
};
|
|
60
76
|
// Store result file
|
|
61
77
|
files.push(file);
|
|
62
78
|
currentFileContent = undefined;
|
|
63
79
|
currentFileOptions = {};
|
|
80
|
+
currentFileOptionsRawData = {};
|
|
81
|
+
currentFileTokenRanges = [];
|
|
82
|
+
currentFileContentToRawSegments = [];
|
|
83
|
+
lastFourSlashLineLfOffset = undefined;
|
|
64
84
|
currentFileName = fileName;
|
|
65
85
|
}
|
|
66
|
-
|
|
86
|
+
let rawOffset = 0;
|
|
87
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
88
|
+
const lineWithPotentialCr = lines[lineIndex];
|
|
67
89
|
i++;
|
|
90
|
+
const lineStartRawOffset = rawOffset;
|
|
91
|
+
const hasLf = lineIndex < lines.length - 1;
|
|
92
|
+
const lineTokenStart = rawTokens.length;
|
|
93
|
+
const tokenizeResult = tokenizeRawLine(rawText, rawTokens, lineStartRawOffset, lineWithPotentialCr, hasLf);
|
|
94
|
+
const lineTokenEnd = rawTokens.length;
|
|
95
|
+
// Maintain legacy parsing behavior: treat CRLF as LF-delimited lines with a trailing '\r' in the line text.
|
|
96
|
+
let line = lineWithPotentialCr;
|
|
68
97
|
if (line.length > 0 && line.charAt(line.length - 1) === '\r') {
|
|
69
98
|
line = line.substr(0, line.length - 1);
|
|
70
99
|
}
|
|
71
100
|
if (line.substr(0, 4) === '////') {
|
|
72
101
|
const text = line.substr(4);
|
|
73
|
-
|
|
102
|
+
currentFileTokenRanges.push({ startToken: lineTokenStart, endToken: lineTokenEnd });
|
|
103
|
+
if (currentFileContent === undefined) {
|
|
104
|
+
currentFileContent = text;
|
|
105
|
+
currentFileContentToRawSegments = [
|
|
106
|
+
{
|
|
107
|
+
contentStart: 0,
|
|
108
|
+
contentEnd: text.length,
|
|
109
|
+
rawStart: lineStartRawOffset + 4,
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const newlineContentOffset = currentFileContent.length;
|
|
115
|
+
currentFileContent = currentFileContent + '\n' + text;
|
|
116
|
+
if (lastFourSlashLineLfOffset === undefined) {
|
|
117
|
+
throw new Error(`Missing line feed mapping for four-slash line ending at line ${i - 1}`);
|
|
118
|
+
}
|
|
119
|
+
currentFileContentToRawSegments.push({
|
|
120
|
+
contentStart: newlineContentOffset,
|
|
121
|
+
contentEnd: newlineContentOffset + 1,
|
|
122
|
+
rawStart: lastFourSlashLineLfOffset,
|
|
123
|
+
});
|
|
124
|
+
const textContentStart = newlineContentOffset + 1;
|
|
125
|
+
currentFileContentToRawSegments.push({
|
|
126
|
+
contentStart: textContentStart,
|
|
127
|
+
contentEnd: textContentStart + text.length,
|
|
128
|
+
rawStart: lineStartRawOffset + 4,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// Record the raw offset of the '\n' for this line (used if another four-slash line follows).
|
|
132
|
+
lastFourSlashLineLfOffset = hasLf ? lineStartRawOffset + lineWithPotentialCr.length : undefined;
|
|
74
133
|
}
|
|
75
134
|
else if (line.substr(0, 3) === '///' && currentFileContent !== undefined) {
|
|
76
135
|
throw new Error(`Three-slash line in the middle of four-slash region at line ${i}`);
|
|
77
136
|
}
|
|
78
137
|
else if (line.substr(0, 2) === '//') {
|
|
79
138
|
// Comment line, check for global/file @options and record them
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
82
|
-
const key =
|
|
83
|
-
const value =
|
|
139
|
+
const directive = tryParseOptionDirective(line.substr(2));
|
|
140
|
+
if (directive) {
|
|
141
|
+
const key = directive.key.toLowerCase();
|
|
142
|
+
const value = directive.value;
|
|
143
|
+
const directiveRawData = tokenizeResult.directiveRawData;
|
|
84
144
|
if (!(0, collectionUtils_1.contains)(fourSlashTypes_1.fileMetadataNames, key)) {
|
|
85
145
|
// Check if the match is already existed in the global options
|
|
86
146
|
if (globalOptions[key] !== undefined) {
|
|
87
147
|
throw new Error(`Global option '${key}' already exists`);
|
|
88
148
|
}
|
|
89
149
|
globalOptions[key] = value;
|
|
150
|
+
if (directiveRawData) {
|
|
151
|
+
globalOptionsRawData[key] = directiveRawData;
|
|
152
|
+
}
|
|
90
153
|
if (key === "projectroot" /* GlobalMetadataOptionNames.projectRoot */) {
|
|
91
154
|
normalizedProjectRoot = (0, pathUtils_1.combinePaths)(normalizedBasePath, value);
|
|
92
155
|
}
|
|
@@ -101,11 +164,17 @@ function parseTestData(basePath, contents, fileName) {
|
|
|
101
164
|
? normalizedPath
|
|
102
165
|
: (0, pathUtils_1.combinePaths)(normalizedProjectRoot, normalizedPath);
|
|
103
166
|
currentFileOptions[key] = value;
|
|
167
|
+
if (directiveRawData) {
|
|
168
|
+
currentFileOptionsRawData[key] = directiveRawData;
|
|
169
|
+
}
|
|
104
170
|
break;
|
|
105
171
|
}
|
|
106
172
|
default:
|
|
107
173
|
// Add other fileMetadata flag
|
|
108
174
|
currentFileOptions[key] = value;
|
|
175
|
+
if (directiveRawData) {
|
|
176
|
+
currentFileOptionsRawData[key] = directiveRawData;
|
|
177
|
+
}
|
|
109
178
|
}
|
|
110
179
|
}
|
|
111
180
|
}
|
|
@@ -117,14 +186,265 @@ function parseTestData(basePath, contents, fileName) {
|
|
|
117
186
|
// Code line, terminate current subfile if there is one
|
|
118
187
|
nextFile();
|
|
119
188
|
}
|
|
189
|
+
rawOffset += lineWithPotentialCr.length + (hasLf ? 1 : 0);
|
|
120
190
|
}
|
|
121
191
|
return {
|
|
122
192
|
markerPositions,
|
|
123
193
|
markers,
|
|
124
194
|
globalOptions,
|
|
195
|
+
globalOptionsRawData,
|
|
125
196
|
files,
|
|
126
197
|
ranges,
|
|
198
|
+
rawText,
|
|
199
|
+
rawTokens,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function tryParseOptionDirective(textAfterTwoSlash) {
|
|
203
|
+
// Matches the legacy behavior of: /^\s*@(\w+):\s*(.*)\s*/
|
|
204
|
+
let i = 0;
|
|
205
|
+
while (i < textAfterTwoSlash.length && /\s/.test(textAfterTwoSlash[i])) {
|
|
206
|
+
i++;
|
|
207
|
+
}
|
|
208
|
+
if (i >= textAfterTwoSlash.length || textAfterTwoSlash[i] !== '@') {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
i++;
|
|
212
|
+
const nameStart = i;
|
|
213
|
+
while (i < textAfterTwoSlash.length && /\w/.test(textAfterTwoSlash[i])) {
|
|
214
|
+
i++;
|
|
215
|
+
}
|
|
216
|
+
if (i === nameStart) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
const key = textAfterTwoSlash.substring(nameStart, i);
|
|
220
|
+
while (i < textAfterTwoSlash.length && /\s/.test(textAfterTwoSlash[i])) {
|
|
221
|
+
i++;
|
|
222
|
+
}
|
|
223
|
+
if (i >= textAfterTwoSlash.length || textAfterTwoSlash[i] !== ':') {
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
i++;
|
|
227
|
+
while (i < textAfterTwoSlash.length && /\s/.test(textAfterTwoSlash[i])) {
|
|
228
|
+
i++;
|
|
229
|
+
}
|
|
230
|
+
const valueStart = i;
|
|
231
|
+
let valueEnd = textAfterTwoSlash.length;
|
|
232
|
+
while (valueEnd > valueStart && /\s/.test(textAfterTwoSlash[valueEnd - 1])) {
|
|
233
|
+
valueEnd--;
|
|
234
|
+
}
|
|
235
|
+
const value = textAfterTwoSlash.substring(valueStart, valueEnd);
|
|
236
|
+
return { key, value };
|
|
237
|
+
}
|
|
238
|
+
function tokenizeRawLine(rawText, rawTokens, lineStartRawOffset, lineTextIncludingOptionalCR, hasLf) {
|
|
239
|
+
const lineTokenStart = rawTokens.length;
|
|
240
|
+
const hasCr = lineTextIncludingOptionalCR.length > 0 && lineTextIncludingOptionalCR.endsWith('\r');
|
|
241
|
+
const lineBody = hasCr
|
|
242
|
+
? lineTextIncludingOptionalCR.substring(0, lineTextIncludingOptionalCR.length - 1)
|
|
243
|
+
: lineTextIncludingOptionalCR;
|
|
244
|
+
const lineBodyStart = lineStartRawOffset;
|
|
245
|
+
const lineBodyEnd = lineStartRawOffset + lineBody.length;
|
|
246
|
+
let directiveRawData;
|
|
247
|
+
const push = (kind, start, end) => {
|
|
248
|
+
if (start < end) {
|
|
249
|
+
rawTokens.push({ kind, start, end });
|
|
250
|
+
}
|
|
127
251
|
};
|
|
252
|
+
const tokenizePlain = (start, end) => {
|
|
253
|
+
let pos = start;
|
|
254
|
+
while (pos < end) {
|
|
255
|
+
const ch = rawText[pos];
|
|
256
|
+
if (ch === ' ' || ch === '\t') {
|
|
257
|
+
const wsStart = pos;
|
|
258
|
+
pos++;
|
|
259
|
+
while (pos < end && (rawText[pos] === ' ' || rawText[pos] === '\t')) {
|
|
260
|
+
pos++;
|
|
261
|
+
}
|
|
262
|
+
push("whitespace" /* RawTokenKind.Whitespace */, wsStart, pos);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
const textStart = pos;
|
|
266
|
+
pos++;
|
|
267
|
+
while (pos < end && rawText[pos] !== ' ' && rawText[pos] !== '\t') {
|
|
268
|
+
pos++;
|
|
269
|
+
}
|
|
270
|
+
push("text" /* RawTokenKind.Text */, textStart, pos);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
if (lineBody.startsWith('////')) {
|
|
275
|
+
push("fourSlashPrefix" /* RawTokenKind.FourSlashPrefix */, lineBodyStart, lineBodyStart + 4);
|
|
276
|
+
tokenizeFourSlashRemainder(rawText, rawTokens, lineBodyStart + 4, lineBodyEnd);
|
|
277
|
+
}
|
|
278
|
+
else if (lineBody.startsWith('//')) {
|
|
279
|
+
const prefixStartToken = rawTokens.length;
|
|
280
|
+
push("twoSlashPrefix" /* RawTokenKind.TwoSlashPrefix */, lineBodyStart, lineBodyStart + 2);
|
|
281
|
+
const afterPrefixStart = lineBodyStart + 2;
|
|
282
|
+
const afterPrefixText = rawText.substring(afterPrefixStart, lineBodyEnd);
|
|
283
|
+
const directive = tryParseOptionDirective(afterPrefixText);
|
|
284
|
+
if (!directive) {
|
|
285
|
+
tokenizePlain(afterPrefixStart, lineBodyEnd);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
const isWhitespaceNotNewline = (ch) => /\s/.test(ch) && ch !== '\r' && ch !== '\n';
|
|
289
|
+
const consumeWhitespaceTokens = (pos, stopChar) => {
|
|
290
|
+
while (pos < lineBodyEnd &&
|
|
291
|
+
isWhitespaceNotNewline(rawText[pos]) &&
|
|
292
|
+
(stopChar === undefined || rawText[pos] !== stopChar)) {
|
|
293
|
+
const wsStart = pos;
|
|
294
|
+
pos++;
|
|
295
|
+
while (pos < lineBodyEnd &&
|
|
296
|
+
isWhitespaceNotNewline(rawText[pos]) &&
|
|
297
|
+
(stopChar === undefined || rawText[pos] !== stopChar)) {
|
|
298
|
+
pos++;
|
|
299
|
+
}
|
|
300
|
+
push("whitespace" /* RawTokenKind.Whitespace */, wsStart, pos);
|
|
301
|
+
}
|
|
302
|
+
return pos;
|
|
303
|
+
};
|
|
304
|
+
// Tokenize with directive structure. This keeps token spans aligned to the stored value.
|
|
305
|
+
let pos = afterPrefixStart;
|
|
306
|
+
// Leading whitespace.
|
|
307
|
+
pos = consumeWhitespaceTokens(pos);
|
|
308
|
+
const atStartToken = rawTokens.length;
|
|
309
|
+
push("directiveAt" /* RawTokenKind.DirectiveAt */, pos, pos + 1);
|
|
310
|
+
pos++;
|
|
311
|
+
const nameStart = pos;
|
|
312
|
+
while (pos < lineBodyEnd && /\w/.test(rawText[pos])) {
|
|
313
|
+
pos++;
|
|
314
|
+
}
|
|
315
|
+
const nameTokenIndex = rawTokens.length;
|
|
316
|
+
push("directiveName" /* RawTokenKind.DirectiveName */, nameStart, pos);
|
|
317
|
+
// Whitespace before ':'
|
|
318
|
+
pos = consumeWhitespaceTokens(pos, ':');
|
|
319
|
+
const colonTokenIndex = rawTokens.length;
|
|
320
|
+
push("directiveColon" /* RawTokenKind.DirectiveColon */, pos, pos + 1);
|
|
321
|
+
pos++;
|
|
322
|
+
// Whitespace after ':'
|
|
323
|
+
pos = consumeWhitespaceTokens(pos);
|
|
324
|
+
const valueStart = pos;
|
|
325
|
+
let valueEnd = lineBodyEnd;
|
|
326
|
+
while (valueEnd > valueStart && /\s/.test(rawText[valueEnd - 1])) {
|
|
327
|
+
valueEnd--;
|
|
328
|
+
}
|
|
329
|
+
const valueTokenStart = rawTokens.length;
|
|
330
|
+
push("directiveValue" /* RawTokenKind.DirectiveValue */, valueStart, valueEnd);
|
|
331
|
+
const valueTokenEnd = rawTokens.length;
|
|
332
|
+
// Trailing whitespace.
|
|
333
|
+
tokenizePlain(valueEnd, lineBodyEnd);
|
|
334
|
+
directiveRawData = {
|
|
335
|
+
directiveLine: { startToken: lineTokenStart, endToken: -1 },
|
|
336
|
+
prefix: { startToken: prefixStartToken, endToken: prefixStartToken + 1 },
|
|
337
|
+
name: { startToken: atStartToken, endToken: nameTokenIndex + 1 },
|
|
338
|
+
colon: { startToken: colonTokenIndex, endToken: colonTokenIndex + 1 },
|
|
339
|
+
value: { startToken: valueTokenStart, endToken: valueTokenEnd },
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
tokenizePlain(lineBodyStart, lineBodyEnd);
|
|
345
|
+
}
|
|
346
|
+
// CR and LF are tokenized separately.
|
|
347
|
+
if (hasCr) {
|
|
348
|
+
push("newlineCR" /* RawTokenKind.NewLineCR */, lineBodyEnd, lineBodyEnd + 1);
|
|
349
|
+
}
|
|
350
|
+
if (hasLf) {
|
|
351
|
+
const lfStart = lineStartRawOffset + lineTextIncludingOptionalCR.length;
|
|
352
|
+
push("newlineLF" /* RawTokenKind.NewLineLF */, lfStart, lfStart + 1);
|
|
353
|
+
}
|
|
354
|
+
const lineTokenEnd = rawTokens.length;
|
|
355
|
+
if (directiveRawData) {
|
|
356
|
+
directiveRawData.directiveLine.endToken = lineTokenEnd;
|
|
357
|
+
}
|
|
358
|
+
return { directiveRawData };
|
|
359
|
+
}
|
|
360
|
+
function tokenizeFourSlashRemainder(rawText, rawTokens, start, end) {
|
|
361
|
+
const push = (kind, s, e) => {
|
|
362
|
+
if (s < e) {
|
|
363
|
+
rawTokens.push({ kind, start: s, end: e });
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
const validMarkerChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$1234567890_';
|
|
367
|
+
let pos = start;
|
|
368
|
+
while (pos < end) {
|
|
369
|
+
const ch = rawText[pos];
|
|
370
|
+
if (ch === ' ' || ch === '\t') {
|
|
371
|
+
const wsStart = pos;
|
|
372
|
+
pos++;
|
|
373
|
+
while (pos < end && (rawText[pos] === ' ' || rawText[pos] === '\t')) {
|
|
374
|
+
pos++;
|
|
375
|
+
}
|
|
376
|
+
push("whitespace" /* RawTokenKind.Whitespace */, wsStart, pos);
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
// Range delimiters.
|
|
380
|
+
if (pos + 1 < end && rawText[pos] === '[' && rawText[pos + 1] === '|') {
|
|
381
|
+
push("rangeStart" /* RawTokenKind.RangeStart */, pos, pos + 2);
|
|
382
|
+
pos += 2;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (pos + 1 < end && rawText[pos] === '|' && rawText[pos + 1] === ']') {
|
|
386
|
+
push("rangeEnd" /* RawTokenKind.RangeEnd */, pos, pos + 2);
|
|
387
|
+
pos += 2;
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
// Object markers.
|
|
391
|
+
if (pos + 1 < end && rawText[pos] === '{' && rawText[pos + 1] === '|') {
|
|
392
|
+
const closeIndex = rawText.indexOf('|}', pos + 2);
|
|
393
|
+
if (closeIndex >= 0 && closeIndex + 2 <= end) {
|
|
394
|
+
push("objectMarkerStart" /* RawTokenKind.ObjectMarkerStart */, pos, pos + 2);
|
|
395
|
+
if (pos + 2 < closeIndex) {
|
|
396
|
+
push("objectMarkerText" /* RawTokenKind.ObjectMarkerText */, pos + 2, closeIndex);
|
|
397
|
+
}
|
|
398
|
+
push("objectMarkerEnd" /* RawTokenKind.ObjectMarkerEnd */, closeIndex, closeIndex + 2);
|
|
399
|
+
pos = closeIndex + 2;
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
// Slash-star markers.
|
|
404
|
+
if (pos + 1 < end && rawText[pos] === '/' && rawText[pos + 1] === '*') {
|
|
405
|
+
const closeIndex = rawText.indexOf('*/', pos + 2);
|
|
406
|
+
if (closeIndex >= 0 && closeIndex + 2 <= end) {
|
|
407
|
+
let isValidMarker = true;
|
|
408
|
+
for (let j = pos + 2; j < closeIndex; j++) {
|
|
409
|
+
if (validMarkerChars.indexOf(rawText[j]) < 0) {
|
|
410
|
+
isValidMarker = false;
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (isValidMarker) {
|
|
415
|
+
push("markerStart" /* RawTokenKind.MarkerStart */, pos, pos + 2);
|
|
416
|
+
if (pos + 2 < closeIndex) {
|
|
417
|
+
push("markerName" /* RawTokenKind.MarkerName */, pos + 2, closeIndex);
|
|
418
|
+
}
|
|
419
|
+
push("markerEnd" /* RawTokenKind.MarkerEnd */, closeIndex, closeIndex + 2);
|
|
420
|
+
pos = closeIndex + 2;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// Plain text chunk until whitespace or a known delimiter.
|
|
426
|
+
const textStart = pos;
|
|
427
|
+
pos++;
|
|
428
|
+
while (pos < end) {
|
|
429
|
+
const c = rawText[pos];
|
|
430
|
+
if (c === ' ' || c === '\t') {
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
if (pos + 1 < end) {
|
|
434
|
+
const c2 = rawText[pos + 1];
|
|
435
|
+
if ((c === '[' && c2 === '|') ||
|
|
436
|
+
(c === '|' && c2 === ']') ||
|
|
437
|
+
(c === '{' && c2 === '|') ||
|
|
438
|
+
(c === '|' && c2 === '}') ||
|
|
439
|
+
(c === '/' && c2 === '*') ||
|
|
440
|
+
(c === '*' && c2 === '/')) {
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
pos++;
|
|
445
|
+
}
|
|
446
|
+
push("text" /* RawTokenKind.Text */, textStart, pos);
|
|
447
|
+
}
|
|
128
448
|
}
|
|
129
449
|
var State;
|
|
130
450
|
(function (State) {
|
|
@@ -136,37 +456,43 @@ function reportError(fileName, line, col, message) {
|
|
|
136
456
|
const errorMessage = `${fileName}(${line},${col}): ${message}`;
|
|
137
457
|
throw new Error(errorMessage);
|
|
138
458
|
}
|
|
139
|
-
function recordObjectMarker(fileName, ignoreCase, location, text, markerMap, markers) {
|
|
459
|
+
function recordObjectMarker(fileName, ignoreCase, location, text, markerMap, markers, rawData) {
|
|
140
460
|
let markerValue;
|
|
141
461
|
try {
|
|
142
462
|
// Attempt to parse the marker value as JSON
|
|
143
463
|
markerValue = JSON.parse('{ ' + text + ' }');
|
|
144
464
|
}
|
|
145
465
|
catch (e) {
|
|
146
|
-
|
|
466
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
467
|
+
reportError(fileName, location.sourceLine, location.sourceColumn, `Unable to parse marker text ${message}`);
|
|
147
468
|
}
|
|
148
|
-
if (markerValue === undefined) {
|
|
469
|
+
if (markerValue === undefined || markerValue === null || typeof markerValue !== 'object') {
|
|
149
470
|
reportError(fileName, location.sourceLine, location.sourceColumn, 'Object markers can not be empty');
|
|
150
471
|
return undefined;
|
|
151
472
|
}
|
|
473
|
+
const markerData = markerValue;
|
|
152
474
|
const marker = {
|
|
153
475
|
fileName,
|
|
154
476
|
fileUri: uriUtils_1.UriEx.file(fileName, !ignoreCase),
|
|
155
477
|
position: location.position,
|
|
156
|
-
data:
|
|
478
|
+
data: markerData,
|
|
479
|
+
rawData,
|
|
157
480
|
};
|
|
158
481
|
// Object markers can be anonymous
|
|
159
|
-
|
|
160
|
-
|
|
482
|
+
const markerNameValue = markerValue.name;
|
|
483
|
+
if (markerNameValue) {
|
|
484
|
+
// Preserve legacy behavior: this may not be a string at runtime.
|
|
485
|
+
markerMap.set(markerNameValue, marker);
|
|
161
486
|
}
|
|
162
487
|
markers.push(marker);
|
|
163
488
|
return marker;
|
|
164
489
|
}
|
|
165
|
-
function recordMarker(fileName, ignoreCase, location, name, markerMap, markers) {
|
|
490
|
+
function recordMarker(fileName, ignoreCase, location, name, markerMap, markers, rawData) {
|
|
166
491
|
const marker = {
|
|
167
492
|
fileName,
|
|
168
493
|
fileUri: uriUtils_1.UriEx.file(fileName, !ignoreCase),
|
|
169
494
|
position: location.position,
|
|
495
|
+
rawData,
|
|
170
496
|
};
|
|
171
497
|
// Verify markers for uniqueness
|
|
172
498
|
if (markerMap.has(name)) {
|
|
@@ -180,12 +506,14 @@ function recordMarker(fileName, ignoreCase, location, name, markerMap, markers)
|
|
|
180
506
|
return marker;
|
|
181
507
|
}
|
|
182
508
|
}
|
|
183
|
-
function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ranges) {
|
|
184
|
-
content =
|
|
509
|
+
function parseFileContent(content, contentToRawSegments, rawTokens, fileName, ignoreCase, markerMap, markers, ranges) {
|
|
510
|
+
({ content, segments: contentToRawSegments } = chompLeadingSpaceWithMapping(content, contentToRawSegments));
|
|
185
511
|
// Any slash-star comment with a character not in this string is not a marker.
|
|
186
512
|
const validMarkerChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$1234567890_';
|
|
187
513
|
/// The file content (minus metacharacters) so far
|
|
188
514
|
let output = '';
|
|
515
|
+
// Mapping segments for the final FourSlashFile.content -> rawText offsets.
|
|
516
|
+
const contentToRawOutputSegments = [];
|
|
189
517
|
/// The current marker (or maybe multi-line comment?) we're parsing, possibly
|
|
190
518
|
let openMarker;
|
|
191
519
|
/// A stack of the open range markers that are still unclosed
|
|
@@ -202,9 +530,13 @@ function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ran
|
|
|
202
530
|
let line = 1;
|
|
203
531
|
let column = 1;
|
|
204
532
|
const flush = (lastSafeCharIndex) => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
533
|
+
const safeIndex = lastSafeCharIndex ?? content.length;
|
|
534
|
+
if (safeIndex <= lastNormalCharPosition) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const outputStart = output.length;
|
|
538
|
+
output = output + content.substring(lastNormalCharPosition, safeIndex);
|
|
539
|
+
appendOutputMappingSegments(contentToRawSegments, lastNormalCharPosition, safeIndex, outputStart, contentToRawOutputSegments);
|
|
208
540
|
};
|
|
209
541
|
if (content.length > 0) {
|
|
210
542
|
let previousChar = content.charAt(0);
|
|
@@ -214,11 +546,13 @@ function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ran
|
|
|
214
546
|
case 0 /* State.none */:
|
|
215
547
|
if (previousChar === '[' && currentChar === '|') {
|
|
216
548
|
// found a range start
|
|
549
|
+
const rawOpen = getRawSpanFromContentSpan(contentToRawSegments, i - 1, i + 1);
|
|
217
550
|
openRanges.push({
|
|
218
551
|
position: i - 1 - difference,
|
|
219
552
|
sourcePosition: i - 1,
|
|
220
553
|
sourceLine: line,
|
|
221
554
|
sourceColumn: column,
|
|
555
|
+
rawOpen,
|
|
222
556
|
});
|
|
223
557
|
// copy all text up to marker position
|
|
224
558
|
flush(i - 1);
|
|
@@ -231,12 +565,23 @@ function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ran
|
|
|
231
565
|
if (!rangeStart) {
|
|
232
566
|
reportError(fileName, line, column, 'Found range end with no matching start.');
|
|
233
567
|
}
|
|
568
|
+
const rawClose = getRawSpanFromContentSpan(contentToRawSegments, i - 1, i + 1);
|
|
569
|
+
const rawSelectedStart = rangeStart.rawOpen?.rawEnd ?? rawClose.rawStart;
|
|
570
|
+
const rawSelectedEnd = rawClose.rawStart;
|
|
571
|
+
const rawFullStart = rangeStart.rawOpen?.rawStart ?? rawClose.rawStart;
|
|
572
|
+
const rawFullEnd = rawClose.rawEnd;
|
|
234
573
|
const range = {
|
|
235
574
|
fileName,
|
|
236
575
|
fileUri: uriUtils_1.UriEx.file(fileName, !ignoreCase),
|
|
237
576
|
pos: rangeStart.position,
|
|
238
577
|
end: i - 1 - difference,
|
|
239
578
|
marker: rangeStart.marker,
|
|
579
|
+
rawData: {
|
|
580
|
+
full: getTokenRangeCoveringRawSpan(rawTokens, rawFullStart, rawFullEnd),
|
|
581
|
+
open: getTokenRangeCoveringRawSpan(rawTokens, rangeStart.rawOpen?.rawStart ?? rawClose.rawStart, rangeStart.rawOpen?.rawEnd ?? rawClose.rawStart),
|
|
582
|
+
selected: getTokenRangeCoveringRawSpan(rawTokens, rawSelectedStart, rawSelectedEnd),
|
|
583
|
+
close: getTokenRangeCoveringRawSpan(rawTokens, rawClose.rawStart, rawClose.rawEnd),
|
|
584
|
+
},
|
|
240
585
|
};
|
|
241
586
|
localRanges.push(range);
|
|
242
587
|
// copy all text up to range marker position
|
|
@@ -269,9 +614,19 @@ function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ran
|
|
|
269
614
|
case 2 /* State.inObjectMarker */:
|
|
270
615
|
// Object markers are only ever terminated by |} and have no content restrictions
|
|
271
616
|
if (previousChar === '|' && currentChar === '}') {
|
|
617
|
+
const rawFull = getRawSpanFromContentSpan(contentToRawSegments, openMarker.sourcePosition, i + 1);
|
|
618
|
+
const rawStart = getRawSpanFromContentSpan(contentToRawSegments, openMarker.sourcePosition, openMarker.sourcePosition + 2);
|
|
619
|
+
const rawEnd = getRawSpanFromContentSpan(contentToRawSegments, i - 1, i + 1);
|
|
620
|
+
const rawTextSpan = getRawSpanFromContentSpan(contentToRawSegments, openMarker.sourcePosition + 2, i - 1);
|
|
272
621
|
// Record the marker
|
|
273
622
|
const objectMarkerNameText = content.substring(openMarker.sourcePosition + 2, i - 1).trim();
|
|
274
|
-
const marker = recordObjectMarker(fileName, ignoreCase, openMarker, objectMarkerNameText, markerMap, markers
|
|
623
|
+
const marker = recordObjectMarker(fileName, ignoreCase, openMarker, objectMarkerNameText, markerMap, markers, {
|
|
624
|
+
kind: 'object',
|
|
625
|
+
full: getTokenRangeCoveringRawSpan(rawTokens, rawFull.rawStart, rawFull.rawEnd),
|
|
626
|
+
start: getTokenRangeCoveringRawSpan(rawTokens, rawStart.rawStart, rawStart.rawEnd),
|
|
627
|
+
text: getTokenRangeCoveringRawSpan(rawTokens, rawTextSpan.rawStart, rawTextSpan.rawEnd),
|
|
628
|
+
end: getTokenRangeCoveringRawSpan(rawTokens, rawEnd.rawStart, rawEnd.rawEnd),
|
|
629
|
+
});
|
|
275
630
|
if (openRanges.length > 0) {
|
|
276
631
|
openRanges[openRanges.length - 1].marker = marker;
|
|
277
632
|
}
|
|
@@ -285,10 +640,20 @@ function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ran
|
|
|
285
640
|
break;
|
|
286
641
|
case 1 /* State.inSlashStarMarker */:
|
|
287
642
|
if (previousChar === '*' && currentChar === '/') {
|
|
643
|
+
const rawFull = getRawSpanFromContentSpan(contentToRawSegments, openMarker.sourcePosition, i + 1);
|
|
644
|
+
const rawStart = getRawSpanFromContentSpan(contentToRawSegments, openMarker.sourcePosition, openMarker.sourcePosition + 2);
|
|
645
|
+
const rawEnd = getRawSpanFromContentSpan(contentToRawSegments, i - 1, i + 1);
|
|
646
|
+
const rawNameSpan = getRawSpanFromContentSpan(contentToRawSegments, openMarker.sourcePosition + 2, i - 1);
|
|
288
647
|
// Record the marker
|
|
289
648
|
// start + 2 to ignore the */, -1 on the end to ignore the * (/ is next)
|
|
290
649
|
const markerNameText = content.substring(openMarker.sourcePosition + 2, i - 1).trim();
|
|
291
|
-
const marker = recordMarker(fileName, ignoreCase, openMarker, markerNameText, markerMap, markers
|
|
650
|
+
const marker = recordMarker(fileName, ignoreCase, openMarker, markerNameText, markerMap, markers, {
|
|
651
|
+
kind: 'slashStar',
|
|
652
|
+
full: getTokenRangeCoveringRawSpan(rawTokens, rawFull.rawStart, rawFull.rawEnd),
|
|
653
|
+
start: getTokenRangeCoveringRawSpan(rawTokens, rawStart.rawStart, rawStart.rawEnd),
|
|
654
|
+
name: getTokenRangeCoveringRawSpan(rawTokens, rawNameSpan.rawStart, rawNameSpan.rawEnd),
|
|
655
|
+
end: getTokenRangeCoveringRawSpan(rawTokens, rawEnd.rawStart, rawEnd.rawEnd),
|
|
656
|
+
});
|
|
292
657
|
if (openRanges.length > 0) {
|
|
293
658
|
openRanges[openRanges.length - 1].marker = marker;
|
|
294
659
|
}
|
|
@@ -342,21 +707,113 @@ function parseFileContent(content, fileName, ignoreCase, markerMap, markers, ran
|
|
|
342
707
|
localRanges.forEach((r) => {
|
|
343
708
|
ranges.push(r);
|
|
344
709
|
});
|
|
710
|
+
const contentToRaw = { segments: contentToRawOutputSegments };
|
|
711
|
+
const rawToContent = { segments: contentToRawOutputSegments };
|
|
345
712
|
return {
|
|
346
713
|
content: output,
|
|
347
714
|
fileOptions: {},
|
|
348
715
|
version: 0,
|
|
349
716
|
fileName,
|
|
350
717
|
fileUri: uriUtils_1.UriEx.file(fileName, !ignoreCase),
|
|
718
|
+
rawData: {
|
|
719
|
+
tokenRanges: [],
|
|
720
|
+
rawToContent,
|
|
721
|
+
contentToRaw,
|
|
722
|
+
},
|
|
351
723
|
};
|
|
352
724
|
}
|
|
353
|
-
function
|
|
725
|
+
function getRawSpanFromContentSpan(segments, contentStart, contentEnd) {
|
|
726
|
+
if (contentStart === contentEnd) {
|
|
727
|
+
const rawOffset = tryGetRawOffsetFromContentIndex(segments, contentStart) ?? 0;
|
|
728
|
+
return { rawStart: rawOffset, rawEnd: rawOffset };
|
|
729
|
+
}
|
|
730
|
+
const rawStart = tryGetRawOffsetFromContentIndex(segments, contentStart) ?? 0;
|
|
731
|
+
const rawLast = tryGetRawOffsetFromContentIndex(segments, contentEnd - 1) ?? rawStart;
|
|
732
|
+
return { rawStart, rawEnd: rawLast + 1 };
|
|
733
|
+
}
|
|
734
|
+
function tryGetRawOffsetFromContentIndex(segments, contentIndex) {
|
|
735
|
+
const seg = (0, fourSlashRawUtils_1.findItemContainingOffset)(segments, contentIndex, (s) => s.contentStart, (s) => s.contentEnd);
|
|
736
|
+
if (!seg) {
|
|
737
|
+
return undefined;
|
|
738
|
+
}
|
|
739
|
+
return seg.rawStart + (contentIndex - seg.contentStart);
|
|
740
|
+
}
|
|
741
|
+
function getTokenRangeCoveringRawSpan(rawTokens, rawStart, rawEnd) {
|
|
742
|
+
if (rawStart === rawEnd) {
|
|
743
|
+
const tokenIndex = (0, fourSlashRawUtils_1.findTokenIndexAtOrAfter)(rawTokens, rawStart);
|
|
744
|
+
return { startToken: tokenIndex, endToken: tokenIndex };
|
|
745
|
+
}
|
|
746
|
+
const startToken = (0, fourSlashRawUtils_1.findTokenIndexAtOrAfter)(rawTokens, rawStart);
|
|
747
|
+
const endToken = (0, fourSlashRawUtils_1.findTokenIndexAtOrAfter)(rawTokens, rawEnd);
|
|
748
|
+
return { startToken, endToken };
|
|
749
|
+
}
|
|
750
|
+
function appendOutputMappingSegments(sourceSegments, sourceStart, sourceEnd, outputStart, out) {
|
|
751
|
+
for (const seg of sourceSegments) {
|
|
752
|
+
const overlapStart = Math.max(sourceStart, seg.contentStart);
|
|
753
|
+
const overlapEnd = Math.min(sourceEnd, seg.contentEnd);
|
|
754
|
+
if (overlapStart >= overlapEnd) {
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
const overlapLen = overlapEnd - overlapStart;
|
|
758
|
+
const rawStart = seg.rawStart + (overlapStart - seg.contentStart);
|
|
759
|
+
const contentStart = outputStart + (overlapStart - sourceStart);
|
|
760
|
+
out.push({
|
|
761
|
+
rawStart,
|
|
762
|
+
rawEnd: rawStart + overlapLen,
|
|
763
|
+
contentStart,
|
|
764
|
+
contentEnd: contentStart + overlapLen,
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
function chompLeadingSpaceWithMapping(content, contentToRawSegments) {
|
|
354
769
|
const lines = content.split('\n');
|
|
355
770
|
for (const line of lines) {
|
|
356
771
|
if (line.length !== 0 && line.charAt(0) !== ' ') {
|
|
357
|
-
return content;
|
|
772
|
+
return { content, segments: contentToRawSegments };
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
// Remove one leading space from each line.
|
|
776
|
+
const newContent = lines.map((s) => s.substr(1)).join('\n');
|
|
777
|
+
// Rebuild mapping segments by walking line-by-line over the original content.
|
|
778
|
+
const newSegments = [];
|
|
779
|
+
let sourcePos = 0;
|
|
780
|
+
let outPos = 0;
|
|
781
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
782
|
+
const line = lines[lineIndex];
|
|
783
|
+
const lineStart = sourcePos;
|
|
784
|
+
const lineEnd = lineStart + line.length;
|
|
785
|
+
// Keep everything after the removed leading space.
|
|
786
|
+
if (line.length > 0) {
|
|
787
|
+
const keepStart = lineStart + 1;
|
|
788
|
+
const keepEnd = lineEnd;
|
|
789
|
+
appendChompedSegments(contentToRawSegments, keepStart, keepEnd, outPos, newSegments);
|
|
790
|
+
outPos += keepEnd - keepStart;
|
|
791
|
+
}
|
|
792
|
+
sourcePos = lineEnd;
|
|
793
|
+
// Keep newline except for the final line.
|
|
794
|
+
if (lineIndex < lines.length - 1) {
|
|
795
|
+
appendChompedSegments(contentToRawSegments, sourcePos, sourcePos + 1, outPos, newSegments);
|
|
796
|
+
sourcePos += 1;
|
|
797
|
+
outPos += 1;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return { content: newContent, segments: newSegments };
|
|
801
|
+
}
|
|
802
|
+
function appendChompedSegments(sourceSegments, sourceStart, sourceEnd, outputStart, out) {
|
|
803
|
+
for (const seg of sourceSegments) {
|
|
804
|
+
const overlapStart = Math.max(sourceStart, seg.contentStart);
|
|
805
|
+
const overlapEnd = Math.min(sourceEnd, seg.contentEnd);
|
|
806
|
+
if (overlapStart >= overlapEnd) {
|
|
807
|
+
continue;
|
|
358
808
|
}
|
|
809
|
+
const overlapLen = overlapEnd - overlapStart;
|
|
810
|
+
const rawStart = seg.rawStart + (overlapStart - seg.contentStart);
|
|
811
|
+
const contentStart = outputStart + (overlapStart - sourceStart);
|
|
812
|
+
out.push({
|
|
813
|
+
contentStart,
|
|
814
|
+
contentEnd: contentStart + overlapLen,
|
|
815
|
+
rawStart,
|
|
816
|
+
});
|
|
359
817
|
}
|
|
360
|
-
return lines.map((s) => s.substr(1)).join('\n');
|
|
361
818
|
}
|
|
362
819
|
//# sourceMappingURL=fourSlashParser.js.map
|