tsifdef 1.1.8
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/CHANGELOG.md +25 -0
- package/CHANGELOG.zh-CN.md +22 -0
- package/CONTRIBUTING.md +52 -0
- package/INTEGRATION.md +166 -0
- package/INTEGRATION.zh-CN.md +159 -0
- package/LICENSE +210 -0
- package/README.md +150 -0
- package/README.zh-CN.md +141 -0
- package/SECURITY.md +15 -0
- package/assets/icon-mono.svg +15 -0
- package/assets/icon.png +0 -0
- package/assets/icon.svg +16 -0
- package/dist/cli/build.d.ts +70 -0
- package/dist/cli/build.js +298 -0
- package/dist/cli/config.d.ts +30 -0
- package/dist/cli/config.js +135 -0
- package/dist/cli/diagnostics.d.ts +3 -0
- package/dist/cli/diagnostics.js +31 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/main.d.ts +9 -0
- package/dist/cli/main.js +165 -0
- package/dist/cli/precompile.d.ts +38 -0
- package/dist/cli/precompile.js +192 -0
- package/dist/cli/source-files.d.ts +10 -0
- package/dist/cli/source-files.js +75 -0
- package/dist/cli/watch.d.ts +34 -0
- package/dist/cli/watch.js +183 -0
- package/dist/core/conditional.d.ts +18 -0
- package/dist/core/conditional.js +126 -0
- package/dist/core/expression.d.ts +44 -0
- package/dist/core/expression.js +224 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +37 -0
- package/dist/core/projection.d.ts +15 -0
- package/dist/core/projection.js +99 -0
- package/dist/core/scanner.d.ts +33 -0
- package/dist/core/scanner.js +344 -0
- package/dist/eslint/package.d.ts +10 -0
- package/dist/eslint/package.js +55 -0
- package/dist/eslint/parser.d.ts +35 -0
- package/dist/eslint/parser.js +59 -0
- package/dist/eslint/plugin.d.ts +78 -0
- package/dist/eslint/plugin.js +229 -0
- package/dist/eslint/projection.d.ts +11 -0
- package/dist/eslint/projection.js +116 -0
- package/dist/tsserver/host-projection.d.ts +45 -0
- package/dist/tsserver/host-projection.js +160 -0
- package/dist/tsserver/index.d.ts +3 -0
- package/dist/tsserver/index.js +32 -0
- package/dist/tsserver/plugin.d.ts +15 -0
- package/dist/tsserver/plugin.js +129 -0
- package/dist/tsserver/project-controller.d.ts +37 -0
- package/dist/tsserver/project-controller.js +60 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.js +20 -0
- package/dist/vscode/document-analysis.d.ts +62 -0
- package/dist/vscode/document-analysis.js +111 -0
- package/dist/vscode/extension.d.ts +133 -0
- package/dist/vscode/extension.js +241 -0
- package/dist/vscode/host.d.ts +79 -0
- package/dist/vscode/host.js +16 -0
- package/dist/vscode/index.d.ts +7 -0
- package/dist/vscode/index.js +36 -0
- package/dist/vscode/macro-presentation.d.ts +43 -0
- package/dist/vscode/macro-presentation.js +130 -0
- package/dist/vscode/package-profile.d.ts +27 -0
- package/dist/vscode/package-profile.js +142 -0
- package/dist/vscode/profile-state.d.ts +22 -0
- package/dist/vscode/profile-state.js +81 -0
- package/package.json +129 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (C) 2026 Tencent. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.projectSource = projectSource;
|
|
17
|
+
exports.maskSourceRanges = maskSourceRanges;
|
|
18
|
+
const conditional_js_1 = require("./conditional.js");
|
|
19
|
+
/** Analyze and project source through the selected macro definitions. */
|
|
20
|
+
function projectSource(source, definitions) {
|
|
21
|
+
const analysis = (0, conditional_js_1.analyzeConditionals)(source, definitions);
|
|
22
|
+
const maskedRanges = normalizeRanges(source.length, analysis.directiveRanges.concat(analysis.inactiveRanges));
|
|
23
|
+
return {
|
|
24
|
+
...analysis,
|
|
25
|
+
projectedText: maskSourceRanges(source, maskedRanges),
|
|
26
|
+
maskedRanges,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Replace non-newline text with whitespace while preserving both UTF-8 byte
|
|
31
|
+
* offsets and UTF-16 editor offsets.
|
|
32
|
+
*/
|
|
33
|
+
function maskSourceRanges(source, ranges) {
|
|
34
|
+
const normalized = normalizeRanges(source.length, ranges);
|
|
35
|
+
const chunks = [];
|
|
36
|
+
let cursor = 0;
|
|
37
|
+
for (const range of normalized) {
|
|
38
|
+
chunks.push(source.slice(cursor, range.start));
|
|
39
|
+
chunks.push(maskText(source.slice(range.start, range.end)));
|
|
40
|
+
cursor = range.end;
|
|
41
|
+
}
|
|
42
|
+
chunks.push(source.slice(cursor));
|
|
43
|
+
return chunks.join("");
|
|
44
|
+
}
|
|
45
|
+
function maskText(source) {
|
|
46
|
+
let result = "";
|
|
47
|
+
for (const character of source) {
|
|
48
|
+
if (character === "\r" || character === "\n") {
|
|
49
|
+
result += character;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const codePoint = character.codePointAt(0);
|
|
53
|
+
if (codePoint <= 0x7f) {
|
|
54
|
+
result += " ";
|
|
55
|
+
}
|
|
56
|
+
else if (codePoint <= 0x7ff) {
|
|
57
|
+
result += "\u00A0";
|
|
58
|
+
}
|
|
59
|
+
else if (codePoint <= 0xffff) {
|
|
60
|
+
result += "\u3000";
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Astral code points occupy four UTF-8 bytes and two UTF-16 code units.
|
|
64
|
+
result += "\u00A0\u00A0";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
function normalizeRanges(sourceLength, ranges) {
|
|
70
|
+
const sorted = ranges.map((range) => {
|
|
71
|
+
if (!Number.isInteger(range.start) ||
|
|
72
|
+
!Number.isInteger(range.end) ||
|
|
73
|
+
range.start < 0 ||
|
|
74
|
+
range.end < range.start ||
|
|
75
|
+
range.end > sourceLength) {
|
|
76
|
+
throw new RangeError(`Invalid source range [${range.start}, ${range.end}) for length ${sourceLength}.`);
|
|
77
|
+
}
|
|
78
|
+
return range;
|
|
79
|
+
});
|
|
80
|
+
sorted.sort((left, right) => left.start - right.start || left.end - right.end);
|
|
81
|
+
const normalized = [];
|
|
82
|
+
for (const range of sorted) {
|
|
83
|
+
if (range.start === range.end) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const previous = normalized.at(-1);
|
|
87
|
+
if (previous !== undefined && range.start <= previous.end) {
|
|
88
|
+
normalized[normalized.length - 1] = {
|
|
89
|
+
start: previous.start,
|
|
90
|
+
end: Math.max(previous.end, range.end),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
normalized.push({ start: range.start, end: range.end });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return normalized;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface SourceRange {
|
|
2
|
+
/** Inclusive UTF-16 offset. */
|
|
3
|
+
readonly start: number;
|
|
4
|
+
/** Exclusive UTF-16 offset. */
|
|
5
|
+
readonly end: number;
|
|
6
|
+
}
|
|
7
|
+
export type DirectiveKind = "if" | "elif" | "else" | "endif" | "error";
|
|
8
|
+
export interface Directive {
|
|
9
|
+
readonly kind: DirectiveKind;
|
|
10
|
+
/** Zero-based physical line number. */
|
|
11
|
+
readonly line: number;
|
|
12
|
+
/** Entire line excluding its line ending. */
|
|
13
|
+
readonly range: SourceRange;
|
|
14
|
+
/** The `#` and directive name. */
|
|
15
|
+
readonly keywordRange: SourceRange;
|
|
16
|
+
readonly argument: string;
|
|
17
|
+
readonly argumentRange: SourceRange | null;
|
|
18
|
+
}
|
|
19
|
+
export type ScannerDiagnosticCode = "unknown-directive" | "unmatched-elif" | "unmatched-else" | "unmatched-endif" | "elif-after-else" | "duplicate-else" | "unterminated-if";
|
|
20
|
+
export interface ScannerDiagnostic {
|
|
21
|
+
readonly code: ScannerDiagnosticCode;
|
|
22
|
+
readonly message: string;
|
|
23
|
+
readonly range: SourceRange;
|
|
24
|
+
}
|
|
25
|
+
export interface ScanResult {
|
|
26
|
+
readonly directives: readonly Directive[];
|
|
27
|
+
/** Every directive-looking line, including unknown directives. */
|
|
28
|
+
readonly directiveRanges: readonly SourceRange[];
|
|
29
|
+
readonly diagnostics: readonly ScannerDiagnostic[];
|
|
30
|
+
}
|
|
31
|
+
/** Scan C/C++-style macro directives without evaluating their expressions. */
|
|
32
|
+
export declare function scanDirectives(source: string): ScanResult;
|
|
33
|
+
//# sourceMappingURL=scanner.d.ts.map
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (C) 2026 Tencent. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.scanDirectives = scanDirectives;
|
|
17
|
+
const directivePattern = /^[\t \v\f\uFEFF]*#(.*)$/;
|
|
18
|
+
const directiveKinds = new Set([
|
|
19
|
+
"if",
|
|
20
|
+
"elif",
|
|
21
|
+
"else",
|
|
22
|
+
"endif",
|
|
23
|
+
"error",
|
|
24
|
+
]);
|
|
25
|
+
const regexPrefixKeywords = new Set([
|
|
26
|
+
"await",
|
|
27
|
+
"case",
|
|
28
|
+
"delete",
|
|
29
|
+
"in",
|
|
30
|
+
"instanceof",
|
|
31
|
+
"new",
|
|
32
|
+
"of",
|
|
33
|
+
"return",
|
|
34
|
+
"throw",
|
|
35
|
+
"typeof",
|
|
36
|
+
"void",
|
|
37
|
+
"yield",
|
|
38
|
+
]);
|
|
39
|
+
/** Scan C/C++-style macro directives without evaluating their expressions. */
|
|
40
|
+
function scanDirectives(source) {
|
|
41
|
+
const directives = [];
|
|
42
|
+
const directiveRanges = [];
|
|
43
|
+
const diagnostics = [];
|
|
44
|
+
const conditionalStack = [];
|
|
45
|
+
const lexicalState = { mode: "code", templates: [] };
|
|
46
|
+
let offset = 0;
|
|
47
|
+
let line = 0;
|
|
48
|
+
while (offset < source.length) {
|
|
49
|
+
const lineEnd = findLineEnd(source, offset);
|
|
50
|
+
const lineText = source.slice(offset, lineEnd);
|
|
51
|
+
const parsedLine = lexicalState.mode === "code"
|
|
52
|
+
? parseDirectiveLine(lineText, offset, line, diagnostics)
|
|
53
|
+
: null;
|
|
54
|
+
if (parsedLine !== null) {
|
|
55
|
+
directiveRanges.push(parsedLine.range);
|
|
56
|
+
if (parsedLine.directive !== null) {
|
|
57
|
+
directives.push(parsedLine.directive);
|
|
58
|
+
checkStructure(parsedLine.directive, conditionalStack, diagnostics);
|
|
59
|
+
}
|
|
60
|
+
// Directive arguments are not TypeScript and cannot change lexical state.
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
scanTypeScriptLine(lineText, lexicalState);
|
|
64
|
+
}
|
|
65
|
+
offset = skipLineEnding(source, lineEnd);
|
|
66
|
+
line += 1;
|
|
67
|
+
}
|
|
68
|
+
for (const frame of conditionalStack) {
|
|
69
|
+
diagnostics.push({
|
|
70
|
+
code: "unterminated-if",
|
|
71
|
+
message: "#if directive has no matching #endif.",
|
|
72
|
+
range: frame.opening.keywordRange,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
diagnostics.sort((left, right) => left.range.start - right.range.start);
|
|
76
|
+
return { directives, directiveRanges, diagnostics };
|
|
77
|
+
}
|
|
78
|
+
function parseDirectiveLine(lineText, lineOffset, line, diagnostics) {
|
|
79
|
+
const match = directivePattern.exec(lineText);
|
|
80
|
+
if (match === null) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const hashIndex = lineText.indexOf("#");
|
|
84
|
+
const lineRange = { start: lineOffset, end: lineOffset + lineText.length };
|
|
85
|
+
const remainder = match[1] ?? "";
|
|
86
|
+
const nameMatch = /^([A-Za-z_][A-Za-z0-9_]*)(.*)$/.exec(remainder);
|
|
87
|
+
const name = nameMatch?.[1];
|
|
88
|
+
if (name === undefined) {
|
|
89
|
+
diagnostics.push({
|
|
90
|
+
code: "unknown-directive",
|
|
91
|
+
message: "Expected a directive name after '#'.",
|
|
92
|
+
range: { start: lineOffset + hashIndex, end: lineOffset + hashIndex + 1 },
|
|
93
|
+
});
|
|
94
|
+
return { directive: null, range: lineRange };
|
|
95
|
+
}
|
|
96
|
+
const keywordRange = {
|
|
97
|
+
start: lineOffset + hashIndex,
|
|
98
|
+
end: lineOffset + hashIndex + name.length + 1,
|
|
99
|
+
};
|
|
100
|
+
const rawArgument = nameMatch?.[2] ?? "";
|
|
101
|
+
if (!directiveKinds.has(name)) {
|
|
102
|
+
if (isTypeScriptPrivateIdentifier(rawArgument)) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
diagnostics.push({
|
|
106
|
+
code: "unknown-directive",
|
|
107
|
+
message: `Unknown directive #${name}.`,
|
|
108
|
+
range: keywordRange,
|
|
109
|
+
});
|
|
110
|
+
return { directive: null, range: lineRange };
|
|
111
|
+
}
|
|
112
|
+
const leadingWhitespace = rawArgument.length - rawArgument.trimStart().length;
|
|
113
|
+
const argument = rawArgument.trim();
|
|
114
|
+
const argumentStart = keywordRange.end + leadingWhitespace;
|
|
115
|
+
return {
|
|
116
|
+
directive: {
|
|
117
|
+
kind: name,
|
|
118
|
+
line,
|
|
119
|
+
range: lineRange,
|
|
120
|
+
keywordRange,
|
|
121
|
+
argument,
|
|
122
|
+
argumentRange: argument.length === 0
|
|
123
|
+
? null
|
|
124
|
+
: { start: argumentStart, end: argumentStart + argument.length },
|
|
125
|
+
},
|
|
126
|
+
range: lineRange,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A private field or method may begin a physical line with `#name`, which is
|
|
131
|
+
* indistinguishable from a directive until the following token is inspected.
|
|
132
|
+
*/
|
|
133
|
+
function isTypeScriptPrivateIdentifier(remainder) {
|
|
134
|
+
const continuation = remainder.trimStart();
|
|
135
|
+
if (continuation.length === 0) {
|
|
136
|
+
// Keep a bare "#name" as an unknown directive. Private members normally
|
|
137
|
+
// have a type, initializer, modifier, terminator, or parameter list.
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return /^(?:[!?:=;(<]|\bin\b)/.test(continuation);
|
|
141
|
+
}
|
|
142
|
+
function checkStructure(directive, stack, diagnostics) {
|
|
143
|
+
const current = stack.at(-1);
|
|
144
|
+
switch (directive.kind) {
|
|
145
|
+
case "if":
|
|
146
|
+
stack.push({ opening: directive, sawElse: false });
|
|
147
|
+
break;
|
|
148
|
+
case "elif":
|
|
149
|
+
if (current === undefined) {
|
|
150
|
+
addStructureDiagnostic(diagnostics, directive, "unmatched-elif", "#elif directive has no matching #if.");
|
|
151
|
+
}
|
|
152
|
+
else if (current.sawElse) {
|
|
153
|
+
addStructureDiagnostic(diagnostics, directive, "elif-after-else", "#elif directive cannot appear after #else.");
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
case "else":
|
|
157
|
+
if (current === undefined) {
|
|
158
|
+
addStructureDiagnostic(diagnostics, directive, "unmatched-else", "#else directive has no matching #if.");
|
|
159
|
+
}
|
|
160
|
+
else if (current.sawElse) {
|
|
161
|
+
addStructureDiagnostic(diagnostics, directive, "duplicate-else", "Conditional block cannot contain more than one #else.");
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
current.sawElse = true;
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
case "endif":
|
|
168
|
+
if (current === undefined) {
|
|
169
|
+
addStructureDiagnostic(diagnostics, directive, "unmatched-endif", "#endif directive has no matching #if.");
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
stack.pop();
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
case "error":
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function addStructureDiagnostic(diagnostics, directive, code, message) {
|
|
180
|
+
diagnostics.push({ code, message, range: directive.keywordRange });
|
|
181
|
+
}
|
|
182
|
+
function findLineEnd(source, start) {
|
|
183
|
+
let offset = start;
|
|
184
|
+
while (offset < source.length) {
|
|
185
|
+
const character = source.charCodeAt(offset);
|
|
186
|
+
if (character === 0x0a || character === 0x0d) {
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
offset += 1;
|
|
190
|
+
}
|
|
191
|
+
return offset;
|
|
192
|
+
}
|
|
193
|
+
function skipLineEnding(source, lineEnd) {
|
|
194
|
+
if (source.charCodeAt(lineEnd) === 0x0d && source.charCodeAt(lineEnd + 1) === 0x0a) {
|
|
195
|
+
return lineEnd + 2;
|
|
196
|
+
}
|
|
197
|
+
return lineEnd < source.length ? lineEnd + 1 : lineEnd;
|
|
198
|
+
}
|
|
199
|
+
function scanTypeScriptLine(line, state) {
|
|
200
|
+
let offset = 0;
|
|
201
|
+
let quoteContinues = false;
|
|
202
|
+
while (offset < line.length) {
|
|
203
|
+
const character = line[offset];
|
|
204
|
+
const next = line[offset + 1];
|
|
205
|
+
if (state.mode === "block-comment") {
|
|
206
|
+
if (character === "*" && next === "/") {
|
|
207
|
+
state.mode = "code";
|
|
208
|
+
offset += 2;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
offset += 1;
|
|
212
|
+
}
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (state.mode === "single-quote" || state.mode === "double-quote") {
|
|
216
|
+
const closingQuote = state.mode === "single-quote" ? "'" : '"';
|
|
217
|
+
if (character === "\\") {
|
|
218
|
+
quoteContinues = offset === line.length - 1;
|
|
219
|
+
offset += 2;
|
|
220
|
+
}
|
|
221
|
+
else if (character === closingQuote) {
|
|
222
|
+
state.mode = "code";
|
|
223
|
+
offset += 1;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
offset += 1;
|
|
227
|
+
}
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (state.mode === "template") {
|
|
231
|
+
if (character === "\\") {
|
|
232
|
+
offset += 2;
|
|
233
|
+
}
|
|
234
|
+
else if (character === "`") {
|
|
235
|
+
state.templates.pop();
|
|
236
|
+
state.mode = "code";
|
|
237
|
+
offset += 1;
|
|
238
|
+
}
|
|
239
|
+
else if (character === "$" && next === "{") {
|
|
240
|
+
const template = state.templates.at(-1);
|
|
241
|
+
if (template !== undefined) {
|
|
242
|
+
template.expressionBraceDepth = 0;
|
|
243
|
+
}
|
|
244
|
+
state.mode = "code";
|
|
245
|
+
offset += 2;
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
offset += 1;
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (character === "/" && next === "/") {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
if (character === "/" && next === "*") {
|
|
256
|
+
state.mode = "block-comment";
|
|
257
|
+
offset += 2;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (character === "/" && isLikelyRegexStart(line, offset)) {
|
|
261
|
+
offset = skipRegexLiteral(line, offset);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (character === "'") {
|
|
265
|
+
state.mode = "single-quote";
|
|
266
|
+
offset += 1;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (character === '"') {
|
|
270
|
+
state.mode = "double-quote";
|
|
271
|
+
offset += 1;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (character === "`") {
|
|
275
|
+
state.templates.push({ expressionBraceDepth: null });
|
|
276
|
+
state.mode = "template";
|
|
277
|
+
offset += 1;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const template = state.templates.at(-1);
|
|
281
|
+
if (template !== undefined && template.expressionBraceDepth !== null) {
|
|
282
|
+
if (character === "{") {
|
|
283
|
+
template.expressionBraceDepth += 1;
|
|
284
|
+
}
|
|
285
|
+
else if (character === "}") {
|
|
286
|
+
if (template.expressionBraceDepth === 0) {
|
|
287
|
+
template.expressionBraceDepth = null;
|
|
288
|
+
state.mode = "template";
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
template.expressionBraceDepth -= 1;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
offset += 1;
|
|
296
|
+
}
|
|
297
|
+
if ((state.mode === "single-quote" || state.mode === "double-quote") &&
|
|
298
|
+
!quoteContinues) {
|
|
299
|
+
// Recover after an invalid unterminated string instead of poisoning later lines.
|
|
300
|
+
state.mode = "code";
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function isLikelyRegexStart(line, slashOffset) {
|
|
304
|
+
const prefix = line.slice(0, slashOffset).trimEnd();
|
|
305
|
+
if (prefix.length === 0) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
const previous = prefix.at(-1);
|
|
309
|
+
if (previous !== undefined && "([{,:;=!?&|+-*%^~<>".includes(previous)) {
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
const word = /([A-Za-z_$][A-Za-z0-9_$]*)$/.exec(prefix)?.[1];
|
|
313
|
+
return word !== undefined && regexPrefixKeywords.has(word);
|
|
314
|
+
}
|
|
315
|
+
function skipRegexLiteral(line, slashOffset) {
|
|
316
|
+
let offset = slashOffset + 1;
|
|
317
|
+
let inCharacterClass = false;
|
|
318
|
+
while (offset < line.length) {
|
|
319
|
+
const character = line[offset];
|
|
320
|
+
if (character === "\\") {
|
|
321
|
+
offset += 2;
|
|
322
|
+
}
|
|
323
|
+
else if (character === "[") {
|
|
324
|
+
inCharacterClass = true;
|
|
325
|
+
offset += 1;
|
|
326
|
+
}
|
|
327
|
+
else if (character === "]") {
|
|
328
|
+
inCharacterClass = false;
|
|
329
|
+
offset += 1;
|
|
330
|
+
}
|
|
331
|
+
else if (character === "/" && !inCharacterClass) {
|
|
332
|
+
offset += 1;
|
|
333
|
+
while (offset < line.length && /[A-Za-z]/.test(line[offset] ?? "")) {
|
|
334
|
+
offset += 1;
|
|
335
|
+
}
|
|
336
|
+
return offset;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
offset += 1;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return offset;
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "../core/index.js";
|
|
2
|
+
export { configs as eslintConfigs, default as eslintPlugin, meta as eslintPluginMeta, processors, } from "./plugin.js";
|
|
3
|
+
export declare const meta: {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const configs: {
|
|
8
|
+
recommended: import("./plugin.js").LegacyConfig;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=package.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (C) 2026 Tencent. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
18
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
19
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(o, k2, desc);
|
|
22
|
+
}) : (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
o[k2] = m[k];
|
|
25
|
+
}));
|
|
26
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
27
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
28
|
+
};
|
|
29
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.configs = exports.meta = exports.processors = exports.eslintPluginMeta = exports.eslintPlugin = exports.eslintConfigs = void 0;
|
|
34
|
+
__exportStar(require("../core/index.js"), exports);
|
|
35
|
+
var plugin_js_1 = require("./plugin.js");
|
|
36
|
+
Object.defineProperty(exports, "eslintConfigs", { enumerable: true, get: function () { return plugin_js_1.configs; } });
|
|
37
|
+
Object.defineProperty(exports, "eslintPlugin", { enumerable: true, get: function () { return __importDefault(plugin_js_1).default; } });
|
|
38
|
+
Object.defineProperty(exports, "eslintPluginMeta", { enumerable: true, get: function () { return plugin_js_1.meta; } });
|
|
39
|
+
Object.defineProperty(exports, "processors", { enumerable: true, get: function () { return plugin_js_1.processors; } });
|
|
40
|
+
const plugin_js_2 = require("./plugin.js");
|
|
41
|
+
// The legacy `.eslintrc` system resolves a plugin by package name, which lands
|
|
42
|
+
// on this entry rather than on `./eslint-plugin`. It then reads `configs`,
|
|
43
|
+
// `processors`, and `meta` off the module, so `extends: ["plugin:tsifdef/
|
|
44
|
+
// recommended"]` only works if those names are present here too.
|
|
45
|
+
//
|
|
46
|
+
// `recommended` must be the eslintrc shape here: the legacy schema rejects a
|
|
47
|
+
// top-level `files` key. The flat shape stays reachable under the same names
|
|
48
|
+
// it has on the flat entry, so a flat config that reaches this entry through
|
|
49
|
+
// the `eslint-plugin-tsifdef` alias still works.
|
|
50
|
+
exports.meta = plugin_js_2.meta;
|
|
51
|
+
exports.configs = {
|
|
52
|
+
...plugin_js_2.configs,
|
|
53
|
+
recommended: plugin_js_2.legacyRecommended,
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=package.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
interface ParserOptions {
|
|
2
|
+
readonly filePath?: string;
|
|
3
|
+
readonly [key: string]: unknown;
|
|
4
|
+
}
|
|
5
|
+
interface ParserResult {
|
|
6
|
+
readonly ast: unknown;
|
|
7
|
+
readonly services?: unknown;
|
|
8
|
+
readonly visitorKeys?: unknown;
|
|
9
|
+
readonly scopeManager?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* ESLint parser wrapper that projects TSIfDef source before delegating to
|
|
13
|
+
* `@typescript-eslint/parser`.
|
|
14
|
+
*
|
|
15
|
+
* The processor still owns ESLint's primary projection and synthetic-message
|
|
16
|
+
* filtering. This wrapper additionally covers consumers such as
|
|
17
|
+
* `eslint-plugin-import` that bypass processors, read dependencies from disk,
|
|
18
|
+
* and invoke the configured parser directly.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseForESLint(code: string, options?: ParserOptions): ParserResult;
|
|
21
|
+
export declare function parse(code: string, options?: ParserOptions): unknown;
|
|
22
|
+
export declare const meta: {
|
|
23
|
+
name: string;
|
|
24
|
+
version: string;
|
|
25
|
+
};
|
|
26
|
+
declare const _default: {
|
|
27
|
+
parse: typeof parse;
|
|
28
|
+
parseForESLint: typeof parseForESLint;
|
|
29
|
+
meta: {
|
|
30
|
+
name: string;
|
|
31
|
+
version: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export default _default;
|
|
35
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (C) 2026 Tencent. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
// you may not use this file except in compliance with the License.
|
|
6
|
+
// You may obtain a copy of the License at
|
|
7
|
+
//
|
|
8
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
//
|
|
10
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
// See the License for the specific language governing permissions and
|
|
14
|
+
// limitations under the License.
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.meta = void 0;
|
|
17
|
+
exports.parseForESLint = parseForESLint;
|
|
18
|
+
exports.parse = parse;
|
|
19
|
+
const node_module_1 = require("node:module");
|
|
20
|
+
const node_path_1 = require("node:path");
|
|
21
|
+
const version_js_1 = require("../version.js");
|
|
22
|
+
const projection_js_1 = require("./projection.js");
|
|
23
|
+
const parserCache = new Map();
|
|
24
|
+
/** Resolve the peer parser relative to the file currently being linted. */
|
|
25
|
+
function loadTypeScriptEslintParser(filePath) {
|
|
26
|
+
const anchor = filePath === undefined
|
|
27
|
+
? (0, node_path_1.join)(process.cwd(), "package.json")
|
|
28
|
+
: (0, node_path_1.join)((0, node_path_1.dirname)((0, node_path_1.resolve)(filePath)), "__tsifdef_eslint_parser__.js");
|
|
29
|
+
const hostRequire = (0, node_module_1.createRequire)(anchor);
|
|
30
|
+
const parserPath = hostRequire.resolve("@typescript-eslint/parser");
|
|
31
|
+
const cached = parserCache.get(parserPath);
|
|
32
|
+
if (cached !== undefined)
|
|
33
|
+
return cached;
|
|
34
|
+
const parser = hostRequire(parserPath);
|
|
35
|
+
parserCache.set(parserPath, parser);
|
|
36
|
+
return parser;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* ESLint parser wrapper that projects TSIfDef source before delegating to
|
|
40
|
+
* `@typescript-eslint/parser`.
|
|
41
|
+
*
|
|
42
|
+
* The processor still owns ESLint's primary projection and synthetic-message
|
|
43
|
+
* filtering. This wrapper additionally covers consumers such as
|
|
44
|
+
* `eslint-plugin-import` that bypass processors, read dependencies from disk,
|
|
45
|
+
* and invoke the configured parser directly.
|
|
46
|
+
*/
|
|
47
|
+
function parseForESLint(code, options) {
|
|
48
|
+
const filePath = typeof options?.filePath === "string" ? options.filePath : undefined;
|
|
49
|
+
const projected = (0, projection_js_1.projectSourceForEslint)(code, filePath).projectedText;
|
|
50
|
+
return loadTypeScriptEslintParser(filePath).parseForESLint(projected, options);
|
|
51
|
+
}
|
|
52
|
+
function parse(code, options) {
|
|
53
|
+
const filePath = typeof options?.filePath === "string" ? options.filePath : undefined;
|
|
54
|
+
const projected = (0, projection_js_1.projectSourceForEslint)(code, filePath).projectedText;
|
|
55
|
+
return loadTypeScriptEslintParser(filePath).parse(projected, options);
|
|
56
|
+
}
|
|
57
|
+
exports.meta = { name: "tsifdef/parser", version: version_js_1.VERSION };
|
|
58
|
+
exports.default = { parse, parseForESLint, meta: exports.meta };
|
|
59
|
+
//# sourceMappingURL=parser.js.map
|